From 252ca9c5d8d781c9044b452d608a419a003e5e3e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 17 Feb 2017 17:23:37 +0100 Subject: [PATCH 001/196] build: bump version to 0.15.0 Tree-SHA512: 7cdf0efaafeb47ec25d29fa9dc1c5caa762ee62614288fc849370d89bd64c1e8039175fe44163fb5655db10b567baa028ae514a05ebdaf06432b9698849da195 --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index fd1396fc9ee6..0dfea990e116 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) -define(_CLIENT_VERSION_MINOR, 14) -define(_CLIENT_VERSION_REVISION, 99) +define(_CLIENT_VERSION_MINOR, 15) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) -define(_CLIENT_VERSION_IS_RELEASE, false) +define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2017) define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]]) From 30c246b04f1606dab17de592c98d03e5b6fd77aa Mon Sep 17 00:00:00 2001 From: practicalswift Date: Thu, 17 Aug 2017 16:19:51 +0200 Subject: [PATCH 002/196] Updating the release notes (minor stylistic changes) --- doc/release-notes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 9398a3f8c262..9208ed48199c 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -124,7 +124,7 @@ Bitcoin Core now supports loading multiple, separate wallets (See [PR 8694](http Multi-wallet is enabled by using more than one `-wallet` argument when starting Bitcoin, either on the command line or in the Bitcoin config file. -**In Bitcoin-Qt, only the first wallet will be displayed and accessible for creating and signing transactions.** GUI selectable multiple wallets will be supported in a future version. However, even in 0.15 other loaded wallets will continue to remain synchronized to the node's current tip in the background. This can be useful if running a pruned node, since loading a wallet where the most recent sync is beyond the pruned height results in having to download and revalidate the whole blockchain. Continuing to synchronize all wallets in the background avoids this problem. +**In Bitcoin-Qt, only the first wallet will be displayed and accessible for creating and signing transactions.** GUI selectable multiple wallets will be supported in a future version. However, even in 0.15 other loaded wallets will remain synchronized to the node's current tip in the background. This can be useful if running a pruned node, since loading a wallet where the most recent sync is beyond the pruned height results in having to download and revalidate the whole blockchain. Continuing to synchronize all wallets in the background avoids this problem. Bitcoin Core 0.15.0 contains the following changes to the RPC interface and `bitcoin-cli` for multi-wallet: @@ -217,7 +217,7 @@ Low-level RPC changes - The `getmempoolancestors`, `getmempooldescendants`, `getmempooolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). -- The `dumpwallet` RPC now returns the full absolute path to the dumped wallet. (it +- The `dumpwallet` RPC now returns the full absolute path to the dumped wallet. It used to return no value, even if successful (See [PR 9740](https://github.com/bitcoin/bitcoin/pull/9740)). - In the `getpeerinfo` RPC, the return object for each peer now returns an `addrbind` member, which contains the ip address and port of the connection to the peer. This is in addition to the `addrlocal` member which contains the ip address and port of the local node as reported by the peer (See [PR 10478](https://github.com/bitcoin/bitcoin/pull/10478)). @@ -231,7 +231,7 @@ Low-level RPC changes - The second argument in the `submitblock` RPC argument has been renamed from `parameters` to `dummy`. This argument never had any effect, and the renaming is simply to communicate this fact to the user (See [PR 10191](https://github.com/bitcoin/bitcoin/pull/10191)) (Clients should, however, use positional arguments for `submitblock` in order to be compatible with BIP 22.) -- The `verbose` argument of `getblock` has been renamed to `verbosity` and now takes an integer from 0-2. Verbose level 0 is equivalent to `verbose=false`. Verbose level 1 is equivalent to `verbose=true`. Verbose level 2 will give the full transaction details of each transaction in the output as given by `getrawtransaction`. The old behavior of using the `verbose` named argument and a boolean value is still maintained for compatibility. +- The `verbose` argument of `getblock` has been renamed to `verbosity` and now takes an integer from 0 to 2. Verbose level 0 is equivalent to `verbose=false`. Verbose level 1 is equivalent to `verbose=true`. Verbose level 2 will give the full transaction details of each transaction in the output as given by `getrawtransaction`. The old behavior of using the `verbose` named argument and a boolean value is still maintained for compatibility. - Error codes have been updated to be more accurate for the following error cases (See [PR 9853](https://github.com/bitcoin/bitcoin/pull/9853)): - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for From 008f64f80f30d91bcad6b4133ce98899c1da95aa Mon Sep 17 00:00:00 2001 From: Derek Miller Date: Fri, 18 Aug 2017 12:32:02 -0500 Subject: [PATCH 003/196] Update release-notes.md Eric Shaw Jr -> Eric Shaw (from GitHub profile) gubatron -> Angel Leon (from GitHub profile) jonnynewbs -> John Newbery (duplicate) keystrike -> James Evans (duplicate) Kibbled Jive Elk Zoo -> KibbledJiveElkZoo (duplicate) kirit93 -> Kirit Thadaka (from GitHub profile) NicolasDorier -> Nicolas Dorier (duplicate) --- doc/release-notes.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 9208ed48199c..77b343a94ca0 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -8,7 +8,7 @@ Bitcoin Core version *0.15.0* is now available from: This is a new major version release, including new features, various bugfixes and performance improvements, as well as updated translations. -Please report bugs using the issue tracker at github: +Please report bugs using the issue tracker at GitHub: @@ -292,6 +292,7 @@ Thanks to everyone who directly contributed to this release: - Allan Doensen - Andres G. Aragoneses - Andrew Chow +- Angel Leon - Awemany - Bob McElrath - Brian McMichael @@ -306,7 +307,7 @@ Thanks to everyone who directly contributed to this release: - Daniel Cousens - darksh1ne - Dimitris Tsapakidis -- Eric Shaw Jr +- Eric Shaw - Evan Klitzke - fanquake - Felix Weis @@ -314,7 +315,6 @@ Thanks to everyone who directly contributed to this release: - Greg Griffith - Gregory Maxwell - Gregory Sanders -- gubatron - Ian Kelling - Jack Grigg - James Evans @@ -326,15 +326,12 @@ Thanks to everyone who directly contributed to this release: - Johnathan Corgan - John Newbery - Jonas Schnelli -- jonnynewbs - Jorge Timón - Kalle Alm - Karl-Johan Alm -- Kewde -- keystrike +- kewde - KibbledJiveElkZoo -- Kibbled Jive Elk Zoo -- kirit93 +- Kirit Thadaka - kobake - Kyle Honeycutt - Lawrence Nahum @@ -354,7 +351,6 @@ Thanks to everyone who directly contributed to this release: - Mikerah - Mike van Rossum - Mitchell Cash -- NicolasDorier - Nicolas Dorier - Patrick Strateman - Pavel Janík From cbdd338a75d53061b97daeb8e6f04d22249117cc Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Tue, 15 Aug 2017 10:27:20 -0700 Subject: [PATCH 004/196] disable jni in builds Github-Pull: #11056 Rebased-From: 844b73e486ca146f3f9f3060e878814752c25fd5 Tree-SHA512: f735853c3d9abbde5032cc55201b0ddc29679e681ba7d3822cbcbeee17c7185ee984b235411224cfb8ff12550de88a0f1367d55ad24bf52c5c03061330849eb2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0dfea990e116..70033ac0fc7a 100644 --- a/configure.ac +++ b/configure.ac @@ -1261,7 +1261,7 @@ if test x$need_bundled_univalue = xyes; then AC_CONFIG_SUBDIRS([src/univalue]) fi -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery --disable-jni" AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT From 6c2b0085fb4980442a732cb879902d8215ca49d5 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 17 Aug 2017 19:35:30 -0700 Subject: [PATCH 005/196] Fix combinerawtransaction RPC help result section Github-Pull: #11083 Rebased-From: f9ca0fe44ec673695e601045630f151a806e000d Tree-SHA512: ef94958d7de11e091db456e253fa4a188b0b0e713149bd568aa2de11a8a3c1585b34bbfb78aaac12f969533f05602ed8b1cd16275429d86a80c36bb594ce6526 --- src/rpc/rawtransaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 81005118541a..0ca1aa66e382 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -572,7 +572,7 @@ UniValue combinerawtransaction(const JSONRPCRequest& request) " ]\n" "\nResult:\n" - "\"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" + "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n" "\nExamples:\n" + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]") From 9fe1f6bd898ab1a69fbce2cb9dd93fcbb60b88fd Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 17 Aug 2017 21:54:23 +0200 Subject: [PATCH 006/196] Add length check for CExtKey deserialization Github-Pull: #11081 Rebased-From: 07685d1bc1b0b815c00a68a5b7b335ffa0d4d90d Tree-SHA512: 7f6b9ca6714d059d500531eb842c1c25edfa04ecba0ea1d9a28010fced657c066cea67d2016bbaa9b96c431a05ca9c0dcf2ba301898ecf96a65a4e01aac7fae9 --- src/key.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/key.h b/src/key.h index 2c6f151727b6..151e63531b13 100644 --- a/src/key.h +++ b/src/key.h @@ -172,6 +172,8 @@ struct CExtKey { { unsigned int len = ::ReadCompactSize(s); unsigned char code[BIP32_EXTKEY_SIZE]; + if (len != BIP32_EXTKEY_SIZE) + throw std::runtime_error("Invalid extended key size\n"); s.read((char *)&code[0], len); Decode(code); } From 2b59cfb1f719b4cd64be852512ee6a60f5dc7ea1 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 17 Aug 2017 19:20:01 +0200 Subject: [PATCH 007/196] doc: Update build-openbsd for 6.1 - Bump "updated for" - Fix link to boost (haenet mirror is broken) - Upgrade boost version to 1.64 Github-Pull: #11080 Rebased-From: 5be6e9b4f9991a5f8ff74aa8aaa4962cb45728b6 Tree-SHA512: 72877bf32e4f38fb530946c065c23edd683a0da379c33fa3eee4fbeb51e2c97171f5d33ebe1e77f25c3e14779d94e8198cc8fbb6e1055a1024638458ef7cc032 --- doc/build-openbsd.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index f4a9826d8079..cd800464b427 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -1,6 +1,6 @@ OpenBSD build guide ====================== -(updated for OpenBSD 6.0) +(updated for OpenBSD 6.1) This guide describes how to build bitcoind and command-line utilities on OpenBSD. @@ -48,13 +48,13 @@ BOOST_PREFIX="${BITCOIN_ROOT}/boost" mkdir -p $BOOST_PREFIX # Fetch the source and verify that it is not tampered with -curl -o boost_1_61_0.tar.bz2 http://heanet.dl.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.bz2 -echo 'a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 boost_1_61_0.tar.bz2' | sha256 -c -# MUST output: (SHA256) boost_1_61_0.tar.bz2: OK -tar -xjf boost_1_61_0.tar.bz2 +curl -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2 +echo '7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 boost_1_64_0.tar.bz2' | sha256 -c +# MUST output: (SHA256) boost_1_64_0.tar.bz2: OK +tar -xjf boost_1_64_0.tar.bz2 -# Boost 1.61 needs one small patch for OpenBSD -cd boost_1_61_0 +# Boost 1.64 needs one small patch for OpenBSD +cd boost_1_64_0 # Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp From 4ef8374559acfdefb2f81c4a5ab2afe553688a27 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 14 Aug 2017 13:36:25 -0400 Subject: [PATCH 008/196] [wallet] Remove keypool_topup_cleanups Unused function. Mostly reverts c25d90f125d69e33688288eff439eb7be75012e9 c25d90f... was merged as part of PR 11022 but is not required. Github-Pull: #11044 Rebased-From: 1221f60c94971c0f66abe5fdf086087a173bb0ac Tree-SHA512: da229b128bee5f124c009a1a2adfb4fa879366c81789824c426c9ce5209c835888a7e6cfeb1724551320a98cd08406a605372f84487a0d289cd6e02f9ac3ea21 --- src/wallet/wallet.cpp | 5 ----- src/wallet/wallet.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 599e74149c50..aa0713ea0363 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3663,11 +3663,6 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id) } } -bool CWallet::HasUnusedKeys(int min_keys) const -{ - return setExternalKeyPool.size() >= min_keys && (setInternalKeyPool.size() >= min_keys || !CanSupportFeature(FEATURE_HD_SPLIT)); -} - void CWallet::GetScriptForMining(std::shared_ptr &script) { std::shared_ptr rKey = std::make_shared(this); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f97a99d82a16..296bb73219ea 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -984,8 +984,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface */ void MarkReserveKeysAsUsed(int64_t keypool_id); const std::map& GetAllReserveKeys() const { return m_pool_key_to_index; } - /** Does the wallet have at least min_keys in the keypool? */ - bool HasUnusedKeys(int min_keys) const; std::set< std::set > GetAddressGroupings(); std::map GetAddressBalances(); From 6ab120cc6ca659bc80e80e09a433f3f39637f941 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 14 Aug 2017 13:38:21 -0400 Subject: [PATCH 009/196] [wallet] Add logging to MarkReserveKeysAsUsed Github-Pull: #11044 Rebased-From: 67ceff4039ae038ae16f06128f868a2e8395b59a Tree-SHA512: 850c5b1010c84e164edf24a83ae36e46309b2eb7a67854bad509265ed590ba67d5f743a8416590da6ecca85fe4bda7f20e8c3152e422638eb7898db11a416af7 --- src/wallet/wallet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index aa0713ea0363..680c5ed9b37a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3659,6 +3659,7 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id) m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); } walletdb.ErasePool(index); + LogPrintf("keypool index %d removed\n", index); it = setKeyPool->erase(it); } } From eb9c21ed793127b12b496c95c28ddb13cc8c0427 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 10 Aug 2017 15:58:25 -0700 Subject: [PATCH 010/196] Only return hex field once in getrawtransaction The hex is already returned in TxToUniv, no need to give it out a second independent time in getrawtransaction itself. Github-Pull: #11027 Rebased-From: e029c6e709d251809aa04edc08f76a077a2443e7 Tree-SHA512: 4f7892431ddb9b59bcc59756890b97a20d046d1d4898f8a80c564223e1cde1c922da403cea4b8ae79d70741d1a9ff337f077043e5bb538cdc4d34fbe09301240 --- src/rpc/rawtransaction.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 0ca1aa66e382..1349d6a2ed0e 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -160,13 +160,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request) : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") + ". Use gettransaction for wallet transactions."); - std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); - if (!fVerbose) - return strHex; + return EncodeHexTx(*tx, RPCSerializationFlags()); UniValue result(UniValue::VOBJ); - result.push_back(Pair("hex", strHex)); TxToJSON(*tx, hashBlock, result); return result; } From 07164bbeadd928e26390789231a48bc32b1774c8 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 11 Aug 2017 12:21:14 -0700 Subject: [PATCH 011/196] Pass serialization flags and whether to include hex to TxToUniv Github-Pull: #11027 Rebased-From: 6bbdafcdc4f9d9e3f9de72ed686c060fb4b8b465 Tree-SHA512: 8ed049a0945c4f56c518aef6d60efebda5cde09ef63d8e472b363821170d71fb4d16414b360824d7537fc7c7b5e5277bbbd092a20899446e97c188ab8df58c1b --- src/core_io.h | 2 +- src/core_write.cpp | 6 ++++-- src/rpc/blockchain.cpp | 2 +- src/rpc/rawtransaction.cpp | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core_io.h b/src/core_io.h index 3f25faf0ec2c..ccc72ebb3219 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -31,6 +31,6 @@ UniValue ValueFromAmount(const CAmount& amount); std::string FormatScript(const CScript& script); std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry); +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0); #endif // BITCOIN_CORE_IO_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 0eae4703abb7..1431fa0c9bee 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -153,7 +153,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) { entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); @@ -207,5 +207,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) if (!hashBlock.IsNull()) entry.pushKV("blockhash", hashBlock.GetHex()); - entry.pushKV("hex", EncodeHexTx(tx)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction". + if (include_hex) { + entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction". + } } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 24e0405a847a..34bcdf9cccb4 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -125,7 +125,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if(txDetails) { UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx); + TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); txs.push_back(objTx); } else diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1349d6a2ed0e..55e4746827a1 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -41,7 +41,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) // Blockchain contextual information (confirmations and blocktime) is not // available to code in bitcoin-common, so we query them here and push the // data into the returned UniValue. - TxToUniv(tx, uint256(), entry); + TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags()); if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); @@ -480,7 +480,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); UniValue result(UniValue::VOBJ); - TxToUniv(CTransaction(std::move(mtx)), uint256(), result); + TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false); return result; } From 129b03ff62dd5e09b6c6e601218e7079c2387dd5 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 19 Aug 2017 15:22:06 -0400 Subject: [PATCH 012/196] gitian: quick hack to fix version string in releases Release version strings were broken in Gitian by 7522. This is a minimal fix suitable for 0.15. After this, we should fix up version handling for good so that gitian packages the correct string in the release tarball, so that git is not required to get the tag name. Github-Pull: #11097 Rebased-From: 4452829b104842c547bd100714a241e9f209e1f4 Tree-SHA512: 40071b97b2207b2262aef0b4802cb231ccafbff0ed04b5945a64dceda8bdbb2ea71bf6a546e1d03533612edfdc55dedd413da967cba0b1bbd3f9139ec3572f60 --- contrib/gitian-descriptors/gitian-linux.yml | 9 ++++++++- contrib/gitian-descriptors/gitian-osx.yml | 9 ++++++++- contrib/gitian-descriptors/gitian-win.yml | 9 ++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 3da8510cfbd7..82f4c7e0a826 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -132,7 +132,6 @@ script: | export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host - export GIT_DIR="$PWD/.git" ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist @@ -145,6 +144,9 @@ script: | find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do @@ -155,6 +157,11 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 206db7c19e75..35dee579afef 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -101,7 +101,6 @@ script: | export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host - export GIT_DIR="$PWD/.git" ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist @@ -115,6 +114,9 @@ script: | find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do @@ -125,6 +127,11 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} make install-strip DESTDIR=${INSTALLPATH} diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 1d4d70494b0c..b39611659964 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -116,7 +116,6 @@ script: | export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host - export GIT_DIR="$PWD/.git" ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist @@ -132,6 +131,9 @@ script: | cp ../$SOURCEDIST $OUTDIR/src popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do @@ -142,6 +144,11 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security From 9c76cf50fb6b306f2ed6c46f7e252c7812de0476 Mon Sep 17 00:00:00 2001 From: jbarcelo Date: Mon, 21 Aug 2017 10:41:04 +0200 Subject: [PATCH 013/196] Trivial: Fix typo in release-notes.md getmempooolentry -> getmempoolentry (twice) --- doc/release-notes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 77b343a94ca0..65f2cccc65cc 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -155,7 +155,7 @@ In previous versions of Bitcoin Core, a portion of each block could be reserved - The `-sendfreetransactions` option has been removed, since almost all miners do not include transactions which do not attach a transaction fee. - The `-blockprioritysize` option has been removed. - The `estimatepriority` and `estimatesmartpriority` RPCs have been removed. -- The `getmempoolancestors`, `getmempooldescendants`, `getmempooolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. +- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. - The `prioritisetransaction` RPC no longer takes a `priority_delta` argument, which is replaced by a `dummy` argument for backwards compatibility with clients using positional arguments. The RPC is still used to change the apparent fee-rate of the transaction by using the `fee_delta` argument. - `-minrelaytxfee` can now be set to 0. If `minrelaytxfee` is set, then fees smaller than `minrelaytxfee` (per kB) are rejected from relaying, mining and transaction creation. This defaults to 1000 satoshi/kB. - The `-printpriority` option has been updated to only output the fee rate and hash of transactions included in a block by the mining code. @@ -215,7 +215,7 @@ Low-level RPC changes - `maximumCount` - a number specifying the minimum number of UTXOs - `minimumSumAmount` - a number specifying the minimum sum value of all UTXOs -- The `getmempoolancestors`, `getmempooldescendants`, `getmempooolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). +- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). - The `dumpwallet` RPC now returns the full absolute path to the dumped wallet. It used to return no value, even if successful (See [PR 9740](https://github.com/bitcoin/bitcoin/pull/9740)). From 28b978b19e87a7ed802c65f2d6561e61ef7ce911 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 21 Aug 2017 08:42:04 +0000 Subject: [PATCH 014/196] qt: Update translations pre-rc2 New locales: - bn - bs - de_DE - en_AU - en_US - es_419 - he_IL - id - ja_JP - my - nb_NO - nl_NL - si - te - th Tree-SHA512: af4e9d0107122e3da7da8ee4952e01a731ed04f13e83ed1979ace24d29c437a83cc23453d8f0b2160829df02c2ffbff0ce749083f82c4d4695c69a3c7feeebed --- src/Makefile.qt.include | 15 + src/qt/bitcoin_locale.qrc | 15 + src/qt/locale/bitcoin_bn.ts | 187 ++ src/qt/locale/bitcoin_bs.ts | 163 ++ src/qt/locale/bitcoin_cy.ts | 160 +- src/qt/locale/bitcoin_de_DE.ts | 628 +++++++ src/qt/locale/bitcoin_el_GR.ts | 18 +- src/qt/locale/bitcoin_en_AU.ts | 175 ++ src/qt/locale/bitcoin_en_US.ts | 175 ++ src/qt/locale/bitcoin_es_419.ts | 167 ++ src/qt/locale/bitcoin_he_IL.ts | 203 +++ src/qt/locale/bitcoin_hi_IN.ts | 2 +- src/qt/locale/bitcoin_id.ts | 171 ++ src/qt/locale/bitcoin_ja_JP.ts | 2645 +++++++++++++++++++++++++++++ src/qt/locale/bitcoin_my.ts | 163 ++ src/qt/locale/bitcoin_nb_NO.ts | 575 +++++++ src/qt/locale/bitcoin_nl_NL.ts | 199 +++ src/qt/locale/bitcoin_pl.ts | 38 +- src/qt/locale/bitcoin_pt_BR.ts | 6 +- src/qt/locale/bitcoin_si.ts | 319 ++++ src/qt/locale/bitcoin_sr@latin.ts | 40 + src/qt/locale/bitcoin_te.ts | 279 +++ src/qt/locale/bitcoin_th.ts | 203 +++ src/qt/locale/bitcoin_tr_TR.ts | 186 +- src/qt/locale/bitcoin_zh_CN.ts | 4 + 25 files changed, 6727 insertions(+), 9 deletions(-) create mode 100644 src/qt/locale/bitcoin_bn.ts create mode 100644 src/qt/locale/bitcoin_bs.ts create mode 100644 src/qt/locale/bitcoin_de_DE.ts create mode 100644 src/qt/locale/bitcoin_en_AU.ts create mode 100644 src/qt/locale/bitcoin_en_US.ts create mode 100644 src/qt/locale/bitcoin_es_419.ts create mode 100644 src/qt/locale/bitcoin_he_IL.ts create mode 100644 src/qt/locale/bitcoin_id.ts create mode 100644 src/qt/locale/bitcoin_ja_JP.ts create mode 100644 src/qt/locale/bitcoin_my.ts create mode 100644 src/qt/locale/bitcoin_nb_NO.ts create mode 100644 src/qt/locale/bitcoin_nl_NL.ts create mode 100644 src/qt/locale/bitcoin_si.ts create mode 100644 src/qt/locale/bitcoin_te.ts create mode 100644 src/qt/locale/bitcoin_th.ts diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index e4b64c1ca79c..7b44ce038337 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -13,18 +13,24 @@ QT_TS = \ qt/locale/bitcoin_be_BY.ts \ qt/locale/bitcoin_bg_BG.ts \ qt/locale/bitcoin_bg.ts \ + qt/locale/bitcoin_bn.ts \ + qt/locale/bitcoin_bs.ts \ qt/locale/bitcoin_ca_ES.ts \ qt/locale/bitcoin_ca.ts \ qt/locale/bitcoin_ca@valencia.ts \ qt/locale/bitcoin_cs.ts \ qt/locale/bitcoin_cy.ts \ qt/locale/bitcoin_da.ts \ + qt/locale/bitcoin_de_DE.ts \ qt/locale/bitcoin_de.ts \ qt/locale/bitcoin_el_GR.ts \ qt/locale/bitcoin_el.ts \ + qt/locale/bitcoin_en_AU.ts \ qt/locale/bitcoin_en_GB.ts \ qt/locale/bitcoin_en.ts \ + qt/locale/bitcoin_en_US.ts \ qt/locale/bitcoin_eo.ts \ + qt/locale/bitcoin_es_419.ts \ qt/locale/bitcoin_es_AR.ts \ qt/locale/bitcoin_es_CL.ts \ qt/locale/bitcoin_es_CO.ts \ @@ -44,13 +50,16 @@ QT_TS = \ qt/locale/bitcoin_fr_FR.ts \ qt/locale/bitcoin_fr.ts \ qt/locale/bitcoin_gl.ts \ + qt/locale/bitcoin_he_IL.ts \ qt/locale/bitcoin_he.ts \ qt/locale/bitcoin_hi_IN.ts \ qt/locale/bitcoin_hr.ts \ qt/locale/bitcoin_hu.ts \ qt/locale/bitcoin_id_ID.ts \ + qt/locale/bitcoin_id.ts \ qt/locale/bitcoin_it_IT.ts \ qt/locale/bitcoin_it.ts \ + qt/locale/bitcoin_ja_JP.ts \ qt/locale/bitcoin_ja.ts \ qt/locale/bitcoin_ka.ts \ qt/locale/bitcoin_kk_KZ.ts \ @@ -63,8 +72,11 @@ QT_TS = \ qt/locale/bitcoin_mk_MK.ts \ qt/locale/bitcoin_mn.ts \ qt/locale/bitcoin_ms_MY.ts \ + qt/locale/bitcoin_my.ts \ + qt/locale/bitcoin_nb_NO.ts \ qt/locale/bitcoin_nb.ts \ qt/locale/bitcoin_ne.ts \ + qt/locale/bitcoin_nl_NL.ts \ qt/locale/bitcoin_nl.ts \ qt/locale/bitcoin_pam.ts \ qt/locale/bitcoin_pl.ts \ @@ -74,6 +86,7 @@ QT_TS = \ qt/locale/bitcoin_ro.ts \ qt/locale/bitcoin_ru_RU.ts \ qt/locale/bitcoin_ru.ts \ + qt/locale/bitcoin_si.ts \ qt/locale/bitcoin_sk.ts \ qt/locale/bitcoin_sl_SI.ts \ qt/locale/bitcoin_sq.ts \ @@ -81,7 +94,9 @@ QT_TS = \ qt/locale/bitcoin_sr.ts \ qt/locale/bitcoin_sv.ts \ qt/locale/bitcoin_ta.ts \ + qt/locale/bitcoin_te.ts \ qt/locale/bitcoin_th_TH.ts \ + qt/locale/bitcoin_th.ts \ qt/locale/bitcoin_tr_TR.ts \ qt/locale/bitcoin_tr.ts \ qt/locale/bitcoin_uk.ts \ diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc index f195b23d818f..cef81781e292 100644 --- a/src/qt/bitcoin_locale.qrc +++ b/src/qt/bitcoin_locale.qrc @@ -6,18 +6,24 @@ locale/bitcoin_be_BY.qm locale/bitcoin_bg_BG.qm locale/bitcoin_bg.qm + locale/bitcoin_bn.qm + locale/bitcoin_bs.qm locale/bitcoin_ca_ES.qm locale/bitcoin_ca.qm locale/bitcoin_ca@valencia.qm locale/bitcoin_cs.qm locale/bitcoin_cy.qm locale/bitcoin_da.qm + locale/bitcoin_de_DE.qm locale/bitcoin_de.qm locale/bitcoin_el_GR.qm locale/bitcoin_el.qm + locale/bitcoin_en_AU.qm locale/bitcoin_en_GB.qm locale/bitcoin_en.qm + locale/bitcoin_en_US.qm locale/bitcoin_eo.qm + locale/bitcoin_es_419.qm locale/bitcoin_es_AR.qm locale/bitcoin_es_CL.qm locale/bitcoin_es_CO.qm @@ -37,13 +43,16 @@ locale/bitcoin_fr_FR.qm locale/bitcoin_fr.qm locale/bitcoin_gl.qm + locale/bitcoin_he_IL.qm locale/bitcoin_he.qm locale/bitcoin_hi_IN.qm locale/bitcoin_hr.qm locale/bitcoin_hu.qm locale/bitcoin_id_ID.qm + locale/bitcoin_id.qm locale/bitcoin_it_IT.qm locale/bitcoin_it.qm + locale/bitcoin_ja_JP.qm locale/bitcoin_ja.qm locale/bitcoin_ka.qm locale/bitcoin_kk_KZ.qm @@ -56,8 +65,11 @@ locale/bitcoin_mk_MK.qm locale/bitcoin_mn.qm locale/bitcoin_ms_MY.qm + locale/bitcoin_my.qm + locale/bitcoin_nb_NO.qm locale/bitcoin_nb.qm locale/bitcoin_ne.qm + locale/bitcoin_nl_NL.qm locale/bitcoin_nl.qm locale/bitcoin_pam.qm locale/bitcoin_pl.qm @@ -67,6 +79,7 @@ locale/bitcoin_ro.qm locale/bitcoin_ru_RU.qm locale/bitcoin_ru.qm + locale/bitcoin_si.qm locale/bitcoin_sk.qm locale/bitcoin_sl_SI.qm locale/bitcoin_sq.qm @@ -74,7 +87,9 @@ locale/bitcoin_sr.qm locale/bitcoin_sv.qm locale/bitcoin_ta.qm + locale/bitcoin_te.qm locale/bitcoin_th_TH.qm + locale/bitcoin_th.qm locale/bitcoin_tr_TR.qm locale/bitcoin_tr.qm locale/bitcoin_uk.qm diff --git a/src/qt/locale/bitcoin_bn.ts b/src/qt/locale/bitcoin_bn.ts new file mode 100644 index 000000000000..bd0739757a5e --- /dev/null +++ b/src/qt/locale/bitcoin_bn.ts @@ -0,0 +1,187 @@ + + + AddressBookPage + + Right-click to edit address or label + ঠিকানা কিংবা লেভেল সম্পাদনার জন্য রাইট-ক্লিক করুন + + + Create a new address + undefined + + + + AddressTableModel + + Address + ঠিকানা + + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Warning + সতর্কতা + + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Address + ঠিকানা + + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + The entered address is invalid. + প্রবেশকৃত ঠিকানাটি শুদ্ধ নয়। + + + Please check the signature and try again. + অনুগ্রহ করে স্বাক্ষরটি পুনরায় পরীক্ষা করে আবারও চেষ্টা করুন। + + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + Address + ঠিকানা + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Block creation options: + ব্লক তৈরির অপশনগুলো: + + + Debugging/Testing options: + ডিবাগিং/টেস্টিং অপশন: + + + Do you want to rebuild the block database now? + আপনি কি পুনরায় ব্লক ডাটাবেইজ এখনই তৈরি করতে চান? + + + RPC server options: + আরপিসি সার্ভার অপশন: + + + This is experimental software. + এটি পরীক্ষামূলক সফটওয়্যার। + + + Transaction amount too small + লেনদেনের পরিমান অনেক ছোট + + + Transaction too large + লেনদেনর অংক অনেক বড় + + + Warning + সতর্কতা + + + Loading addresses... + ঠিকানাগুলো লোডিং হচ্ছে... + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts new file mode 100644 index 000000000000..83f0c84f0a62 --- /dev/null +++ b/src/qt/locale/bitcoin_bs.ts @@ -0,0 +1,163 @@ + + + AddressBookPage + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Bitcoin + Bitcoin + + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + Alt+A + Alt+A + + + Alt+P + Alt+P + + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + Alt+A + Alt+A + + + Alt+P + Alt+P + + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + All + Sve + + + Today + Danas + + + This month + Ovaj mjesec + + + Last month + Prošli mjesec + + + This year + Ove godine + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Bitcoin Core + Bitcoin Jezrga + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index 9f2d87b6061f..e007e5ae4ee8 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -29,10 +29,42 @@ &Delete &Dileu + + Sending addresses + Anfon cyfeiriadau + + + Receiving addresses + Derbyn cyfeiriadau + + + &Copy Address + &Copïo Cyfeiriad + + + Copy &Label + Copïo &Label + + + Exporting Failed + Methu Allforio + AddressTableModel - + + Label + Label + + + Address + Cyfeiriad + + + (no label) + (dim label) + + AskPassphraseDialog @@ -81,6 +113,14 @@ Quit application Gadael rhaglen + + &About %1 + &Ynghylch %1 + + + Show information about %1 + Dangos gwybodaeth am %1 + About &Qt Ynghylch &Qt @@ -220,6 +260,18 @@ Date Dyddiad + + Copy address + Copïo cyfeiriad + + + Copy label + Copïo label + + + (no label) + (dim label) + EditAddressDialog @@ -361,6 +413,10 @@ &Label: &Label: + + Copy label + Copïo label + ReceiveRequestDialog @@ -368,9 +424,29 @@ Copy &Address &Cyfeiriad Copi + + Address + Cyfeiriad + + + Label + Label + RecentRequestsTableModel + + Date + Dyddiad + + + Label + Label + + + (no label) + (dim label) + SendCoinsDialog @@ -394,7 +470,11 @@ Confirm the send action Cadarnhau'r gweithrediad anfon - + + (no label) + (dim label) + + SendCoinsEntry @@ -455,15 +535,87 @@ TransactionDesc + + Date + Dyddiad + TransactionDescDialog TransactionTableModel + + Date + Dyddiad + + + Type + Math + + + Label + Label + + + (no label) + (dim label) + TransactionView + + Today + Heddiw + + + This week + Yr wythnos hon + + + This month + Y mis hwn + + + Last month + Mis diwethaf + + + This year + Eleni + + + Copy address + Copïo cyfeiriad + + + Copy label + Copïo label + + + Edit label + Golygu label + + + Date + Dyddiad + + + Type + Math + + + Label + Label + + + Address + Cyfeiriad + + + Exporting Failed + Methu Allforio + UnitDisplayStatusBarControl @@ -476,6 +628,10 @@ WalletView + + &Export + &Allforio + bitcoin-core diff --git a/src/qt/locale/bitcoin_de_DE.ts b/src/qt/locale/bitcoin_de_DE.ts new file mode 100644 index 000000000000..750cadd87b73 --- /dev/null +++ b/src/qt/locale/bitcoin_de_DE.ts @@ -0,0 +1,628 @@ + + + AddressBookPage + + Right-click to edit address or label + Rechtsklick um Adresse oder Etikett zu bearbeiten + + + Create a new address + Eine neue Adresse erstellen + + + &New + &Neu + + + Copy the currently selected address to the system clipboard + Ausgewählte Adresse in die Zwischenablage kopieren + + + &Copy + &Kopieren + + + C&lose + Schliessen + + + Delete the currently selected address from the list + Ausgewählte Adresse aus der Liste löschen + + + Export the data in the current tab to a file + Daten des aktiven Fensters exportieren + + + &Export + &Exportieren + + + &Delete + &Löschen + + + Choose the address to send coins to + Wähle die Empfängeradresse + + + Choose the address to receive coins with + Wähle die Empfangsadresse + + + C&hoose + Dies sind deine Bitcoin Adressen zum Senden von Zahlungsmitteln. +Überprüfe immer die Menge, sowie die Empfänger-Adresse vor dem Senden von Coins. + + + Sending addresses + Sendeadresse + + + Receiving addresses + Empfangsadresse + + + &Copy Address + &Kopiere Adresse + + + Copy &Label + Kopiere &Etikett + + + &Edit + &Bearbeiten + + + Export Address List + Export Adressliste + + + Comma separated file (*.csv) + Komma getrenntes Dokument (*.csv) + + + Exporting Failed + Export fehlgeschlagen + + + + AddressTableModel + + Label + Etikett + + + Address + Adresse + + + (no label) + (kein Etikett) + + + + AskPassphraseDialog + + Passphrase Dialog + Passwort Dialog + + + Enter passphrase + Passwort eingeben + + + New passphrase + Neues Passwort + + + Repeat new passphrase + Neues Passwort wiederholen + + + Encrypt wallet + Brieftasche verschlüsseln + + + This operation needs your wallet passphrase to unlock the wallet. + Diese Aktion benötigt ihr Passwort zum entsperren der Wallet. + + + Unlock wallet + Brieftasche entriegeln + + + Decrypt wallet + Brieftasche entschlüsseln + + + Change passphrase + Passwort ändern + + + Confirm wallet encryption + Brieftaschenverschlüsselung bestätigen + + + Wallet encrypted + Brieftasche verschlüsselt + + + Wallet encryption failed + Brieftaschenverschlüsselung fehlgeschlagen + + + Wallet unlock failed + Brieftasche öffnen fehlgeschlagen + + + The passphrase entered for the wallet decryption was incorrect. + Inkorrektes Passwort um die Brieftasche zu entschlüsseln + + + Wallet decryption failed + Brieftasche entschlüsseln fehlgeschlagen + + + Wallet passphrase was successfully changed. + Brieftaschen Passwort erfolgreich geändert + + + Warning: The Caps Lock key is on! + Achtung: Die Umschalttaste ist eingeschaltet! + + + + BanTableModel + + IP/Netmask + IP/Netzmaske + + + Banned Until + Gesperrt bis + + + + BitcoinGUI + + Synchronizing with network... + Über das Netzwerk abgleichen... + + + &Overview + &Übersicht + + + Node + Knoten + + + Show general overview of wallet + Generelle Übersicht der Brieftasche + + + &Transactions + &Transaktionen + + + Browse transaction history + Zeige Transaktionsverlauf + + + Quit application + Programm beenden + + + &Options... + &Einstellungen... + + + &Encrypt Wallet... + &Brieftasche verschlüsseln... + + + &Backup Wallet... + &Sicherungskopie der Brieftasche... + + + &Change Passphrase... + &Passwort ändern... + + + &Sending addresses... + &Adressen senden... + + + &Receiving addresses... + &Adressen empfangen... + + + Wallet + Brieftasche + + + &Send + &Senden + + + &Receive + &Empfangen + + + &Settings + &Einstellungen + + + &Help + &Hilfe + + + Show the list of used sending addresses and labels + Zeige Liste der benutzten Sendeadressen und -etiketten + + + Error + Fehler + + + Warning + Achtung + + + Information + Information + + + Sent transaction + Überweisung gesendet + + + Incoming transaction + Überweisung empfangen + + + + CoinControlDialog + + Date + Datum + + + Confirmations + Bestätigungen + + + Confirmed + Bestätigt + + + Copy address + Adresse kopieren + + + Copy label + Etikett kopieren + + + Copy amount + Betrag kopieren + + + Copy transaction ID + Transaktions ID kopieren + + + yes + Ja + + + no + Nein + + + (no label) + (kein Etikett) + + + + EditAddressDialog + + Edit Address + Adresse bearbeiten + + + &Label + &Etikett + + + &Address + &Adresse + + + New receiving address + Neue Empfangsadresse + + + New sending address + Neue Sendeadresse + + + Edit receiving address + Empfangsadresse bearbeiten + + + Edit sending address + Sendeadresse bearbeiten + + + + FreespaceChecker + + name + Name + + + + HelpMessageDialog + + version + Version + + + + Intro + + Welcome + Willkommen + + + Error + Fehler + + + + ModalOverlay + + Form + Formular + + + Unknown... + Unbekannt... + + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + Form + Formular + + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + Copy label + Etikett kopieren + + + Copy amount + Betrag kopieren + + + + ReceiveRequestDialog + + Address + Adresse + + + Label + Etikett + + + + RecentRequestsTableModel + + Date + Datum + + + Label + Etikett + + + (no label) + (kein Etikett) + + + + SendCoinsDialog + + Copy amount + Betrag kopieren + + + (no label) + (kein Etikett) + + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + Date + Datum + + + + TransactionDescDialog + + + TransactionTableModel + + Date + Datum + + + Label + Etikett + + + (no label) + (kein Etikett) + + + + TransactionView + + Copy address + Adresse kopieren + + + Copy label + Etikett kopieren + + + Copy amount + Betrag kopieren + + + Copy transaction ID + Transaktions ID kopieren + + + Comma separated file (*.csv) + Komma getrenntes Dokument (*.csv) + + + Confirmed + Bestätigt + + + Date + Datum + + + Label + Etikett + + + Address + Adresse + + + Exporting Failed + Export fehlgeschlagen + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Exportieren + + + Export the data in the current tab to a file + Daten des aktiven Fensters exportieren + + + + bitcoin-core + + Information + Information + + + Warning + Achtung + + + This is the minimum transaction fee you pay on every transaction. + Das ist die Mindestgebühr jeder Transaktion + + + This is the transaction fee you will pay if you send a transaction. + Das ist die Gebühr für die Überweisung + + + Transaction amounts must not be negative + Überweisungsbetrag kann nicht negativ sein + + + Transaction must have at least one recipient + Überweisung muss mindestens einen Empfänger haben + + + Insufficient funds + Ungenügendes Guthaben + + + Loading block index... + Block Verzeichnis laden... + + + Loading wallet... + Brieftasche laden... + + + Done loading + Laden abgeschlossen + + + Error + Fehler + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 2bbc1546a5a0..b068672ec4d8 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -61,6 +61,14 @@ Receiving addresses Διευθύνσεις λήψης + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Αυτές είναι οι Bitcoin διευθύνσεις σας για να στέλνετε πληρωμές. Να ελέγχετε πάντα το ποσό, καθώς και τη διεύθυνση παραλήπτη πριν στείλετε νομίσματα. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Αυτές είναι οι Bitcoin διευθύνσεις σας για να λαμβάνετε πληρωμές. Προτείνετε να χρησιμοποιείτε μια νέα διεύθυνση παραλήπτη για κάθε συναλλαγή. + &Copy Address &Αντιγραφή Διεύθυνσης @@ -85,7 +93,11 @@ Exporting Failed Αποτυχία Εξαγωγής - + + There was an error trying to save the address list to %1. Please try again. + Σφάλμα κατά την προσπάθεια αποθήκευσης της λίστας διευθύνσεων στο %1. Παρακαλώ δοκιμάστε ξανά. + + AddressTableModel @@ -119,6 +131,10 @@ 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>δέκα ή περισσότερους τυχαίους χαρακτήρες </b>, ή <b>οχτώ ή παραπάνω λέξεις </b>. + Encrypt wallet Κρυπτογράφηση πορτοφολιού diff --git a/src/qt/locale/bitcoin_en_AU.ts b/src/qt/locale/bitcoin_en_AU.ts new file mode 100644 index 000000000000..c2efefb50a63 --- /dev/null +++ b/src/qt/locale/bitcoin_en_AU.ts @@ -0,0 +1,175 @@ + + + AddressBookPage + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Synchronizing with network... + Synchronising with network... + + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + Start minimized + Start minimised + + + + Intro + + + ModalOverlay + + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronising with the bitcoin network, as detailed below. + + + + OpenURIDialog + + + OptionsDialog + + 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. + Minimise instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + + + Show only a tray icon after minimizing the window. + Show only a tray icon after minimising the window. + + + &Minimize to the tray instead of the taskbar + &Minimise to the tray instead of the taskbar + + + M&inimize on close + M&inimise on close + + + + OverviewPage + + 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 synchronises with the Bitcoin network after a connection is established, but this process has not completed yet. + + + + PaymentServer + + Payment request is not initialized. + Payment request is not initialised. + + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + (Smart fee not initialized yet. This usually takes a few blocks...) + (Smart fee not initialised yet. This usually takes a few blocks...) + + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Error initializing block database + Error initialising block database + + + Error initializing wallet database environment %s! + Error initialising wallet database environment %s! + + + Initialization sanity check failed. %s is shutting down. + Initialisation sanity check failed. %s is shutting down. + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + Randomise credentials for every proxy connection. This enables Tor stream isolation (default: %u) + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_en_US.ts b/src/qt/locale/bitcoin_en_US.ts new file mode 100644 index 000000000000..65cc0332e3b4 --- /dev/null +++ b/src/qt/locale/bitcoin_en_US.ts @@ -0,0 +1,175 @@ + + + AddressBookPage + + Right-click to edit address or label + Right-click to edit address or label + + + Create a new address + Create a new address + + + &New + &New + + + Copy the currently selected address to the system clipboard + Copy the currently selected address to the system clipboard + + + &Copy + &Copy + + + C&lose + C&lose + + + Delete the currently selected address from the list + Delete the currently selected address from the list + + + Export the data in the current tab to a file + Export the data in the current tab to a file + + + &Export + &Export + + + &Delete + &Delete + + + + AddressTableModel + + + AskPassphraseDialog + + Passphrase Dialog + Passphrase Dialog + + + Enter passphrase + Enter passphrase + + + New passphrase + New passphrase + + + Repeat new passphrase + Repeat new passphrase + + + + BanTableModel + + + BitcoinGUI + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_es_419.ts b/src/qt/locale/bitcoin_es_419.ts new file mode 100644 index 000000000000..91ba9478eac1 --- /dev/null +++ b/src/qt/locale/bitcoin_es_419.ts @@ -0,0 +1,167 @@ + + + AddressBookPage + + Right-click to edit address or label + Haga clic para editar la dirección o etiqueta + + + Create a new address + Crear una nueva dirección + + + &New + &New + + + Copy the currently selected address to the system clipboard + Copia la dirección seleccionada al portapapeles del sistema + + + Delete the currently selected address from the list + Borrar la dirección que esta seleccionada en la lista + + + Export the data in the current tab to a file + Exportar los datos de la actual tabla hacia un archivo + + + Choose the address to send coins to + Seleccione la dirección a la que enviará las monedas + + + Choose the address to receive coins with + Seleccione la dirección con la que recibirá las monedas + + + 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 de Bitcoin para enviar sus pagos. Siempre revise el monto y la dirección recibida antes de enviar monedas. + + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + Export the data in the current tab to a file + Exportar los datos de la actual tabla hacia un archivo + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_he_IL.ts b/src/qt/locale/bitcoin_he_IL.ts new file mode 100644 index 000000000000..722cc561a572 --- /dev/null +++ b/src/qt/locale/bitcoin_he_IL.ts @@ -0,0 +1,203 @@ + + + AddressBookPage + + Right-click to edit address or label + קליק ימני כדי לערוך כתובת או תווית + + + Create a new address + צור כתובת חדשה + + + &New + חדש + + + Copy the currently selected address to the system clipboard + העתק את הכתובת הנבחרת ללוח + + + &Copy + העתק + + + C&lose + סגור + + + Delete the currently selected address from the list + מחק את הכתובת הנבחרת מהרשימה + + + Export the data in the current tab to a file + יצא את המידע בעמוד הנוכחי לקובץ + + + &Export + ייצוא + + + &Delete + מחק + + + 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. + אלו הן כתובות הביטקוין שלך לקבלת תשלומים. מומלץ להשתמש בכתובת חדשה בכל העברת מטבעות + + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Bitcoin + ביטקוין + + + Wallet + ארנק + + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + ייצוא + + + Export the data in the current tab to a file + יצא את המידע בעמוד הנוכחי לקובץ + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index e1db9c25299e..1d06445e2c86 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -11,7 +11,7 @@ &New - नया + &NEW Copy the currently selected address to the system clipboard diff --git a/src/qt/locale/bitcoin_id.ts b/src/qt/locale/bitcoin_id.ts new file mode 100644 index 000000000000..0d4de19e80d2 --- /dev/null +++ b/src/qt/locale/bitcoin_id.ts @@ -0,0 +1,171 @@ + + + AddressBookPage + + Right-click to edit address or label + Klik kanan untuk mengubah alamat atau label + + + Create a new address + Buat sebuah alamat baru + + + &New + &Baru + + + Copy the currently selected address to the system clipboard + Salin alamat yang dipilih ke dalam clipboard sistem + + + &Copy + &Salin + + + C&lose + &Tutup + + + Delete the currently selected address from the list + Hapus alamat yang dipilih dari daftar + + + &Delete + &Hapus + + + Choose the address to send coins to + Pilih alamat untuk mengirim koin kepada + + + C&hoose + P&ilih + + + Sending addresses + Alamat mengirim + + + Receiving addresses + Alamat menerima + + + &Copy Address + &Salin Alamat + + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_ja_JP.ts b/src/qt/locale/bitcoin_ja_JP.ts new file mode 100644 index 000000000000..d1970597234c --- /dev/null +++ b/src/qt/locale/bitcoin_ja_JP.ts @@ -0,0 +1,2645 @@ + + + AddressBookPage + + Right-click to edit address or label + 編集するためにアドレスもしくはラベルを右クリックします + + + Create a new address + 新しいアドレスを作成します + + + &New + 新規 + + + Copy the currently selected address to the system clipboard + クリップボードに現在選択されているアドレスをコピーします + + + &Copy + &コピー + + + C&lose + C&失敗 + + + Delete the currently selected address from the list + リストから現在選択中のアドレスを削除します + + + Export the data in the current tab to a file + ファイルの現在のタブを出力します + + + &Export + &出力 + + + &Delete + &削除 + + + Choose the address to send coins to + 送付するコインのアドレスを選択 + + + Choose the address to receive coins with + 受け取るコインのアドレスを選択 + + + C&hoose + C&選択 + + + 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 + + Passphrase Dialog + パスフレーズダイヤログ + + + Enter passphrase + パスフレーズの入力 + + + New passphrase + 新規のパスフレーズ + + + 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. + 提供されたパスフレーズは一致しません。 + + + 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! + 注意: CapsLockキーが有効になっています! + + + + BanTableModel + + IP/Netmask + IPアドレス/ネットマスク + + + Banned Until + まで禁止 + + + + BitcoinGUI + + Sign &message... + サイン &メッセージ... + + + Synchronizing with network... + ネットワークで同期中... + + + &Overview + &概要 + + + Node + ノード + + + Show general overview of wallet + 財布の一般概要を表示 + + + &Transactions + &処理 + + + Browse transaction history + 処理の履歴を見る + + + E&xit + 退出 + + + Quit application + アプリケーションを終了 + + + &About %1 + &%1について + + + Show information about %1 + %1についての情報を見る + + + About &Qt + &Qtについて + + + Show information about Qt + Qtについての情報を見る + + + &Options... + &オプション... + + + Modify configuration options for %1 + %1のオプション設定を変更する + + + &Encrypt Wallet... + &財布の暗号化... + + + &Backup Wallet... + &財布のバックアップ... + + + &Change Passphrase... + &パスフレーズの変更... + + + &Sending addresses... + &アドレスの送信... + + + &Receiving addresses... + &アドレスの受信... + + + Open &URI... + オープン&URI... + + + Click to disable network activity. + ネットワーク処理を無効にするためにクリックする + + + Network activity disabled. + 無効化されたネットワーク + + + Click to enable network activity again. + 再度、ネットワーク処理を有効化するために、クリック + + + Syncing Headers (%1%)... + ヘッダーを同期中 (%1%)... + + + Reindexing blocks on disk... + ディスクのブロックの再インデックス中... + + + Send coins to a Bitcoin address + ビットコインアドレスにコインを送信 + + + Backup wallet to another location + 他の場所に財布をバックアップ + + + Change the passphrase used for wallet encryption + 財布の暗号化に使用するパスフレーズを変更 + + + &Debug window + &デバッグ用ウィンドウ + + + Open debugging and diagnostic console + デバッグと診断のコンソールを開く + + + &Verify message... + &メッセージの確認... + + + Bitcoin + ビットコイン + + + Wallet + 財布 + + + &Send + &送信 + + + &Receive + &受信 + + + &Show / Hide + &表示/ 非表示 + + + Show or hide the main Window + メインウィンドウの表示もしくは非表示 + + + Encrypt the private keys that belong to your wallet + 財布に属するプライベートキーの暗号化 + + + Sign messages with your Bitcoin addresses to prove you own them + 所有者であることを証明するためにビットコインアドレスのメッセージにサイン + + + Verify messages to ensure they were signed with specified Bitcoin addresses + 署名された特定のビットコインアドレスを確認するために、メッセージを確認 + + + &File + &ファイル + + + &Settings + &設定 + + + &Help + &ヘルプ + + + Tabs toolbar + ツールバータブ + + + Request payments (generates QR codes and bitcoin: URIs) + 支払の要求 (QRコードとビットコインのURIを作成) + + + Show the list of used sending addresses and labels + 送信に使用したアドレスとラベルの一覧を表示 + + + Show the list of used receiving addresses and labels + 受信に使用したアドレスとラベルの一覧を表示 + + + Open a bitcoin: URI or payment request + ビットコインのURIまたは支払要求を開く + + + &Command-line options + &コマンドラインのオプション + + + Indexing blocks on disk... + ディスクのブロックのインデックス化中... + + + Processing blocks on disk... + ディスクのブロックの処理中... + + + %1 behind + %1残り + + + Last received block was generated %1 ago. + 最後の受信ブロックは%1前に生成されました。 + + + Transactions after this will not yet be visible. + トランザクション後も、これらは見えることはありません。 + + + Error + エラー + + + Warning + 警告 + + + Information + 情報 + + + Up to date + 更新日 + + + Show the %1 help message to get a list with possible Bitcoin command-line options + ビットコインのコマンドラインオプションとして可能なリストの取得の%1ヘルプメッセージを表示 + + + %1 client + クライアント%1 + + + Connecting to peers... + ピアに接続中... + + + Catching up... + 追いつき中... + + + Date: %1 + + 日付: %1 + + + + Amount: %1 + + 残高: %1 + + + + Type: %1 + + タイプ: %1 + + + + Label: %1 + + ラベル: %1 + + + + Address: %1 + + アドレス: %1 + + + + Sent transaction + 処理送信 + + + Incoming transaction + 処理受信 + + + HD key generation is <b>enabled</b> + HDキー世代は<b>有効化</b> + + + HD key generation is <b>disabled</b> + HDキー世代は<b>無効化</b> + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + 財布は<b>暗号化された</b> そして現在 <b>ロック解除されています</b> + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + 財布は <b>暗号化され</b> そして現在 <b>ロックされています</b> + + + A fatal error occurred. Bitcoin can no longer continue safely and will quit. + 致命的なエラーが発生しました。ビットコインは安全に終了することができません。 + + + + CoinControlDialog + + Coin Selection + コイン選択 + + + Quantity: + 量: + + + Bytes: + バイト: + + + Amount: + 残高: + + + Fee: + 手数料: + + + Dust: + ごみ: + + + After Fee: + 後の料金: + + + Change: + 変更: + + + (un)select all + 全て選択する(しない) + + + Tree mode + ツリー型 + + + List mode + リストモード + + + Amount + 残高 + + + Received with label + 受信されたラベル + + + Received with address + 受信されたアドレス + + + Date + 日付 + + + Confirmations + 確認 + + + Confirmed + 確認済み + + + Copy address + アドレスのコピー + + + Copy label + ラベルのコピー + + + Copy amount + 残高のコピー + + + Copy transaction ID + トランザクションIDのコピー + + + Lock unspent + 未消費のロック + + + Unlock unspent + 未消費のロック解除 + + + Copy quantity + 量をコピー + + + Copy fee + 料金をコピー + + + Copy after fee + 後料金をこぴー + + + Copy bytes + バイトをコピー + + + Copy dust + ゴミをコピー + + + Copy change + 変更をコピー + + + (%1 locked) + (%1 ロック済み) + + + yes + はい + + + no + いいえ + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + 受信したレシピが現在のダスト閾値よりも残高が少ない場合、ラベルは赤になります。 + + + Can vary +/- %1 satoshi(s) per input. + 入力ごとにsatoshiの+/- %1に変更できます。 + + + (no label) + (ラベルなし) + + + change from %1 (%2) + %1 (%2)から変更 + + + (change) + (変更) + + + + EditAddressDialog + + Edit Address + アドレス編集 + + + &Label + &ラベル + + + The label associated with this address list entry + ラベルに結合されたアドレスのリストエントリー + + + The address associated with this address list entry. This can only be modified for sending addresses. + アドレスに結合されたアドレスリストのエントリーです。これは送信アドレスのみによって変更されます。 + + + &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. + 財布をロック解除できませんでした。 + + + New key generation failed. + 新規のキー生成に失敗しました。 + + + + FreespaceChecker + + A new data directory will be created. + 新しい日付の辞書が作成されるでしょう。 + + + name + 名前 + + + Directory already exists. Add %1 if you intend to create a new directory here. + 辞書はすでに存在しています。新しい辞書を作成する場合は、%1を追加してください。 + + + Path already exists, and is not a directory. + パスはすでに存在しており、辞書ではありません。 + + + Cannot create data directory here. + ここに日付辞書を作成することはできません。 + + + + HelpMessageDialog + + version + バージョン + + + (%1-bit) + (%1-ビット) + + + About %1 + %1について + + + Command-line options + コマンドラインオプション + + + Usage: + 使用方法: + + + command-line options + コマンドラインオプション: + + + UI Options: + UIオプション: + + + Choose data directory on startup (default: %u) + 起動の日付辞書の選択 (デフォルト: %u) + + + Set language, for example "de_DE" (default: system locale) + 言語設定, 例 "de_DE" (デフォルト: システムロケール) + + + Start minimized + 最小化起動 + + + Set SSL root certificates for payment request (default: -system-) + 支払要求のSSLルート証明の設定 (デフォルト: -システム-) + + + Show splash screen on startup (default: %u) + 起動スクリーンを表示 (デフォルト: %u) + + + Reset all settings changed in the GUI + GUIのすべての設定をリセット + + + + Intro + + Welcome + ようこそ + + + Welcome to %1. + ようこそ %1. + + + As this is the first time the program is launched, you can choose where %1 will store its data. + プログラムの初回起動時なので、データの保存場所 %1を選択してください。 + + + Use the default data directory + デフォルトデータ辞書を使用 + + + Use a custom data directory: + カスタムデータ辞書を使用 + + + Error: Specified data directory "%1" cannot be created. + エラー: 特定の辞書%1の作成に失敗しました。 + + + Error + エラー + + + + ModalOverlay + + Form + フォーム + + + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. + 最近のトランザクションが表示できない可能性があります。従って、ウォレットの残高が正しくない可能性があります。この情報はビットコインネットワークに接続し、同期処理を完了させると正しくなります。詳細は以下になります。 + + + Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network. + 使用したビットコインで、未処理となっているものは、ネットワークによって受領されません。 + + + Number of blocks left + 残りのブロック数 + + + Unknown... + 不明... + + + Last block time + 最後のブロック時間 + + + Progress + 実行 + + + Progress increase per hour + 時間ごとの実行増加 + + + calculating... + 計算中... + + + Estimated time left until synced + 同期化完了までの予測時間 + + + Hide + 隠す + + + Unknown. Syncing Headers (%1)... + 不明. ヘッダーの同期中 (%1)... + + + + OpenURIDialog + + Open URI + オープンURI + + + Open payment request from URI or file + URLもしくはファイルからの支払い要求を開く + + + URI: + URI: + + + Select payment request file + 支払い要求ファイルの選択 + + + Select payment request file to open + 開く支払い要求ファイルを選択 + + + + OptionsDialog + + Options + オプション + + + &Main + &メイン + + + Automatically start %1 after logging in to the system. + システムログイン時に%1を自動的に開始 + + + &Start %1 on system login + &システムログインで%1を開始 + + + Size of &database cache + &データベース喝取のサイズ + + + MB + メガバイト + + + Number of script &verification threads + &認証スレッドスクリプトの数 + + + Accept connections from outside + 外部からの接続承認 + + + Allow incoming connections + 内部接続の許可 + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + IP プロキシのアドレス (例 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. + ウィンドウが閉じられた時、アプリケーションを終了せずに最小化します。オプションボタンが有効な時は、アプリケーションはメニューの終了が選択されら時のみ、終了します。 + + + 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 |. + サードパーティのURL(例 a block explorer)はコンテキストメニューアイテムの処理タブに表示されます。YRLの%sは処理ハッシュによって置き換えられます。複数URLは水平バー | によって区切られます。 + + + Third party transaction URLs + サードパティ処理URL + + + Active command-line options that override above options: + オプション上書きのコマンドラインオプションの有効化 + + + Reset all client options to default. + 全てのクライアントオプションをデフォルトにリセット + + + &Reset Options + &リセットオプション + + + &Network + &ネットワーク + + + (0 = auto, <0 = leave that many cores free) + (0 = 自動, <0 = 使用しないコア数) + + + W&allet + ウォレット + + + Expert + 専門家 + + + Enable coin &control features + コインと制御機能の有効化 + + + 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. + 認証されていない変更の支出を無効化した場合、その変更を含む処理はすべての認証が完了するまで、使用することはできません。また、これは残高の計算にも影響します。 + + + &Spend unconfirmed change + &認証されていない変更の支払い + + + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. + 自動絵的にルータのビットコインのクライアントポートが開きます。この機能はルータがUPnPをサポートし、有効であるときに動作します。 + + + Map port using &UPnP + &UPnPを使用してポート配置します。 + + + Connect to the Bitcoin network through a SOCKS5 proxy. + SOCKS5プロキシを使用してビットコインネットワークへ接続 + + + &Connect through SOCKS5 proxy (default proxy): + &SOCKS5プロキシを使用して接続 (デフォルト プロキシ): + + + Proxy &IP: + プロキシ &IP: + + + &Port: + &ポート: + + + Port of the proxy (e.g. 9050) + プロキシのポート (例 9050) + + + Used for reaching peers via: + ピア経由での使用: + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Tor秘匿ネットワークのための区切られたSOCKS5を経由して、ビットコインネットワークに接続 + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Tor匿名サービスを経由して到達ピアへ、区切られたSOCKS5 プロキシを使用: + + + &Window + &画面 + + + &Hide the icon from the system tray. + &システムトレイのアイコンを非表示. + + + Hide tray icon + トレイアイコンを非表示 + + + Show only a tray icon after minimizing the window. + 画面最小化時にトレイアイコンを表示する。 + + + &Minimize to the tray instead of the taskbar + &ツールバーの代わりにトレイへ最小化 + + + M&inimize on close + クローズで最小化 + + + &Display + &画面 + + + User Interface &language: + ユーザインターフェース &言語: + + + The user interface language can be set here. This setting will take effect after restarting %1. + ユーザインタフェースの言語はここで設定されます。設定は%1を再起動後、有効になります。 + + + &Unit to show amounts in: + &残高表示の単位: + + + Choose the default subdivision unit to show in the interface and when sending coins. + コイン送付時のインターフェースに表示するデフォルトの除算単位の選択 + + + Whether to show coin control features or not. + コイン制御機能を表示するかどうか。 + + + &OK + &OK + + + &Cancel + &キャンセル + + + default + デフォルト + + + none + なし + + + Confirm options reset + オプションリセットの確認 + + + Client restart required to activate changes. + 変更を有効にするため、クライアントの再起動が必要です。 + + + Client will be shut down. Do you want to proceed? + クライアントは停止します。継続してもよろしいでしょうか? + + + This change would require a client restart. + 変更は、クライアントの再起動が必要になる場合があります。 + + + The supplied proxy address is invalid. + 提供されたプロキシアドレスは無効です。 + + + + OverviewPage + + 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. + 表示されている情報は、期限切れの可能性があります。ウォレットは自動的にビットコインネットワークへの接続が確立した後に同期化されます。しかし、処理はまだ、完了していません。 + + + Watch-only: + 読み取り専用: + + + Available: + 有効: + + + Your current spendable balance + 現在の支払い可能な残高 + + + Pending: + 未決定: + + + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + 全てのトランザクションはまだ、確認されておらず、支払い可能な残高も数えられていません。 + + + Immature: + 未完成: + + + Mined balance that has not yet matured + まだ、完成していない、採掘された残高 + + + Balances + 残高 + + + Total: + 合計: + + + Your current total balance + 現在の合計残高 + + + Your current balance in watch-only addresses + 読み取り専用アドレス内の現在の残高 + + + Spendable: + 支払い可能: + + + Recent transactions + 最近の処理 + + + Unconfirmed transactions to watch-only addresses + 読み取り専用アドレスへの未確認の処理 + + + Mined balance in watch-only addresses that has not yet matured + まだ、完成していない、読み取り専用アドレスの中の発掘された残高 + + + Current total balance in watch-only addresses + 読み取り専用アドレス内の現在の合計残高 + + + + PaymentServer + + Payment request error + 支払い要求エラー + + + Cannot start bitcoin: click-to-pay handler + ビットコインを開始できません: click-to-pay handler + + + URI handling + URI ハンドリング + + + Payment request fetch URL is invalid: %1 + 取得した支払要求は無効です: %1 + + + Invalid payment address %1 + 無効な支払アドレス %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URLはパースできませんでした! 原因はビットコインアドレスが無効であるか、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 request is not initialized. + 支払要求は初期化されていません。 + + + Unverified payment requests to custom payment scripts are unsupported. + カスタム支払スクリプトへの未検証の支払要求は、サポートされていません。 + + + Invalid payment request. + 無効な支払要求: + + + Requested payment amount of %1 is too small (considered dust). + 要求支払額%1は小さすぎます (ダストを検討してください). + + + Refund from %1 + %1からの払い戻し + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + 支払要求 %1 は大きすぎます (%2 バイト, %3 バイトまで許可). + + + Error communicating with %1: %2 + 通信エラー:%1 :%2 + + + Payment request cannot be parsed! + 支払要求は解析できませんでした! + + + Bad response from server %1 + サーバ%1からの不正なレスポンス + + + Network request error + ネットワーク要求エラー + + + Payment acknowledged + 認証済み支払 + + + + PeerTableModel + + User Agent + ユーザエージェント + + + Node/Service + ノード/サービス + + + NodeId + ノードID + + + Ping + Ping + + + + QObject + + Amount + 残高 + + + Enter a Bitcoin address (e.g. %1) + ビットコインアドレスの入力 (例 %1) + + + %1 d + %1 d + + + %1 h + %1 h + + + %1 m + %1 m + + + %1 s + %1 s + + + None + なし + + + N/A + 該当なし + + + %1 ms + %1 ms + + + %1 and %2 + %1 と %2 + + + %1 didn't yet exit safely... + %1 は安全に終了できませんでした... + + + + QObject::QObject + + Error: Specified data directory "%1" does not exist. + エラー: 特定の日付辞書 "%1" は存在しません。 + + + Error: Cannot parse configuration file: %1. Only use key=value syntax. + エラー: 構成ファイルが解析できませんでした: %1. キー=値の構文のみが使用できます。 + + + Error: %1 + エラー: %1 + + + + QRImageWidget + + &Save Image... + &イメージ保存... + + + &Copy Image + &イメージコピー + + + Save QR Code + QRコード保存 + + + PNG Image (*.png) + PNGイメージ(*.png) + + + + RPCConsole + + N/A + 該当なし + + + Client version + クライアントバージョン + + + &Information + &情報 + + + Debug window + デバッグ画面 + + + General + 一般 + + + Using BerkeleyDB version + BerkeleyDBバージョンの使用 + + + Datadir + データディレクトリ + + + Startup time + 開始時間 + + + Network + ネットワーク + + + Name + 名前 + + + Number of connections + 接続数 + + + Block chain + ブロックチェーン + + + Current number of blocks + 現在のブロック数 + + + Memory Pool + メモリプール + + + Current number of transactions + 現在の処理数 + + + Memory usage + メモリ使用量 + + + Received + 受信済み + + + Sent + 送信済み + + + &Peers + &ピア + + + Banned peers + 禁止ピア + + + Select a peer to view detailed information. + 詳細情報を表示するピアの選択 + + + Whitelisted + ホワイトリスト済み + + + Direction + 方向 + + + Version + バージョン + + + Starting Block + ブロック開始中 + + + Synced Headers + 同期化されたヘッダー + + + Synced Blocks + 同期化されたブロック + + + User Agent + ユーザエージェント + + + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. + 現在のデータ辞書から%1デバッグログファイルを開きます。ログファイルが大きいため、数秒かかります。 + + + Decrease font size + フォントサイズの縮小 + + + Increase font size + フォントサイズの拡大 + + + Services + サービス + + + Ban Score + 禁止スコア + + + Connection Time + 接続時間 + + + Last Send + 最後の送信 + + + Last Receive + 最終受信 + + + Ping Time + Ping時間 + + + The duration of a currently outstanding ping. + 現在の異常なpingの間隔 + + + Ping Wait + ping待ち + + + Min Ping + ping最小時間 + + + Time Offset + 時間オフセット + + + Last block time + 最後のブロック時間 + + + &Open + &開く + + + &Console + &コンソール + + + &Network Traffic + &ネットワークトラヒック + + + Totals + 合計 + + + In: + 入力: + + + Out: + 出力: + + + Debug log file + デバッグログファイル + + + Clear console + コンソールのクリア + + + 1 &hour + 1 &時 + + + 1 &day + 1 &日 + + + 1 &week + 1 &週 + + + 1 &year + 1 &年 + + + &Disconnect + &切断 + + + Ban for + 禁止の + + + &Unban + &禁止しない + + + Welcome to the %1 RPC console. + %1 RPCコンソールへようこそ + + + Type <b>help</b> for an overview of available commands. + <b>help</b> と入力すると有効なコマンドが表示されます。 + + + Network activity disabled + 無効化されたネットワーク利用 + + + %1 B + %1 バイト + + + %1 KB + %1 キロバイト + + + %1 MB + %1 メガバイト + + + %1 GB + %1 Gギガバイト + + + (node id: %1) + (ノードid: %1) + + + via %1 + %1経由 + + + never + いままでない + + + Inbound + 流入 + + + Outbound + 流出 + + + Yes + はい + + + No + いいえ + + + Unknown + 未知 + + + + ReceiveCoinsDialog + + &Amount: + &残高: + + + &Label: + &ラベル: + + + &Message: + &メッセージ: + + + 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. + 前回使用された受信アドレスを再利用します。再度アドレスを使用することは、セキュリティとプライバシーの問題になります。再度支払要求を事前に再生成しない限り、これを使用しないようにしてください。 + + + R&euse an existing receiving address (not recommended) + &再度存在している受信アドレスを死闘する(非推奨) + + + 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. + 支払要求に添付されたオプションメッセージは、要求を開いたときに表示されます。メモ: メッセージは、ビットコインネットワーク上で支払と一緒に送信されません。 + + + An optional label to associate with the new receiving address. + 新規受信アドレスと関連するオプションラベル + + + Use this form to request payments. All fields are <b>optional</b>. + 支払要求のための形式を使用してください。すべてのフィールドは<b>おプション</b> です。 + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + 要求のためのオプション残高。特定の金額の要求をしないときは空か0を入力します。 + + + Clear all fields of the form. + 入力形式の全てのフィールドをクリア + + + Clear + クリア + + + Requested payments history + 支払要求履歴 + + + &Request payment + &支払要求 + + + Show the selected request (does the same as double clicking an entry) + 選択された要求の表示。(空をダブルクリックしたときと同じ) + + + Show + 表示 + + + Remove the selected entries from the list + リストから選択されたエントリの削除 + + + Remove + 削除 + + + Copy URI + コピーURI + + + Copy label + ラベルのコピー + + + Copy message + メッセージコピー + + + Copy amount + 残高のコピー + + + + ReceiveRequestDialog + + QR Code + QRコード + + + Copy &URI + &URIコピー + + + Copy &Address + &アドレスコピー + + + &Save Image... + &イメージ保存... + + + Request payment to %1 + %1のための支払要求 + + + Payment information + 支払情報 + + + URI + URI + + + Address + アドレス + + + Amount + 残高 + + + Label + ラベル + + + Message + メッセージ + + + Resulting URI too long, try to reduce the text for label / message. + URIが長すぎるので、ラベルまたはメッセージを短くしてください。 + + + Error encoding URI into QR Code. + QRコードのURIのコード化エラー + + + + RecentRequestsTableModel + + Date + 日付 + + + Label + ラベル + + + Message + メッセージ + + + (no label) + (ラベルなし) + + + (no message) + (メッセージなし) + + + (no amount requested) + (料金要求なし) + + + Requested + 要求済み + + + + SendCoinsDialog + + Send Coins + コイン送付 + + + Coin Control Features + コイン制御機能 + + + Inputs... + 入力... + + + automatically selected + 自動的に選択される + + + Insufficient funds! + 残高不十分! + + + Quantity: + 量: + + + Bytes: + バイト: + + + Amount: + 残高: + + + Fee: + 手数料: + + + After Fee: + 後の料金: + + + Change: + 変更: + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + これが有効化されていて変更アドレスが空または無効でない時、変更は新しく生成されたアドレスへ送信されます。 + + + Custom change address + カスタム変更アドレス + + + Transaction Fee: + 処理費用: + + + Choose... + 選択... + + + collapse fee-settings + 料金設定を折りたたむ + + + per 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. + カスタム料金が1000 satoshiで処理が250バイトのみの場合、料金はキロバイトあたりは250 satoshiのみとなり、最新の合計は1000 satoshiまで支払います。処理が1キロバイトよりも大きい場合、キロバイトごとに支払いが行われます。 + + + Hide + 隠す + + + 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. + 最小の料金のみ支払いは、ブロック内の処理容量よりも小さい場合に限り、問題ありません。しかし、ネットワークの処理できる量よりも、ビットコイン処理のほうが需要があり、最終的にその確認処理が実行されないことに注意する必要があります。 + + + (read the tooltip) + (ツールチップを読む) + + + Recommended: + 推奨: + + + Custom: + カスタム: + + + (Smart fee not initialized yet. This usually takes a few blocks...) + (スマート料金は初期化されていません。通常であれば数ブロックかかります...) + + + Send to multiple recipients at once + 一度に複数の受信者に送信します + + + Add &Recipient + 追加&受信者 + + + Clear all fields of the form. + 入力形式の全てのフィールドをクリア + + + Dust: + ごみ: + + + Confirmation time target: + 目標時間の確認: + + + Clear &All + クリア&全て + + + Balance: + 残高: + + + Confirm the send action + 送信実行の確認 + + + S&end + &送信 + + + Copy quantity + 量をコピー + + + Copy amount + 残高のコピー + + + Copy fee + 料金をコピー + + + Copy after fee + 後料金をこぴー + + + Copy bytes + バイトをコピー + + + Copy dust + ゴミをコピー + + + Copy change + 変更をコピー + + + %1 to %2 + %2から%1 + + + Are you sure you want to send? + 送信してもよろしいですか? + + + added as transaction fee + 処理料金として追加済み + + + Total Amount %1 + 合計残高: %1 + + + or + もしくは + + + Confirm send coins + 送信コイン確認 + + + The recipient address is not valid. Please recheck. + 受信者アドレスは無効です。再度確認してください。 + + + The amount to pay must be larger than 0. + 支払料金は0より大きい必要があります。 + + + The amount exceeds your balance. + 料金が残高を超えています。 + + + The total exceeds your balance when the %1 transaction fee is included. + %1の処理料金を含めると、合計が残高を超えます。 + + + Duplicate address found: addresses should only be used once each. + 重複アドレスの発見: アドレスはそれぞれ一つずつ使用される必要があります。 + + + Transaction creation failed! + 処理の作成に失敗しました! + + + The transaction was rejected with the following reason: %1 + 処理は次の理由により却下されました: %1 + + + A fee higher than %1 is considered an absurdly high fee. + 料金が%1より高い場合、非常識に高い料金として考えられます。 + + + Payment request expired. + 支払要求期限切れ + + + Pay only the required fee of %1 + %1の必須料金のみ支払う + + + Warning: Invalid Bitcoin address + 注意: 無効なビットコインアドレス + + + Warning: Unknown change address + 注意: 未知の変更アドレス + + + Confirm custom change address + カスタム変更アドレスの確認 + + + The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure? + 変更のために選択したアドレスは、ウォレットの一部ではありません。ウォレット内の一部またはすべて料金はこのアドレスで送付される必要があります。実行してもよろしいでしょうか? + + + (no label) + (ラベルなし) + + + + SendCoinsEntry + + A&mount: + &残高: + + + Pay &To: + 支払&宛先: + + + &Label: + &ラベル: + + + Choose previously used address + 前回使用したアドレスの選択 + + + This is a normal payment. + これは通常の支払です。 + + + The Bitcoin address to send the payment to + 支払に送信するビットコインアドレス + + + Alt+A + Alt+A + + + Paste address from clipboard + クリップボードからアドレスを貼り付ける + + + Alt+P + Alt+P + + + Remove this entry + 入力の削除 + + + 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. + 料金は送信料金から控除されます。受信者は入力された料金よりも低い金額を受け取ります。複数の受信者を選択した場合、この料金は同額に分けられます。 + + + S&ubtract fee from amount + &残高から料金を差し引く + + + Message: + メッセージ: + + + This is an unauthenticated payment request. + これは未証明の支払要求です。 + + + This is an authenticated payment request. + これは証明済みの支払要求です。 + + + Enter a label for this address to add it to the list of used addresses + 使用されたアドレス一覧のために、このアドレスのラベルを入力します。 + + + 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. + 参考資料に保存された処理のビットコインURIは、メッセージに添付されます。メモ: このメッセージはビットコイン上で送信されません。 + + + Pay To: + 支払先: + + + Memo: + メモ: + + + Enter a label for this address to add it to your address book + アドレス帳にアドレスを追加すためのラベルの入力 + + + + SendConfirmationDialog + + Yes + はい + + + + ShutdownWindow + + %1 is shutting down... + %1は停止中です... + + + Do not shut down the computer until this window disappears. + この画面が消えるまで、コンピュータを停止しないでください。 + + + + SignVerifyMessageDialog + + Signatures - Sign / Verify a Message + 署名 - サイン / メッセージの確認 + + + &Sign Message + &署名メッセージ + + + 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. + 送信されたビットコインを受信できることを証明するために、アドレスのメッセージや同意事項に署名できます。フィッシング攻撃が署名を利用する可能性があるので、署名が曖昧やランダムでないことに注意してください。詳細な明細のみに署名されます。 + + + The Bitcoin address to sign the message with + メッセージ署名するためのビットコインアドレス + + + Choose previously used address + 前回使用したアドレスの選択 + + + Alt+A + Alt+A + + + Paste address from clipboard + クリップボードからアドレスを貼り付ける + + + Alt+P + Alt+P + + + Enter the message you want to sign here + ここに署名をするメッセージを入力 + + + Signature + 署名 + + + Copy the current signature to the system clipboard + システムのクリップボードへ現在の署名をコピー + + + Sign the message to prove you own this Bitcoin address + ビットコインアドレスを証明するために、メッセージに署名 + + + Sign &Message + 署名&メッセージ + + + Reset all sign message fields + 全ての署名フィールドをリセット + + + Clear &All + クリア&全て + + + &Verify Message + &メッセージ確認 + + + 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! + 以下のメッセージを確認して、受信者のアドレス、メッセージ(タブやすスペースなどを正確にこぴーしてください)、署名を入力してください。中間の攻撃者からのアタックを避けるために、署名されていないメッセージを読まないように注意してください。署名はアドレスと受信を証明することはできますが、送信者の処理を証明できないことに注意してください。 + + + The Bitcoin address the message was signed with + メッセージのビットコインアドレスはサインされています + + + Verify the message to ensure it was signed with the specified Bitcoin address + 特定のビットコインアドレスと署名されているメッセージであることを確認してください。 + + + Verify &Message + 確認&メッセージ + + + Reset all verify message fields + 全ての確認フィールドをリセット + + + Click "Sign Message" to generate signature + 署名を生成するため、"署名メッセージ"をクリック + + + The entered address is invalid. + 入力されたアドレスは無効です。 + + + Please check the address and try again. + アドレスを確認して、再実行してください。 + + + The entered address does not refer to a key. + 入力されたアドレスは鍵と関連がありません。 + + + Wallet unlock was cancelled. + ウォレットのロック解除は中断されました。 + + + Private key for the entered address is not available. + 入力されたプライベートキーは無効です。 + + + Message signing failed. + メッセージの署名は失敗しました。 + + + Message signed. + メッセージに署名しました。 + + + The signature could not be decoded. + 署名は復号化できませんでした。 + + + Please check the signature and try again. + 署名を確認して、再実行してください。 + + + The signature did not match the message digest. + 署名は、メッセージダイジェストと一致しませんでした。 + + + Message verification failed. + メッセージ確認は失敗しました。 + + + Message verified. + メッセージは確認されました。 + + + + SplashScreen + + [testnet] + [testnet] + + + + TrafficGraphWidget + + KB/s + キロバイト/秒 + + + + TransactionDesc + + Open until %1 + %1まで開く + + + conflicted with a transaction with %1 confirmations + 処理と%1確認が矛盾しています。 + + + %1/offline + %1/オフライン + + + 0/unconfirmed, %1 + 0/未確認, %1 + + + in memory pool + メモリプール中 + + + not in memory pool + メモリプール外 + + + abandoned + 放棄 + + + %1/unconfirmed + %1/未確認 + + + %1 confirmations + %1 確認 + + + Status + 状態 + + + , has not been successfully broadcast yet + まだ、散布に成功していません + + + Date + 日付 + + + Source + ソース + + + Generated + 生成済み + + + From + 送信元 + + + unknown + 不明 + + + To + 送信先 + + + own address + 自アドレス + + + watch-only + 読み取り専用 + + + label + ラベル + + + Credit + 信用 + + + not accepted + 承認拒否 + + + Debit + デビット + + + Total debit + デビットの合計 + + + Total credit + 合計クレジット + + + Transaction fee + 処理料金 + + + Net amount + ネット残高 + + + Message + メッセージ + + + Comment + コメント + + + Transaction ID + 処理ID + + + Transaction total size + 処理合計サイズ + + + Output index + 出力インデックス + + + Merchant + 商人 + + + Amount + 残高 + + + + TransactionDescDialog + + + TransactionTableModel + + Date + 日付 + + + Label + ラベル + + + Open until %1 + %1まで開く + + + watch-only + 読み取り専用 + + + (no label) + (ラベルなし) + + + + TransactionView + + Copy address + アドレスのコピー + + + Copy label + ラベルのコピー + + + Copy amount + 残高のコピー + + + Copy transaction ID + トランザクションIDのコピー + + + Comma separated file (*.csv) + カンマ区切りのファイル(*.csv) + + + Confirmed + 確認済み + + + Date + 日付 + + + Label + ラベル + + + Address + アドレス + + + Exporting Failed + 出力の失敗 + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + Send Coins + コイン送付 + + + + WalletView + + &Export + &出力 + + + Export the data in the current tab to a file + ファイルの現在のタブを出力します + + + + bitcoin-core + + Information + 情報 + + + Warning + 警告 + + + Error + エラー + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_my.ts b/src/qt/locale/bitcoin_my.ts new file mode 100644 index 000000000000..f123d3758bed --- /dev/null +++ b/src/qt/locale/bitcoin_my.ts @@ -0,0 +1,163 @@ + + + AddressBookPage + + Right-click to edit address or label + လိပ်စာ သို့မဟုတ် ခေါင်းစဉ်တပ်ရန် Right-click နှိပ်ပါ။ + + + Create a new address + လိပ်စာအသစ်ယူမယ်။ + + + &New + &အသစ် + + + Copy the currently selected address to the system clipboard + လက်ရှိရွေးထားတဲ့ လိပ်စာကို clipboard ပေါ်တင်မယ်။ + + + &Copy + &ကူးမယ် + + + Delete the currently selected address from the list + လက်ရှိရွေးထားတဲ့ လိပ်စာကို ဖျက်မယ်။ + + + Export the data in the current tab to a file + လက်ရှိ tab မှာရှိတဲ့ဒေတာတွေကို ဖိုင်လ်မှာသိမ်းမယ်။ + + + &Export + &ထုတ်ယူသိမ်းဆည်း + + + &Delete + &ဖျက် + + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &ထုတ်ယူသိမ်းဆည်း + + + Export the data in the current tab to a file + လက်ရှိ tab မှာရှိတဲ့ဒေတာတွေကို ဖိုင်လ်မှာသိမ်းမယ်။ + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_nb_NO.ts b/src/qt/locale/bitcoin_nb_NO.ts new file mode 100644 index 000000000000..1b8c20443cc4 --- /dev/null +++ b/src/qt/locale/bitcoin_nb_NO.ts @@ -0,0 +1,575 @@ + + + AddressBookPage + + Right-click to edit address or label + Høyreklikk for å redigere adresse, eller beskrivelse + + + Create a new address + Opprett en ny adresse + + + &New + &Ny + + + Copy the currently selected address to the system clipboard + Kopier den valgte adressen til utklippstavlen + + + &Copy + &Kopier + + + C&lose + &Lukk + + + Delete the currently selected address from the list + Slett den valgte adressen fra listen + + + Export the data in the current tab to a file + Eksporter data i den valgte fliken til en fil + + + &Export + &Eksport + + + &Delete + &Slett + + + Choose the address to send coins to + Velg en adresse å sende mynter til + + + Choose the address to receive coins with + Velg adressen som skal motta myntene + + + C&hoose + &Velg + + + Sending addresses + Avsender adresser + + + Receiving addresses + Mottager adresser + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Dette er dine Bitcoin adresser for å sende å sende betalinger. Husk å sjekke beløp og mottager adresser før du sender mynter. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Dette er dine Bitcoin adresse for å motta betalinger. Det er anbefalt å bruke en ny mottager adresse for hver transaksjon. + + + &Copy Address + &Kopier adresse + + + Copy &Label + Kopier &beskrivelse + + + &Edit + R&ediger + + + Export Address List + Eksporter adresse listen + + + Comma separated file (*.csv) + Komma separert fil (*.csv) + + + Exporting Failed + Eksporten feilet + + + There was an error trying to save the address list to %1. Please try again. + Fet oppstod en feil ved lagring av adresselisten til %1. Vennligst prøv igjen. + + + + AddressTableModel + + Label + Beskrivelse + + + Address + Adresse + + + (no label) + (ingen beskrivelse) + + + + AskPassphraseDialog + + Passphrase Dialog + Passord dialog + + + Enter passphrase + Oppgi passord setning + + + New passphrase + Ny passord setning + + + Repeat new passphrase + Repeter passorsetningen + + + 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>. + Oppgi passordsetningen for lommeboken. <br/>Vennligst bruk en passordsetninge med <b>ti, eller flere tilfeldige tegn </b>, eller <b>åtte, eller flere ord</b>. + + + Encrypt wallet + Krypter lommeboken + + + This operation needs your wallet passphrase to unlock the wallet. + Denne operasjonen krever passordsetningen for å låse opp lommeboken. + + + Unlock wallet + Lås opp lommeboken + + + This operation needs your wallet passphrase to decrypt the wallet. + Denne operasjonen krever passordsetningen for å dekryptere lommeboken. + + + Decrypt wallet + Dekrypter lommeboken + + + Change passphrase + Endre passordsetningen + + + Enter the old passphrase and new passphrase to the wallet. + Oppgi den gamle og den nye passordsetningen for lommeboken. + + + Confirm wallet encryption + Bekreft kryptering av lommeboken + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Advarsel: Dersom du krypterer lommeboken og mister passordsetningen vil du <b>MISTE ALLE DINE BITCOIN</b>! + + + Are you sure you wish to encrypt your wallet? + Er du sikker på at du vil kryptere lommeboken? + + + Wallet encrypted + Lommeboken er kryptert + + + %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 vil nå lukkes for å fullføre krypteringsprosessen. Husk at å kryptere lommeboken ikke kan beskytte dine bitcoin fullstendig fra å bli stjålet av skadelig programvare som har infisert datamaskinen din. + + + 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. + VIKTIG: Alle tidligere sikkerhetskopier du har tatt av lommebokfilen bør erstattes med den nye krypterte lommebokfilen. Av sikkerhetsgrunner vil tidligere sikkerhetskopier av lommebokfilen bli ubrukelige når du begynner å bruke den ny kypterte lommeboken. + + + Wallet encryption failed + Lommebokkrypteringen feilet + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Lommebokkrypteringen feilet pga. en intern feil. Lommeboken din ble ikke kryptert. + + + The supplied passphrases do not match. + De oppgitte passordsetningene er forskjellige. + + + Wallet unlock failed + Opplåsing av lommeboken feilet + + + The passphrase entered for the wallet decryption was incorrect. + Passordsetningen som ble oppgitt for å dekryptere lommeboken var feil. + + + Wallet decryption failed + Dekryptering av lommeboken feilet + + + Wallet passphrase was successfully changed. + Passordsetningen for lommeboken ble endret + + + Warning: The Caps Lock key is on! + Advarsel: Caps Lock er på! + + + + BanTableModel + + IP/Netmask + IP/Nettmaske + + + Banned Until + Utestengt Til + + + + BitcoinGUI + + Sign &message... + Signer &melding + + + Synchronizing with network... + Synkroniserer med nettverket + + + &Overview + &Oversikt + + + Node + Node + + + Show general overview of wallet + Vis generell oversikt over lommeboken + + + &Transactions + &Transaksjoner + + + Browse transaction history + Bla gjennom transaksjoner + + + E&xit + &Avslutt + + + Quit application + Avslutt program + + + &About %1 + &Om %1 + + + Show information about %1 + Vis informasjon om %1 + + + About &Qt + Om &Qt + + + Show information about Qt + Vis informasjon om Qt + + + &Options... + &Valg + + + Modify configuration options for %1 + Endre konfigurasjonsalternativer for %1 + + + &Encrypt Wallet... + &Krypter lommebok... + + + &Backup Wallet... + &Sikkerhetskopier lommebok + + + &Change Passphrase... + &Endre passordsetning + + + &Sending addresses... + &Avsender adresser + + + &Receiving addresses... + &Mottager adresser + + + Open &URI... + Åpne &URI + + + Click to disable network activity. + Klikk for å slå av nettverksaktivitet. + + + Network activity disabled. + Nettverksaktivitet er slått av + + + Click to enable network activity again. + Klikk for å slå på nettverksaktivitet igjen. + + + Syncing Headers (%1%)... + Synkroniserer Headers (%1%)... + + + Reindexing blocks on disk... + Reindekserer blokker på disken + + + Send coins to a Bitcoin address + Send mynter til en Bitcoin adresse + + + Backup wallet to another location + Sikkerhetskopier lommeboken til en annen lokasjon + + + Change the passphrase used for wallet encryption + Endre passordsetningen for kryptering av lommeboken + + + &Debug window + &Feilsøkingsvindu + + + Open debugging and diagnostic console + Åpne konsoll for feilsøking og diagnostisering + + + &Verify message... + &Verifiser meldingen... + + + Bitcoin + Bitcoin + + + Wallet + Lommebok + + + &Send + &Sende + + + &Receive + &Motta + + + &Show / Hide + Vi&s / Skjul + + + Show or hide the main Window + Vis, eller skjul, hovedvinduet + + + Encrypt the private keys that belong to your wallet + Krypter de private nøklene som tilhører lommeboken din + + + Sign messages with your Bitcoin addresses to prove you own them + Signer meldingene med Bitcoin adresse for å bevise at diu eier dem + + + Verify messages to ensure they were signed with specified Bitcoin addresses + Verifiser meldinger for å sikre at de ble signert med en angitt Bitcoin adresse + + + &File + &Fil + + + &Settings + In&stillinger + + + &Help + &Hjelp + + + Tabs toolbar + Hjelpelinje for fliker + + + + CoinControlDialog + + (no label) + (ingen beskrivelse) + + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Address + Adresse + + + Label + Beskrivelse + + + + RecentRequestsTableModel + + Label + Beskrivelse + + + (no label) + (ingen beskrivelse) + + + + SendCoinsDialog + + (no label) + (ingen beskrivelse) + + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + Label + Beskrivelse + + + (no label) + (ingen beskrivelse) + + + + TransactionView + + Comma separated file (*.csv) + Komma separert fil (*.csv) + + + Label + Beskrivelse + + + Address + Adresse + + + Exporting Failed + Eksporten feilet + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Eksport + + + Export the data in the current tab to a file + Eksporter data i den valgte fliken til en fil + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_nl_NL.ts b/src/qt/locale/bitcoin_nl_NL.ts new file mode 100644 index 000000000000..dbd68c0b354a --- /dev/null +++ b/src/qt/locale/bitcoin_nl_NL.ts @@ -0,0 +1,199 @@ + + + AddressBookPage + + Right-click to edit address or label + Klik met de rechter muisknop om dit adres of label te veranderen + + + Create a new address + Maak een nieuw adres aan + + + &New + &Nieuw + + + Copy the currently selected address to the system clipboard + Kopieer het geselecteerde adres naar het klembord + + + &Copy + &Kopieren + + + C&lose + S&luiten + + + Delete the currently selected address from the list + Verwijder het geselecteerde adres uit de lijst + + + Export the data in the current tab to a file + Exporteer de data in dit tab naar een bestand + + + &Export + &Exporteer + + + &Delete + &Verwijderen + + + Choose the address to send coins to + Selecteer het adres om munten naar toe te sturen. + + + Choose the address to receive coins with + Selecteer het adres om munten mee te ontvangen. + + + C&hoose + S&electeren + + + Sending addresses + Verzendadres + + + Receiving addresses + Ontvangstadres + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Dit zijn uw Bitcoin adressen voor het versturen van betalingen. Controleer altijd het bedrag en het ontvangstadres voordat u munten verstuurd. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Dit zijn uw Bitcoin adressen voor het ontvangen van betalingen. Het wordt aanbevolen om voor elke transactie een nieuw ontvangstadres te gebruiken. + + + &Copy Address + &Adres Kopiëren + + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Exporteer + + + Export the data in the current tab to a file + Exporteer de data in dit tab naar een bestand + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 3675bd060a8e..c7355e626f6d 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -889,6 +889,10 @@ Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. Świeże transakcje mogą nie być jeszcze widoczne, a zatem saldo portfela może być nieprawidłowe. Te detale będą poprawne, gdy portfel zakończy synchronizację z siecią bitcoin, zgodnie z poniższym opisem. + + Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network. + Próba wydania bitcoinów które nie są jeszcze wyświetlone jako transakcja zostanie odrzucona przez sieć. + Number of blocks left Pozostało bloków @@ -1688,6 +1692,10 @@ Type <b>help</b> for an overview of available commands. Wpisz <b>help</b> aby uzyskać listę dostępnych komend + + Network activity disabled + Aktywność sieciowa wyłączona + %1 B %1 B @@ -1870,7 +1878,11 @@ Message Wiadomość - + + Error encoding URI into QR Code. + Błąd kodowania URI w kod QR + + RecentRequestsTableModel @@ -2120,6 +2132,14 @@ Transaction creation failed! Utworzenie transakcji nie powiodło się! + + The transaction was rejected with the following reason: %1 + Transakcja została odrzucona z następującym powodem: %1 + + + A fee higher than %1 is considered an absurdly high fee. + Opłata wyższa niż %1 jest uznawana za absurdalnie dużą. + Payment request expired. Żądanie płatności upłynęło. @@ -3278,6 +3298,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Set key pool size to <n> (default: %u) Ustaw rozmiar puli kluczy na <n> (domyślnie: %u) + + Set maximum BIP141 block weight (default: %d) + ustawienie maksymalnego rozmiaru bloku BIP141 (domyślnie: %d) + Set the number of threads to service RPC calls (default: %d) Ustaw liczbę wątków do obsługi RPC (domyślnie: %d) @@ -3298,6 +3322,18 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Spend unconfirmed change when sending transactions (default: %u) Wydawaj niepotwierdzoną resztę podczas wysyłania transakcji (domyślnie: %u) + + The wallet will avoid paying less than the minimum relay fee. + Portfel będzie unikał płacenia mniejszej niż przekazana opłaty. + + + This is the minimum transaction fee you pay on every transaction. + Minimalna opłata transakcyjna którą płacisz przy każdej transakcji. + + + This is the transaction fee you will pay if you send a transaction. + To jest opłata transakcyjna którą zapłacisz jeśli wyślesz transakcję. + Threshold for disconnecting misbehaving peers (default: %u) Próg, po którym nastąpi rozłączenie węzłów nietrzymających się zasad (domyślnie: %u) diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 59724318bbf8..7ec31194b056 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -3,7 +3,7 @@ AddressBookPage Right-click to edit address or label - Clique com o botão direito para editar o endereço ou rótulo + Clique com o botão direito para editar o endereço ou rótulocabeça Create a new address @@ -327,7 +327,7 @@ Syncing Headers (%1%)... - Sincronizando cabeçahos (%1%)... + Sincronizando cabeçalhos (%1%)... Reindexing blocks on disk... @@ -923,7 +923,7 @@ Unknown. Syncing Headers (%1)... - Desconhecido. Sincroniando cabeçahos (%1)... + Desconhecido. Sincronizando cabeçalhos (%1)... diff --git a/src/qt/locale/bitcoin_si.ts b/src/qt/locale/bitcoin_si.ts new file mode 100644 index 000000000000..3202c3614c9e --- /dev/null +++ b/src/qt/locale/bitcoin_si.ts @@ -0,0 +1,319 @@ + + + AddressBookPage + + Create a new address + නව ලිපිනයක් සාදන්න + + + Choose the address to send coins to + කාසි යැවිය යුතු ලිපිනය තෝරන්න + + + Choose the address to receive coins with + කාසි ලැබිය යුතු ලිපිනය තෝරන්න + + + Sending addresses + යවන ලිපින + + + Receiving addresses + ලබන ලිපින + + + + AddressTableModel + + Label + ලේබලය + + + Address + ලිපිනය + + + (no label) + (ලේබලයක් නැත) + + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Warning + අවවාදය + + + Information + තොරතුර + + + + CoinControlDialog + + Quantity: + ප්‍රමාණය: + + + Bytes: + බයිට්ස්: + + + Amount: + අගය: + + + Fee: + ගාස්තුව: + + + Amount + අගය + + + Date + දිනය + + + yes + ඔව් + + + no + නැත + + + (no label) + (ලේබලයක් නැත) + + + (change) + (වෙනස) + + + + EditAddressDialog + + + FreespaceChecker + + name + නම + + + + HelpMessageDialog + + + Intro + + Welcome + ආයුබෝවන් + + + + ModalOverlay + + calculating... + ගණනනය කරමින්... + + + + OpenURIDialog + + URI: + URI: + + + + OptionsDialog + + MB + MB + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + Amount + අගය + + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Address + ලිපිනය + + + Amount + අගය + + + Label + ලේබලය + + + + RecentRequestsTableModel + + Date + දිනය + + + Label + ලේබලය + + + (no label) + (ලේබලයක් නැත) + + + + SendCoinsDialog + + Quantity: + ප්‍රමාණය: + + + Bytes: + බයිට්ස්: + + + Amount: + අගය: + + + Fee: + ගාස්තුව: + + + (no label) + (ලේබලයක් නැත) + + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + Date + දිනය + + + Amount + අගය + + + + TransactionDescDialog + + + TransactionTableModel + + Date + දිනය + + + Label + ලේබලය + + + (no label) + (ලේබලයක් නැත) + + + + TransactionView + + Date + දිනය + + + Label + ලේබලය + + + Address + ලිපිනය + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Information + තොරතුර + + + Warning + අවවාදය + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_sr@latin.ts b/src/qt/locale/bitcoin_sr@latin.ts index 2cfb95fb2173..9e539a68cac2 100644 --- a/src/qt/locale/bitcoin_sr@latin.ts +++ b/src/qt/locale/bitcoin_sr@latin.ts @@ -41,6 +41,38 @@ &Delete &Izbrisati + + Choose the address to send coins to + Izaberite adresu za slanje novčića + + + Choose the address to receive coins with + Izaberite adresu za prijem novčića + + + Sending addresses + Adresa na koju se šalje + + + Receiving addresses + Adresa na koju se prima + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Ovo su Vaše Bitcoin adrese na koju se vrše uplate. Uvek proverite iznos i prijemnu adresu pre slanja novčića + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Ovo su Vaše Bitcoin adrese za primanje uplata. Preporučuje se upotreba nove adrese za svaku transakciju. + + + Copy &Label + Kopiranje &Oznaka + + + &Edit + &Izmena + AddressTableModel @@ -137,6 +169,14 @@ Quit application Isključi aplikaciju + + &About %1 + &Otprilike %1 + + + Show information about %1 + Prikaži informacije za otprilike %1 + &Options... &Opcije... diff --git a/src/qt/locale/bitcoin_te.ts b/src/qt/locale/bitcoin_te.ts new file mode 100644 index 000000000000..290d72a599de --- /dev/null +++ b/src/qt/locale/bitcoin_te.ts @@ -0,0 +1,279 @@ + + + AddressBookPage + + Right-click to edit address or label + చిరునామా లేదా లేబుల్ సవరించడానికి రైట్-క్లిక్ చేయండి + + + Create a new address + క్రొత్త చిరునామా సృష్టించండి + + + &New + &క్రొత్త + + + Copy the currently selected address to the system clipboard + ప్రస్తుతం ఎంచుకున్న చిరునామాను సిస్టం క్లిప్ బోర్డుకు కాపీ చేయండి + + + &Copy + &కాపి + + + C&lose + C&కోల్పోవు + + + Delete the currently selected address from the list + ప్రస్తుతం ఎంచుకున్న చిరునామా ను జాబితా నుండి తీసివేయండి + + + 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. + ఇవి మీరు అందుకునే చెల్లింపుల బిట్‌కాయిన్ చిరునామాలు. ప్రతీ లావాదేవీకి క్రొత్త అందుకునే చిరునామా వాడటం మంచిది. + + + Export Address List + చిరునామా జాబితాను ఎగుమతి చేయండి + + + Exporting Failed + ఎగుమతి విఫలమయ్యింది + + + + AddressTableModel + + Label + ఉల్లాకు + + + + AskPassphraseDialog + + Passphrase Dialog + సంకేతపదము డైలాగ్ + + + Enter passphrase + సంకేతపదము చేర్చండి + + + New passphrase + క్రొత్త సంకేతపదము + + + 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>పది లేదా ఎక్కువ యాదృచ్ఛిక అక్షరాలు</b>, లేక <b>ఎనిమిది కంటే ఎక్కువ పదాలు</b> కలిగి ఉన్న సంకేతపదము దయచేసి వాడండి. + + + 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 + జోలె సంకేతపరబడింది + + + Wallet encryption failed + జోలె సంకేతపరచడం విఫలమయ్యింది + + + + BanTableModel + + + BitcoinGUI + + Error + లోపం + + + Warning + హెచ్చరిక + + + Information + వర్తమానము + + + Up to date + తాజాగా ఉంది + + + Connecting to peers... + తోటివాళ్లతో అనుసంధానం కుదురుస్తుంది + + + + CoinControlDialog + + Coin Selection + నాణెం ఎంపిక + + + Quantity: + పరిమాణం + + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + Error + లోపం + + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Label + ఉల్లాకు + + + + RecentRequestsTableModel + + Label + ఉల్లాకు + + + + SendCoinsDialog + + Quantity: + పరిమాణం + + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + Label + ఉల్లాకు + + + + TransactionView + + Label + ఉల్లాకు + + + Exporting Failed + ఎగుమతి విఫలమయ్యింది + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Information + వర్తమానము + + + Warning + హెచ్చరిక + + + Error + లోపం + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_th.ts b/src/qt/locale/bitcoin_th.ts new file mode 100644 index 000000000000..a83f8312a09c --- /dev/null +++ b/src/qt/locale/bitcoin_th.ts @@ -0,0 +1,203 @@ + + + AddressBookPage + + Right-click to edit address or label + คลิกขวาเพื่อแก้ไขที่อยู่หรือชื่อ + + + Create a new address + สร้างที่อยู่ใหม่ + + + &New + ใหม่ + + + &Copy + คัดลอก + + + C&lose + ปิด + + + &Export + ส่งออก + + + &Delete + ลบ + + + Choose the address to send coins to + เลือกที่อยู่ที่จะส่งเหรียญ + + + Choose the address to receive coins with + เลือกที่อยู่ที่จะรับเหรียญ + + + C&hoose + เลือก + + + Sending addresses + ที่อยู่ในการส่ง + + + Receiving addresses + ที่อยู่ในการรับ + + + &Copy Address + คัดลอกที่อยู่ + + + Copy &Label + คัดลอกชื่อ + + + &Edit + แก้ไข + + + Exporting Failed + การส่งออกล้มเหลว + + + + AddressTableModel + + Address + ที่อยู่ + + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + + CoinControlDialog + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + ModalOverlay + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QObject::QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Address + ที่อยู่ + + + + RecentRequestsTableModel + + + SendCoinsDialog + + + SendCoinsEntry + + + SendConfirmationDialog + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + + TransactionView + + Address + ที่อยู่ + + + Exporting Failed + การส่งออกล้มเหลว + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + ส่งออก + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_tr_TR.ts b/src/qt/locale/bitcoin_tr_TR.ts index c4e4d2983e1c..0a50a38dbff7 100644 --- a/src/qt/locale/bitcoin_tr_TR.ts +++ b/src/qt/locale/bitcoin_tr_TR.ts @@ -41,22 +41,114 @@ &Delete &Sil + + Choose the address to send coins to + koinlerin gönderileceği adresi seçin + + + C&hoose + Seçim + + + Sending addresses + Gönderilen Adresler + + + Receiving addresses + Alınan Adresler + + + &Edit + Düzenle + + + Export Address List + Adres Listesini Dışar Aktar + + + Exporting Failed + Dışa Aktarma Başarısız + AddressTableModel + + Label + etiket + + + Address + adres + AskPassphraseDialog + + Encrypt wallet + Cüzdanı Şifrele + + + This operation needs your wallet passphrase to unlock the wallet. + Bu işlem, cüzdan kilidinizi açmak için parolanıza ihtiyaç duyuyor + + + Unlock wallet + Cüzdanı Kilitle + + + Decrypt wallet + Cüzdanın Şifresini Çöz + + + Confirm wallet encryption + Cüzdan Şifrelemesini Onaylayın + + + Are you sure you wish to encrypt your wallet? + Cüzdanınızı şifrelemek istediğinizden emin misiniz? + + + Wallet encrypted + Cüzdan Şifrelendi + + + Wallet unlock failed + Cüzdan Kilidi Açma Hatası + BanTableModel BitcoinGUI + + E&xit + Çıkış + + + &About %1 + Hakkında%1 + &Receiving addresses... Alış adresleri + + Network activity disabled. + Ağ etkinliği devre dışı. + + + Error + Hata + + + Warning + Uyarı + + + Information + Bilgi + CoinControlDialog @@ -80,6 +172,10 @@ Intro + + Error + Hata + ModalOverlay @@ -120,9 +216,21 @@ Copy &Address &Adresi Kopyala + + Address + adres + + + Label + etiket + RecentRequestsTableModel + + Label + etiket + SendCoinsDialog @@ -153,9 +261,25 @@ TransactionTableModel + + Label + etiket + TransactionView + + Label + etiket + + + Address + adres + + + Exporting Failed + Dışa Aktarma Başarısız + UnitDisplayStatusBarControl @@ -171,5 +295,65 @@ bitcoin-core - + + Print this help message and exit + Bu yardım mesajını yazdır ve çıkış yap + + + Print version and exit + Versiyonu yazdır ve çıkış yap + + + Verifying blocks... + Bloklar Onaylanıyor... + + + Verifying wallet... + Cüzdan Onaylanıyor... + + + Wallet options: + Cüzdan Ayarları + + + Information + Bilgi + + + RPC server options: + RPC sunucu ayarları + + + Transaction too large + İşlem çok büyük + + + Warning + Uyarı + + + Loading addresses... + Adresler bekleniyor... + + + Insufficient funds + Yetersiz Bakiye + + + Loading wallet... + Cüzdan Bekleniyor... + + + Cannot write default address + Varsayılan adres yazılamıyor + + + Rescanning... + Tekrar taranıyor... + + + Error + Hata + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 77d32402d3cf..2094d67dd8a2 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -2066,6 +2066,10 @@ Dust: 小额: + + Confirmation time target: + 确认时间目标: + Clear &All 清除所有(&A) From 0a6af47ffabbeee29fec5b5d71eaff43a08969da Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 23 Aug 2017 10:10:14 -0400 Subject: [PATCH 015/196] [doc] build-windows: Mention that only trusty works Github-Pull: #11119 Rebased-From: fa14b6797088065f890b33c1a2c7f6ee4af20c6c Tree-SHA512: a790a5d37a06a691f2536763a504ead5b06b94708ba07f3b94bedbb76b0201825be3dcd95343512d7a6211089be2abc3f1e0957ed27055426e6943d4bdb6fbd9 --- doc/build-windows.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/build-windows.md b/doc/build-windows.md index 9549a4b9da04..ca1a05dfb45d 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -6,6 +6,9 @@ Below are some notes on how to build Bitcoin Core for Windows. Most developers use cross-compilation from Ubuntu to build executables for Windows. This is also used to build the release binaries. +Currently only building on Ubuntu Trusty 14.04 is supported. +Other versions are unsupported or known to be broken (e.g. Ubuntu Xenial 16.04). + While there are potentially a number of ways to build on Windows (for example using msys / mingw-w64), using the Windows Subsystem For Linux is the most straightforward. If you are building with another method, please contribute the instructions here for others who are running versions From e51bb71e4a5657f1ea7a046aefe1f24f6674f6ad Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 25 Aug 2017 14:46:07 -0500 Subject: [PATCH 016/196] Fix rounding errors in calculation of minimum change size Github-Pull: #11145 Rebased-From: a54c7b94f8825e9b52fec9066fe7c1d5b6f53482 Tree-SHA512: d9abb9794edbf7e52450c63d183a4f28e9a3621a670b7f21af92407be096363b44a356818f2abbea11c168d123c04852bd0b60f1cd9d423aefbf4ae831f8567d --- src/wallet/wallet.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 680c5ed9b37a..142e04c7c830 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2852,13 +2852,15 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // new inputs. We now know we only need the smaller fee // (because of reduced tx size) and so we should add a // change output. Only try this once. - CAmount fee_needed_for_change = GetMinimumFee(change_prototype_size, coin_control, ::mempool, ::feeEstimator, nullptr); - CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate); - CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change; - if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) { - pick_new_inputs = false; - nFeeRet = nFeeNeeded + fee_needed_for_change; - continue; + if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) { + unsigned int tx_size_with_change = nBytes + change_prototype_size + 2; // Add 2 as a buffer in case increasing # of outputs changes compact size + CAmount fee_needed_with_change = GetMinimumFee(tx_size_with_change, coin_control, ::mempool, ::feeEstimator, nullptr); + CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate); + if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) { + pick_new_inputs = false; + nFeeRet = fee_needed_with_change; + continue; + } } // If we have change output already, just increase it From 5b059a833eb57a4dd8458f42aedba85265b2bbf3 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 25 Aug 2017 14:49:44 -0500 Subject: [PATCH 017/196] Output a bit more information for fee calculation report. Github-Pull: #11145 Rebased-From: 6af49dddeaeec7f134e86d6f8cf839c55870b7ab Tree-SHA512: 7245c6f7ed81cf3913e351ff1df7f74f4be7abe0ae8be312e4862c9875e2943b0b11136bc9999191cdf03468fdac5d41e294bb59b657605c22643b102e37c070 --- src/wallet/wallet.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 142e04c7c830..318c159cfb23 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2670,6 +2670,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); assert(txNew.nLockTime < LOCKTIME_THRESHOLD); FeeCalculation feeCalc; + CAmount nFeeNeeded; unsigned int nBytes; { std::set setCoins; @@ -2831,7 +2832,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT vin.scriptWitness.SetNull(); } - CAmount nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc); + nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc); // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. @@ -2955,8 +2956,8 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT } } - LogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", - nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, + LogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", + nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, feeCalc.est.pass.start, feeCalc.est.pass.end, 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool), feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool, From e8ad101e5b104ca913beb82a77f5b3bfa1a7c5f6 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 22 Aug 2017 13:32:17 -0400 Subject: [PATCH 018/196] Changing -txindex requires -reindex, not -reindex-chainstate Github-Pull: #11108 Rebased-From: cd0ea487422028bec1f5df62ab4c57909c2bcc90 Tree-SHA512: 0fbd50b1343eec14301ee9c2fc76e48dcb1610ce1ddbf3cccbd937e2c0d1bbdfc4920fbc05e7e560c424e0ed7367d6ad3595a1bd38dea669bcbd1c838f522d8e --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index d79c2967b97e..a708295f43e6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1428,7 +1428,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Check for changed -txindex state if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex"); + strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); break; } From 29a3cb237802a6f240def54cbc74cb2d5375683a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 28 Aug 2017 08:27:19 +0000 Subject: [PATCH 019/196] qt: Translation update pre-rc3 Tree-SHA512: d813ef923d804722bc161cc62e09ee003b386c0abf2d513ede671e9f14ac4c3df749a9f23ddcba9400fcc335dbef6540e47a212dca8ddc0a3d73aee01f098754 --- src/qt/bitcoinstrings.cpp | 3 +- src/qt/locale/bitcoin_en.ts | 32 ++-- src/qt/locale/bitcoin_es_ES.ts | 94 ++++++++++- src/qt/locale/bitcoin_he.ts | 4 + src/qt/locale/bitcoin_lt.ts | 22 +++ src/qt/locale/bitcoin_lv_LV.ts | 108 +++++++++++- src/qt/locale/bitcoin_ms_MY.ts | 80 +++++++++ src/qt/locale/bitcoin_nl.ts | 6 +- src/qt/locale/bitcoin_pl.ts | 292 ++++++++++++++++++++++++++++++++- src/qt/locale/bitcoin_pt_BR.ts | 12 +- src/qt/locale/bitcoin_sv.ts | 4 + 11 files changed, 619 insertions(+), 38 deletions(-) diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 9f798ccf6238..533572819b8f 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -250,8 +250,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "" "You need to rebuild the database using -reindex to go back to unpruned " "mode. This will redownload the entire blockchain"), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"You need to rebuild the database using -reindex-chainstate to change -txindex"), QT_TRANSLATE_NOOP("bitcoin-core", "%d of last 100 blocks have unexpected version"), QT_TRANSLATE_NOOP("bitcoin-core", "%s corrupt, salvage failed"), QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"), @@ -416,6 +414,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Wallet options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: unknown new rules activated (versionbit %i)"), QT_TRANSLATE_NOOP("bitcoin-core", "Whether to operate in a blocks only mode (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"), QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."), QT_TRANSLATE_NOOP("bitcoin-core", "ZeroMQ notification options:"), }; diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 821be8987e00..89050ee6b582 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -3990,7 +3990,7 @@ bitcoin-core - + Options: Options: @@ -4015,7 +4015,7 @@ Accept command line and JSON-RPC commands - + Distributed under the MIT software license, see the accompanying file %s or %s @@ -4040,7 +4040,7 @@ - + Error: A fatal internal error occurred, see debug.log for details @@ -4065,7 +4065,7 @@ - + Bitcoin Core Bitcoin Core @@ -4221,11 +4221,6 @@ - You need to rebuild the database using -reindex-chainstate to change -txindex - - - - %d of last 100 blocks have unexpected version @@ -4580,7 +4575,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 @@ -4655,7 +4650,7 @@ - + (default: %u) @@ -4839,6 +4834,11 @@ Whether to operate in a blocks only mode (default: %u) + + + You need to rebuild the database using -reindex to change -txindex + + Zapping all transactions from wallet... @@ -4850,22 +4850,22 @@ - + Password for JSON-RPC connections 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 - + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) @@ -5000,7 +5000,7 @@ - + %s is set very high! diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts index e0ddf7d530f1..1413cc1adf58 100644 --- a/src/qt/locale/bitcoin_es_ES.ts +++ b/src/qt/locale/bitcoin_es_ES.ts @@ -63,11 +63,11 @@ 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. + Estas son sus direcciones Bitcoin para enviar pagos. Verifique siempre la cantidad y la dirección de recepción 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 + Estas son sus direcciones Bitcoin para recibir pagos. Se recomienda utilizar una nueva dirección de recepción para cada transacción &Copy Address @@ -531,6 +531,14 @@ Incoming transaction Transacción entrante + + HD key generation is <b>enabled</b> + La generación de claves HD está <b>activada</b> + + + HD key generation is <b>disabled</b> + La generación de claves HD está <b>desactivada</b> + Wallet is <b>encrypted</b> and currently <b>unlocked</b> El monedero está <b>cifrado</b> y actualmente <b>desbloqueado</b> @@ -719,7 +727,7 @@ New receiving address - Nueva dirección de recivimiento + Nueva dirección de recepción New sending address @@ -727,7 +735,7 @@ Edit receiving address - Editar dirección de recivimiento + Editar dirección de recepción Edit sending address @@ -877,6 +885,10 @@ Form Formulario + + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. + Las transacciones recientes podrían no ser visibles todavía, por lo que el balance de la cartera podría ser incorrecto. Esta información será correcta una vez su cartera se haya terminado de sincronizar con la red bitcoin, como se detalla más abajo. + Number of blocks left Número de bloques restantes @@ -1395,6 +1407,26 @@ %1 ms %1 ms + + %n second(s) + %n segundo%n segundos + + + %n minute(s) + %n minuto%n minutos + + + %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 @@ -1410,7 +1442,15 @@ Error: Specified data directory "%1" does not exist. Error: directorio especificado "%1" no existe. - + + Error: Cannot parse configuration file: %1. Only use key=value syntax. + Error: no se puede interpretar el archivo de configuración: %1. Utilize exclusivamente sintaxis clave=valor. + + + Error: %1 + Error: %1 + + QRImageWidget @@ -1588,6 +1628,10 @@ Ping Wait Espera de Ping + + Min Ping + Ping mín. + Time Offset Desplazamiento de tiempo @@ -1648,6 +1692,14 @@ 1 &year 1 &año + + &Disconnect + &Desconectar + + + &Unban + &Desbanear + Welcome to the %1 RPC console. Bienvenido a la consola RPC %1. @@ -1660,6 +1712,14 @@ Type <b>help</b> for an overview of available commands. Escriba <b>help</b> para ver un resumen de los comandos disponibles. + + WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command. + ADVERTENCIA: algunos estafadores han estado pidiendo a los usuarios que escriban comandos aquí, robando el contenido de sus carteras. No use esta consola sin entender completamente las ramificaciones del comando. + + + Network activity disabled + Actividad de red desactivada + %1 B %1 B @@ -2104,6 +2164,10 @@ Transaction creation failed! ¡Falló la creación de transacción! + + The transaction was rejected with the following reason: %1 + Esta transacción fue rechazada por la siguiente razón: %1 + A fee higher than %1 is considered an absurdly high fee. Una couta mayor que %1 se considera una cuota irracionalmente alta. @@ -2112,6 +2176,10 @@ Payment request expired. Solicitud de pago caducada. + + %n block(s) + %n bloque%n bloques + Pay only the required fee of %1 Pagar únicamente la cuota solicitada de %1 @@ -2124,6 +2192,14 @@ Warning: Unknown change address Alerta: dirección cambiada desconocida + + Confirm custom change address + Confirmar dirección de cambio personalizada + + + The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure? + La dirección que seleccionó para el cambio no es parte de esta cartera. Parte o la totalidad de los fondos de su cartera podrían ser enviados a esta dirección. ¿Está seguro? + (no label) (sin etiqueta) @@ -2385,6 +2461,10 @@ TransactionDesc + + Open for %n more block(s) + Abierto para %n bloque másAbierto para %n bloques más + Open until %1 Abierto hasta %1 @@ -3658,6 +3738,10 @@ Threshold for disconnecting misbehaving peers (default: %u) Umbral para la desconexión de pares con mal comportamiento (predeterminado: %u) + + Transaction amounts must not be negative + Las cantidades de las transacciones no pueden ser negativas. + Unknown network specified in -onlynet: '%s' La red especificada en -onlynet '%s' es desconocida diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 82be81e9219c..c1a66af5c2d2 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -1003,6 +1003,10 @@ Map port using &UPnP מיפוי פתחה באמצעות UPnP + + Connect to the Bitcoin network through a SOCKS5 proxy. + התחבר לרשת הביטקוין דרך פרוקסי SOCKS5. + Proxy &IP: כתובת ה־IP של המ&תווך: diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 67fee9ae42d5..54afafac2c34 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -44,6 +44,10 @@ AddressTableModel + + Address + Adresas + AskPassphraseDialog @@ -113,6 +117,10 @@ &About %1 &Apie %1 + + Show information about %1 + Rodyti informaciją apie %1 + About &Qt Apie &Qt @@ -245,6 +253,12 @@ Catching up... Vejamasi... + + Date: %1 + + Data: %1 + + Sent transaction Sandoris nusiųstas @@ -716,6 +730,10 @@ Copy &Address &Kopijuoti adresą + + Address + Adresas + RecentRequestsTableModel @@ -900,6 +918,10 @@ TransactionView + + Address + Adresas + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index 2953da443ab5..44038b949767 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -37,10 +37,46 @@ &Delete &Dzēst + + Choose the address to send coins to + Izvēlies adresi uz kuru sūtīt bitcoins + + + Choose the address to receive coins with + Izvēlies adresi ar kuru saņemt bitcoins + + + &Copy Address + &Kopēt adresi + + + &Edit + &Rediģēt + + + Export Address List + Eksportēt Adrešu Sarakstu + + + Exporting Failed + Eksportēšana Neizdevās + AddressTableModel - + + Label + Nosaukums + + + Address + Adrese + + + (no label) + (bez nosaukuma) + + AskPassphraseDialog @@ -59,6 +95,30 @@ Repeat new passphrase Jaunā parole vēlreiz + + Encrypt wallet + Šifrēt maciņu + + + Unlock wallet + Atslēgt maciņu + + + Decrypt wallet + Atšifrēt maciņu + + + Confirm wallet encryption + Apstiprināt maciņa šifrēšanu + + + Are you sure you wish to encrypt your wallet? + Vai tu tiešām vēlies šifrēt savu maciņu? + + + Wallet encryption failed + Maciņa šifrēšana neizdevās + BanTableModel @@ -328,6 +388,10 @@ Confirmed Apstiprināts + + (no label) + (bez nosaukuma) + EditAddressDialog @@ -840,9 +904,25 @@ &Save Image... &Saglabāt Attēlu... + + Address + Adrese + + + Label + Nosaukums + RecentRequestsTableModel + + Label + Nosaukums + + + (no label) + (bez nosaukuma) + SendCoinsDialog @@ -926,7 +1006,11 @@ S&end &Sūtīt - + + (no label) + (bez nosaukuma) + + SendCoinsEntry @@ -1081,9 +1165,29 @@ TransactionTableModel + + Label + Nosaukums + + + (no label) + (bez nosaukuma) + TransactionView + + Label + Nosaukums + + + Address + Adrese + + + Exporting Failed + Eksportēšana Neizdevās + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_ms_MY.ts b/src/qt/locale/bitcoin_ms_MY.ts index 7844093e3bb6..e4ac41730591 100644 --- a/src/qt/locale/bitcoin_ms_MY.ts +++ b/src/qt/locale/bitcoin_ms_MY.ts @@ -318,6 +318,22 @@ Alihkan fail data ke dalam tab semasa Open &URI... Buka &URI... + + Click to disable network activity. + Tekan untuk lumpuhkan rangkaian + + + Network activity disabled. + Aktiviti rangkaian dilumpuhkan + + + Click to enable network activity again. + Tekan untuk mengaktifkan rangkain semula + + + Syncing Headers (%1%)... + Penyelarasn tajuk (%1%)... + Reindexing blocks on disk... Reindexi blok pada cakera... @@ -330,6 +346,70 @@ Alihkan fail data ke dalam tab semasa Backup wallet to another location Wallet sandaran ke lokasi lain + + Change the passphrase used for wallet encryption + Tukar kata laluan untuk dompet disulitkan + + + &Debug window + Tetingkap Debug + + + Open debugging and diagnostic console + buka debug dan konsol diagnostik + + + &Verify message... + sahkan mesej + + + Bitcoin + Bitcoin + + + Wallet + dompet + + + &Send + hantar + + + &Receive + terima + + + &Show / Hide + &tunjuk/sembunyi + + + Show or hide the main Window + tunjuk atau sembunyi tetingkap utama + + + Encrypt the private keys that belong to your wallet + sulitkan kata laluan milik peribadi anda + + + Sign messages with your Bitcoin addresses to prove you own them + Log mesej dengan alamat Bitcoin anda untuk membuktikan anda memilikinya + + + Verify messages to ensure they were signed with specified Bitcoin addresses + Sahkan mesej untuk memastikan mereka telah ditandatangani dengan alamat Bitcoin yang ditentukan + + + &File + fail + + + &Settings + tetapan + + + &Help + tolong + CoinControlDialog diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index e523e832810d..c8b0d17593fb 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -311,7 +311,7 @@ &Receiving addresses... - &Ontvang adressen... + &Ontvangstadressen... Open &URI... @@ -423,7 +423,7 @@ Show the list of used receiving addresses and labels - Toon de lijst met gebruikte ontvangst adressen en labels + Toon de lijst met gebruikte ontvangstadressen en labels Open a bitcoin: URI or payment request @@ -1809,7 +1809,7 @@ An optional label to associate with the new receiving address. - Een optioneel label om te associëren met het nieuwe ontvangende adres + Een optioneel label om te associëren met het nieuwe ontvangstadres Use this form to request payments. All fields are <b>optional</b>. diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index c7355e626f6d..d4650ffcf5bf 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -1305,6 +1305,10 @@ Refund from %1 Zwrot z %1 + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Żądanie płatności %1 jest zbyt duże (%2 bajtów, dozwolone %3 bajtów). + Error communicating with %1: %2 Błąd komunikacji z %1 : %2 @@ -1422,6 +1426,10 @@ Error: Specified data directory "%1" does not exist. Błąd: Określony folder danych "%1" nie istnieje. + + Error: Cannot parse configuration file: %1. Only use key=value syntax. + Błąd: Nie można przetworzyć pliku konfiguracyjnego: %1. Używaj tylko składni klucz=wartość. + Error: %1 Błąd: %1 @@ -1692,6 +1700,10 @@ Type <b>help</b> for an overview of available commands. Wpisz <b>help</b> aby uzyskać listę dostępnych komend + + WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command. + UWAGA: Oszuści nakłaniają do wpisywania tutaj różnych poleceń aby ukraść portfel. Nie używaj tej konsoli bez pełnego zrozumienia wpisywanych poleceń. + Network activity disabled Aktywność sieciowa wyłączona @@ -1878,6 +1890,10 @@ Message Wiadomość + + Resulting URI too long, try to reduce the text for label / message. + Wynikowy URI jest zbyt długi, spróbuj zmniejszyć tekst etykiety / wiadomości + Error encoding URI into QR Code. Błąd kodowania URI w kod QR @@ -2144,10 +2160,18 @@ Payment request expired. Żądanie płatności upłynęło. + + %n block(s) + %n blok%n bloków%n bloków%n bloków + Pay only the required fee of %1 Zapłać tylko wymaganą opłatę w wysokości %1 + + Estimated to begin confirmation within %n block(s). + Przybliżony czas zatwierdzenia: %n blok.Przybliżony czas zatwierdzenia: %n bloki.Przybliżony czas zatwierdzenia: %n bloków.Przybliżony czas zatwierdzenia: %n bloków. + Warning: Invalid Bitcoin address Ostrzeżenie: nieprawidłowy adres Bitcoin @@ -2156,6 +2180,10 @@ Warning: Unknown change address Ostrzeżenie: Nieznany adres reszty + + Confirm custom change address + Potwierdź zmianę adresu własnego + (no label) (brak etykiety) @@ -2239,7 +2267,11 @@ Memo: Notatka: - + + Enter a label for this address to add it to your address book + Wprowadź etykietę dla tego adresu by dodać go do książki adresowej + + SendConfirmationDialog @@ -2345,6 +2377,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Reset all verify message fields Resetuje wszystkie pola weryfikacji wiadomości + + Click "Sign Message" to generate signature + Kliknij "Podpisz Wiadomość" żeby uzyskać podpis + The entered address is invalid. Podany adres jest nieprawidłowy. @@ -2353,6 +2389,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Please check the address and try again. Proszę sprawdzić adres i spróbować ponownie. + + The entered address does not refer to a key. + Wprowadzony adres nie odnosi się do klucza. + Wallet unlock was cancelled. Odblokowanie portfela zostało anulowane. @@ -2369,6 +2409,22 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Message signed. Wiadomość podpisana. + + The signature could not be decoded. + Podpis nie może zostać zdekodowany. + + + Please check the signature and try again. + Sprawdź podpis i spróbuj ponownie. + + + The signature did not match the message digest. + Podpis nie odpowiada skrótowi wiadomości. + + + Message verification failed. + Weryfikacja wiadomości nie powiodła się. + Message verified. Wiadomość zweryfikowana. @@ -2390,10 +2446,54 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw TransactionDesc + + Open for %n more block(s) + Otwórz dla %n kolejnego blokuOtwórz dla %n kolejnych blokówOtwórz dla %n kolejnych blokówOtwórz dla %n kolejnych bloków + + + Open until %1 + Otwórz do %1 + + + conflicted with a transaction with %1 confirmations + sprzeczny z transakcją posiadającą %1 potwierdzeń + + + %1/offline + %1/offline + + + 0/unconfirmed, %1 + 0/niezatwierdzone, %1 + + + in memory pool + w obszarze pamięci + abandoned porzucone + + %1/unconfirmed + %1/niezatwierdzone + + + %1 confirmations + %1 potwierdzeń + + + Status + Status + + + , has not been successfully broadcast yet + , nie został jeszcze pomyślnie rozesłany + + + , broadcast through %n node(s) + , przekazywany przez %n węzęł, przekazywany przez %n węzy, przekazywany przez %n węzłów, przekazywany przez %n węzłów + Date Data @@ -2430,14 +2530,50 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw label etykieta + + Credit + Uznanie + + + not accepted + niezaakceptowane + + + Debit + Debet + Transaction fee Opłata transakcyjna + + Net amount + Kwota netto + Message Wiadomość + + Comment + Komentarz + + + Transaction ID + ID transakcji + + + Transaction total size + Rozmiar transakcji + + + Output index + Indeks wyjściowy + + + Debug information + Informacje debugowania + Transaction Transakcja @@ -2465,7 +2601,11 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw This pane shows a detailed description of the transaction Ten panel pokazuje szczegółowy opis transakcji - + + Details for %1 + Szczegóły %1 + + TransactionTableModel @@ -2480,6 +2620,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Label Etykieta + + Open for %n more block(s) + Otwórz dla %n kolejnego blokuOtwórz dla %n kolejnych blokówOtwórz dla %n kolejnych blokówOtwórz dla %n kolejnych bloków + + + Open until %1 + Otwórz do %1 + Offline Offline @@ -2492,26 +2640,70 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Abandoned Porzucone + + Confirming (%1 of %2 recommended confirmations) + Potwierdzanie (%1 z %2 rekomendowanych potwierdzeń) + + + Confirmed (%1 confirmations) + Zatwierdzony (%1 potwierdzeń) + Conflicted Skonfliktowane + + Immature (%1 confirmations, will be available after %2) + Niedojrzała (%1 potwierdzeń, będzie dostępna po %2) + + + This block was not received by any other nodes and will probably not be accepted! + Ten blok nie został odebrany przez jakikolwiek inny węzeł i prawdopodobnie nie zostanie zaakceptowany! + Generated but not accepted Wygenerowane ale nie zaakceptowane + + Received from + Odebrano od + Sent to Wysłane do + + Payment to yourself + Płatność do siebie + + + Mined + Wydobyto + watch-only tylko-obserwowany + + (n/a) + (brak) + (no label) (brak etykiety) + + Transaction status. Hover over this field to show number of confirmations. + Status transakcji. Najedź na pole, aby zobaczyć liczbę potwierdzeń. + + + Date and time that the transaction was received. + Data i czas odebrania transakcji. + + + Type of transaction. + Rodzaj transakcji. + TransactionView @@ -2547,6 +2739,26 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Sent to Wysłane do + + To yourself + Do siebie + + + Mined + Wydobyto + + + Other + Inne + + + Enter address or label to search + Wprowadź adres albo etykietę aby wyszukać + + + Abandon transaction + Porzuć transakcję + Copy address Kopiuj adres @@ -2563,14 +2775,34 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Copy transaction ID Skopiuj ID transakcji + + Copy raw transaction + Skopiuj surowe dane transakcji + + + Copy full transaction details + Skopiuj pełne informacje o transakcji + Edit label Zmień etykietę + + Show transaction details + Pokaż szczegóły transakcji + + + Export Transaction History + Eksport historii transakcji + Comma separated file (*.csv) Plik *.CSV (dane rozdzielane przecinkami) + + Confirmed + Potwierdzony + Date Data @@ -2587,10 +2819,22 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Address Adres + + ID + ID + Exporting Failed Eksportowanie nie powiodło się + + Exporting Successful + Eksport powiódł się + + + The transaction history was successfully saved to %1. + Historia transakcji została zapisana do %1. + Range: Zakres: @@ -2609,20 +2853,44 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw WalletFrame - + + No wallet has been loaded. + Nie załadowano żadnego portfela. + + WalletModel - + + Send Coins + Wyślij płatność + + WalletView + + &Export + &Eksportuj + + + Export the data in the current tab to a file + Eksportuj dane z aktywnej karty do pliku + Backup Wallet Kopia zapasowa portfela + + Wallet Data (*.dat) + Dane Portfela (*.dat) + Backup Failed Nie udało się wykonać kopii zapasowej + + There was an error trying to save the wallet data to %1. + Wystąpił błąd przy próbie zapisu pliku portfela do %1. + Backup Successful Wykonano kopię zapasową @@ -2654,6 +2922,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Accept command line and JSON-RPC commands Akceptuj linię poleceń oraz polecenia JSON-RPC + + Distributed under the MIT software license, see the accompanying file %s or %s + Rozprowadzane na licencji MIT, zobacz dołączony plik %s lub %s + If <category> is not supplied or if <category> = 1, output all debugging information. Jeżeli <category> nie zostanie określona lub <category> = 1, wyświetl wszystkie informacje debugowania. @@ -3210,6 +3482,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Support filtering of blocks and transaction with bloom filters (default: %u) Wspieraj filtrowanie bloków i transakcji używając Filtrów Blooma (domyślnie: %u) + + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. + Produkt zawiera oprogramowanie stworzone przez OpenSSL Project do użycia w OpensSSL Toolkit %s, oprogramowanie kryptograficzne napisane przez Eric Young oraz oprogramowanie UPnP napisane przez Thomas Bernard. + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. Całkowita długość łańcucha wersji (%i) przekracza maksymalną dopuszczalną długość (%i). Zmniejsz ilość lub rozmiar parametru uacomment. @@ -3294,6 +3570,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Relay non-P2SH multisig (default: %u) Przekazuj transakcje multisig inne niż P2SH (domyślnie: %u) + + Send transactions with full-RBF opt-in enabled (default: %u) + Wyślij transakcje z włączoną flagą full-RBF (domyślnie: %u) + Set key pool size to <n> (default: %u) Ustaw rozmiar puli kluczy na <n> (domyślnie: %u) @@ -3322,6 +3602,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Spend unconfirmed change when sending transactions (default: %u) Wydawaj niepotwierdzoną resztę podczas wysyłania transakcji (domyślnie: %u) + + Starting network threads... + Uruchamianie wątków sieciowych... + The wallet will avoid paying less than the minimum relay fee. Portfel będzie unikał płacenia mniejszej niż przekazana opłaty. diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 7ec31194b056..c0648b0da1df 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -3,11 +3,11 @@ AddressBookPage Right-click to edit address or label - Clique com o botão direito para editar o endereço ou rótulocabeça + Clique com o botão direito para editar o endereço ou rótulo Create a new address - Criar novo endereço + Criar um novo endereço &New @@ -3835,7 +3835,7 @@ Starting network threads... - Iniciando análise da rede... + Iniciando atividades da rede... The wallet will avoid paying less than the minimum relay fee. @@ -3855,11 +3855,11 @@ Transaction amounts must not be negative - As quantidades das transações devem ser positivas. + As quantidades das transações não podem serem negativas Transaction has too long of a mempool chain - A transação demorou muito na memória + A transação demorou muito para ser confirmada na mempool chain Transaction must have at least one recipient @@ -3879,7 +3879,7 @@ Add a node to connect to and attempt to keep the connection open - Adicionar um cliente para se conectar e tentar manter a conexão ativa + Adicionar um nódulo para se conectar e tentar manter a conexão ativa Loading wallet... diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index ac5426f1917d..2862d2feb4c0 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -1361,6 +1361,10 @@ Var vänlig och försök igen. Node/Service Nod/Tjänst + + NodeId + Nod-ID + Ping Ping From a461cf4e373b043ed37917d6b1dda4812278841e Mon Sep 17 00:00:00 2001 From: kallewoof Date: Tue, 29 Aug 2017 00:00:43 +0900 Subject: [PATCH 020/196] Update release-notes.md --- doc/release-notes.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 65f2cccc65cc..01670aa64c19 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -327,7 +327,6 @@ Thanks to everyone who directly contributed to this release: - John Newbery - Jonas Schnelli - Jorge Timón -- Kalle Alm - Karl-Johan Alm - kewde - KibbledJiveElkZoo From fad16a90b2c210f745b75cc72a20287b054644af Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 1 Sep 2017 15:14:20 +0200 Subject: [PATCH 021/196] doc: Add missing contributors to release notes Guido Vranken via commit 9fe1f6b --- doc/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index 01670aa64c19..5130c3e788c6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -312,6 +312,7 @@ Thanks to everyone who directly contributed to this release: - fanquake - Felix Weis - flack +- Guido Vranken - Greg Griffith - Gregory Maxwell - Gregory Sanders From 58f1e54cbfae6dab82d9192e3147c860f5a29c8c Mon Sep 17 00:00:00 2001 From: Janus Troelsen Date: Wed, 6 Sep 2017 12:30:44 +0200 Subject: [PATCH 022/196] Release Notes: Fix SHA256-with-SSE4 PR link --- doc/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 01670aa64c19..3d70077e48f1 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -86,7 +86,7 @@ Initial Block Download, startup, transaction and block validation much faster: this results in new block validation being 40-50% faster. - LevelDB has been upgraded to version 1.20 (See [PR 10544](https://github.com/bitcoin/bitcoin/pull/10544)). This version contains hardware acceleration for CRC on architectures supporting SSE 4.2. As a result, synchronization and block validation are now faster. -- SHA256 hashing has been optimized for architectures supporting SSE 4 (See [PR 10182](https://github.com/bitcoin/bitcoin/pull/10182)). SHA256 is around +- SHA256 hashing has been optimized for architectures supporting SSE 4 (See [PR 10821](https://github.com/bitcoin/bitcoin/pull/10821)). SHA256 is around 50% faster on supported hardware, which results in around 5% faster IBD and block validation. In version 0.15, SHA256 hardware optimization is disabled in release builds by default, but can be enabled by using `--enable-experimental-asm` when building. From d4c9d00e7e79958dea9586f927778dba2be8230a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 7 Sep 2017 23:51:12 +0200 Subject: [PATCH 023/196] doc: Add PRs list to release notes Tree-SHA512: 1dd5e19a2ece38002da1d4bcf017a0a1a3ab2dc8b31fe7b3e7ebc6fef58de4547abbff3fb6555496da1ecf1f9a0cc941f980b053a0376a776e8301de3834aac1 --- doc/release-notes.md | 473 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index 3d70077e48f1..dcaf971223b6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -279,6 +279,479 @@ Low-level RPC changes - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the fee. Previously returned RPC_MISC_ERROR. +0.15.0 Change log +================= + +### RPC and other APIs +- #9485 `61a640e` ZMQ example using python3 and asyncio (mcelrath) +- #9894 `0496e15` remove 'label' filter for rpc command help (instagibbs) +- #9853 `02bd6e9` Fix error codes from various RPCs (jnewbery) +- #9842 `598ef9c` Fix RPC failure testing (continuation of #9707) (jnewbery) +- #10038 `d34995a` Add mallocinfo mode to `getmemoryinfo` RPC (laanwj) +- #9500 `3568b30` [Qt][RPC] Autocomplete commands for 'help' command in debug console (achow101) +- #10056 `e6156a0` [zmq] Call va_end() on va_start()ed args (kallewoof) +- #10086 `7438cea` Trivial: move rpcserialversion into RPC option group (jlopp) +- #10150 `350b224` [rpc] Add logging rpc (jnewbery) +- #10208 `393160c` [wallet] Rescan abortability (kallewoof) +- #10143 `a987def` [net] Allow disconnectnode RPC to be called with node id (jnewbery) +- #10281 `0e8499c` doc: Add RPC interface guidelines (laanwj) +- #9733 `d4732f3` Add getchaintxstats RPC (sipa) +- #10310 `f4b15e2` [doc] Add hint about getmempoolentry to getrawmempool help (kallewoof) +- #8704 `96c850c` [RPC] Transaction details in getblock (achow101) +- #8952 `9390845` Add query options to listunspent RPC call (pedrobranco) +- #10413 `08ac35a` Fix docs (there's no rpc command setpaytxfee) (RHavar) +- #8384 `e317c0d` Add witness data output to TxInError messages (instagibbs) +- #9571 `4677151` RPC: getblockchaininfo returns BIP signaling statistics (pinheadmz) +- #10450 `ef2d062` Fix bumpfee rpc "errors" return value (ryanofsky) +- #10475 `39039b1` [RPC] getmempoolinfo mempoolminfee is a BTC/KB feerate (instagibbs) +- #10478 `296928e` rpc: Add listen address to incoming connections in `getpeerinfo` (laanwj) +- #10403 `08d0390` Fix importmulti failure to return rescan errors (ryanofsky) +- #9740 `9fec4da` Add friendly output to dumpwallet (aideca) +- #10426 `16f6c98` Replace bytes_serialized with bogosize (sipa) +- #10252 `980deaf` RPC/Mining: Restore API compatibility for prioritisetransaction (luke-jr) +- #9672 `46311e7` Opt-into-RBF for RPC & bitcoin-tx (luke-jr) +- #10481 `9c248e3` Decodehextx scripts sanity check (achow101) +- #10488 `fa1f106` Note that the prioritizetransaction dummy value is deprecated, and has no meaning (TheBlueMatt) +- #9738 `c94b89e` gettxoutproof() should return consistent result (jnewbery) +- #10191 `00350bd` [trivial] Rename unused RPC arguments 'dummy' (jnewbery) +- #10627 `b62b4c8` fixed listunspent rpc convert parameter (tnakagawa) +- #10412 `bef02fb` Improve wallet rescan API (ryanofsky) +- #10400 `1680ee0` [RPC] Add an uptime command that displays the amount of time (in seconds) bitcoind has been running (rvelhote) +- #10683 `d81bec7` rpc: Move the `generate` RPC call to rpcwallet (laanwj) +- #10710 `30bc0f6` REST/RPC example update (Mirobit) +- #10747 `9edda0c` [rpc] fix verbose argument for getblock in bitcoin-cli (jnewbery) +- #10589 `104f5f2` More economical fee estimates for RBF and RPC options to control (morcos) +- #10543 `b27b004` Change API to estimaterawfee (morcos) +- #10807 `afd2fca` getbalance example covers at least 6 confirms (instagibbs) +- #10707 `75b5643` Better API for estimatesmartfee RPC (morcos) +- #10784 `9e8d6a3` Do not allow users to get keys from keypool without reserving them (TheBlueMatt) +- #10857 `d445a2c` [RPC] Add a deprecation warning to getinfo's output (achow101) +- #10571 `adf170d` [RPC]Move transaction combining from signrawtransaction to new RPC (achow101) +- #10783 `041dad9` [RPC] Various rpc argument fixes (instagibbs) +- #9622 `6ef3c7e` [rpc] listsinceblock should include lost transactions when parameter is a reorg'd block (kallewoof) +- #10799 `8537187` Prevent user from specifying conflicting parameters to fundrawtx (TheBlueMatt) +- #10931 `0b11a07` Fix misleading "Method not found" multiwallet errors (ryanofsky) +- #10788 `f66c596` [RPC] Fix addwitnessaddress by replacing ismine with producesignature (achow101) +- #10999 `627c3c0` Fix amounts formatting in `decoderawtransaction` (laanwj) +- #11002 `4268426` [wallet] return correct error code from resendwallettransaction (jnewbery) +- #11029 `96a63a3` [RPC] trivial: gettxout no longer shows version of tx (FelixWeis) +- #11083 `6c2b008` Fix combinerawtransaction RPC help result section (jonasnick) +- #11027 `07164bb` [RPC] Only return hex field once in getrawtransaction (achow101) +- #10698 `5af6572` Be consistent in calling transactions "replaceable" for Opt-In RBF (TheBlueMatt) + +### Block and transaction handling +- #9801 `a8c5751` Removed redundant parameter from mempool.PrioritiseTransaction (gubatron) +- #9819 `1efc99c` Remove harmless read of unusued priority estimates (morcos) +- #9822 `b7547fa` Remove block file location upgrade code (benma) +- #9602 `30ff3a2` Remove coin age priority and free transactions - implementation (morcos) +- #9548 `47510ad` Remove min reasonable fee (morcos) +- #10249 `c73af54` Switch CCoinsMap from boost to std unordered_map (sipa) +- #9966 `2a183de` Control mempool persistence using a command line parameter (jnewbery) +- #10199 `318ea50` Better fee estimates (morcos) +- #10196 `bee3529` Bugfix: PrioritiseTransaction updates the mempool tx counter (sdaftuar) +- #10195 `1088b02` Switch chainstate db and cache to per-txout model (sipa) +- #10284 `c2ab38b` Always log debug information for fee calculation in CreateTransaction (morcos) +- #10503 `efbcf2b` Use REJECT_DUPLICATE for already known and conflicted txn (sipa) +- #10537 `b3eb0d6` Few Minor per-utxo assert-semantics re-adds and tweak (TheBlueMatt) +- #10626 `8c841a3` doc: Remove outdated minrelaytxfee comment (MarcoFalke) +- #10559 `234ffc6` Change semantics of HaveCoinInCache to match HaveCoin (morcos) +- #10581 `7878353` Simplify return values of GetCoin/HaveCoin(InCache) (sipa) +- #10684 `a381f6a` Remove no longer used mempool.exists(outpoint) (morcos) +- #10148 `d4e551a` Use non-atomic flushing with block replay (sipa) +- #10685 `30c2130` Clarify CCoinsViewMemPool documentation (TheBlueMatt) +- #10558 `90a002e` Address nits from per-utxo change (morcos) +- #10706 `6859ad2` Improve wallet fee logic and fix GUI bugs (morcos) +- #10526 `754aa02` Force on-the-fly compaction during pertxout upgrade (sipa) +- #10985 `d896d5c` Add undocumented -forcecompactdb to force LevelDB compactions (sipa) +- #10292 `e4bbd3d` Improved efficiency in COutPoint constructors (mm-s) +- #10290 `8d6d43e` Add -stopatheight for benchmarking (sipa) + +### P2P protocol and network code +- #9726 `7639d38` netbase: Do not print an error on connection timeouts through proxy (laanwj) +- #9805 `5b583ef` Add seed.btc.petertodd.org to mainnet DNS seeds (petertodd) +- #9861 `22f609f` Trivial: Debug log ambiguity fix for peer addrs (keystrike) +- #9774 `90cb2a2` Enable host lookups for -proxy and -onion parameters (jmcorgan) +- #9558 `7b585cf` Clarify assumptions made about when BlockCheck is called (TheBlueMatt) +- #10135 `e19586a` [p2p] Send the correct error code in reject messages (jnewbery) +- #9665 `eab00d9` Use cached [compact] blocks to respond to getdata messages (TheBlueMatt) +- #10215 `a077a90` Check interruptNet during dnsseed lookups (TheBlueMatt) +- #10234 `faf2dea` [net] listbanned RPC and QT should show correct banned subnets (jnewbery) +- #10134 `314ebdf` [qa] Fixes segwit block relay test after inv-direct-fetch was disabled (sdaftuar) +- #10351 `3f57c55` removed unused code in INV message (Greg-Griffith) +- #10061 `ae78609` [net] Added SetSocketNoDelay() utility function (tjps) +- #10408 `28c6e8d` Net: Improvements to Tor control port parser (str4d) +- #10460 `5c63d66` Broadcast address every day, not 9 hours (sipa) +- #10471 `400fdd0` Denote functions CNode::GetRecvVersion() and CNode::GetRefCount() as const (pavlosantoniou) +- #10345 `67700b3` [P2P] Timeout for headers sync (sdaftuar) +- #10564 `8d9f45e` Return early in IsBanned (gmaxwell) +- #10587 `de8db47` Net: Fix resource leak in ReadBinaryFile(...) (practicalswift) +- #9549 `b33ca14` [net] Avoid possibility of NULL pointer dereference in MarkBlockAsInFlight(...) (practicalswift) +- #10446 `2772dc9` net: avoid extra dns query per seed (theuni) +- #10824 `9dd6a2b` Avoid unnecessary work in SetNetworkActive (promag) +- #10948 `df3a6f4` p2p: Hardcoded seeds update pre-0.15 branch (laanwj) +- #10977 `02f4c4a` [net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest&) (practicalswift) +- #10982 `c8b62c7` Disconnect network service bits 6 and 8 until Aug 1, 2018 (TheBlueMatt) +- #11012 `0e5cff6` Make sure to clean up mapBlockSource if we've already seen the block (theuni) + +### Validation +- #9725 `67023e9` CValidationInterface Cleanups (TheBlueMatt) +- #10178 `2584925` Remove CValidationInterface::UpdatedTransaction (TheBlueMatt) +- #10201 `a6548a4` pass Consensus::Params& to functions in validation.cpp and make them static (mariodian) +- #10297 `431a548` Simplify DisconnectBlock arguments/return value (sipa) +- #10464 `f94b7d5` Introduce static DoWarning (simplify UpdateTip) (jtimon) +- #10569 `2e7d8f8` Fix stopatheight (achow101) +- #10192 `2935b46` Cache full script execution results in addition to signatures (TheBlueMatt) +- #10179 `21ed30a` Give CValidationInterface Support for calling notifications on the CScheduler Thread (TheBlueMatt) +- #10557 `66270a4` Make check to distinguish between orphan txs and old txs more efficient (morcos) +- #10775 `7c2400c` nCheckDepth chain height fix (romanornr) +- #10821 `16240f4` Add SSE4 optimized SHA256 (sipa) +- #10854 `04d395e` Avoid using sizes on non-fixed-width types to derive protocol constants (gmaxwell) +- #10945 `2a50b11` Update defaultAssumeValid according to release-process.md (gmaxwell) +- #10986 `2361208` Update chain transaction statistics (sipa) +- #11028 `6bdf4b3` Avoid masking of difficulty adjustment errors by checkpoints (sipa) +- #9533 `cb598cf` Allow non-power-of-2 signature cache sizes (sipa) +- #9208 `acd9957` Improve DisconnectTip performance (sdaftuar) +- #10618 `f90603a` Remove confusing MAX_BLOCK_BASE_SIZE (gmaxwell) +- #10758 `bd92424` Fix some chainstate-init-order bugs (TheBlueMatt) +- #10550 `b7296bc` Don't return stale data from CCoinsViewCache::Cursor() (ryanofsky) +- #10998 `2507fd5` Fix upgrade cancel warnings (TheBlueMatt) +- #9868 `cbdb473` Abstract out the command line options for block assembly (sipa) + +### Build system +- #9727 `5f0556d` Remove fallbacks for boost_filesystem < v3 (laanwj) +- #9788 `50a2265` gitian: bump descriptors for master (theuni) +- #9794 `7ca2f54` Minor update to qrencode package builder (mitchellcash) +- #9514 `2cc0df1` release: Windows signing script (theuni) +- #9921 `8b789d8` build: Probe MSG_DONTWAIT in the same way as MSG_NOSIGNAL (laanwj) +- #10011 `32d1b34` build: Fix typo s/HAVE_DONTWAIT/HAVE_MSG_DONTWAIT (laanwj) +- #9946 `90dd9e6` Fix build errors if spaces in path or parent directory (pinheadmz) +- #10136 `81da4c7` build: Disable Wshadow warning (laanwj) +- #10166 `64962ae` Ignore Doxyfile generated from Doxyfile.in template (paveljanik) +- #10239 `0416ea9` Make Boost use std::atomic internally (sipa) +- #10228 `27faa6c` build: regenerate bitcoin-config.h as necessary (theuni) +- #10273 `8979f45` [scripts] Minor improvements to `macdeployqtplus` script (chrisgavin) +- #10325 `a26280b` 0.15.0 Depends Updates (fanquake) +- #10328 `79aeff6` Update contrib/debian to latest Ubuntu PPA upload (TheBlueMatt) +- #7522 `d25449f` Bugfix: Only use git for build info if the repository is actually the right one (luke-jr) +- #10489 `e654d61` build: silence gcc7's implicit fallthrough warning (theuni) +- #10549 `ad1a13e` Avoid printing generic and duplicated "checking for QT" during ./configure (drizzt) +- #10628 `8465b68` [depends] expat 2.2.1 (fanquake) +- #10806 `db825d2` build: verify that the assembler can handle crc32 functions (theuni) +- #10766 `b4d03be` Building Environment: Set ARFLAGS to cr (ReneNyffenegger) +- #10803 `91edda8` Explicitly search for bdb5.3 (pstratem) +- #10855 `81560b0` random: only use getentropy on openbsd (theuni) +- #10508 `1caafa6` Run Qt wallet tests on travis (ryanofsky) +- #10851 `e222618` depends: fix fontconfig with newer glibc (theuni) +- #10971 `88b1e4b` build: fix missing sse42 in depends builds (theuni) +- #11097 `129b03f` gitian: quick hack to fix version string in releases (theuni) +- #10039 `919aaf6` Fix compile errors with Qt 5.3.2 and Boost 1.55.0 (ryanofsky) +- #10168 `7032021` Fix build warning from #error text (jnewbery) +- #10301 `318392c` Check if sys/random.h is required for getentropy (jameshilliard) + +### GUI +- #9724 `1a9fd5c` Qt/Intro: Add explanation of IBD process (luke-jr) +- #9834 `b00ba62` qt: clean up initialize/shutdown signals (benma) +- #9481 `ce01e62` [Qt] Show more significant warning if we fall back to the default fee (jonasschnelli) +- #9974 `b9f930b` Add basic Qt wallet test (ryanofsky) +- #9690 `a387d3a` Change 'Clear' button string to 'Reset' (da2x) +- #9592 `9c7b7cf` [Qt] Add checkbox in the GUI to opt-in to RBF when creating a transaction (ryanofsky) +- #10098 `2b477e6` Make qt wallet test compatible with qt4 (ryanofsky) +- #9890 `1fa4ae6` Add a button to open the config file in a text editor (ericshawlinux) +- #10156 `51833a1` Fix for issues with startup and multiple monitors on windows (AllanDoensen) +- #10177 `de01da7` Changed "Send" button default status from true to false (KibbledJiveElkZoo) +- #10221 `e96486c` Stop treating coinbase outputs differently in GUI: show them at 1conf (TheBlueMatt) +- #10231 `987a6c0` [Qt] Reduce a significant cs_main lock freeze (jonasschnelli) +- #10242 `f6f3b58` [qt] Don't call method on null WalletModel object (ryanofsky) +- #10093 `a3e756b` [Qt] Don't add arguments of sensitive command to console window (jonasschnelli) +- #10362 `95546c8` [GUI] Add OSX keystroke to RPCConsole info (spencerlievens) +- #9697 `962cd3f` [Qt] simple fee bumper with user verification (jonasschnelli) +- #10390 `e477516` [wallet] remove minimum total fee option (instagibbs) +- #10420 `4314544` Add Qt tests for wallet spends & bumpfee (ryanofsky) +- #10454 `c1c9a95` Fix broken q4 test build (ryanofsky) +- #10449 `64beb13` Overhaul Qt fee bumper (jonasschnelli) +- #10582 `7c72fb9` Pass in smart fee slider value to coin control dialog (morcos) +- #10673 `4c72cc3` [qt] Avoid potential null pointer dereference in TransactionView::exportClicked() (practicalswift) +- #10769 `8fdd23a` [Qt] replace fee slider with a Dropdown, extend conf. targets (jonasschnelli) +- #10870 `412b466` [Qt] Use wallet 0 in rpc console if running with multiple wallets (jonasschnelli) +- #10988 `a9dd111` qt: Increase BLOCK_CHAIN_SIZE constants (laanwj) +- #10644 `e292140` Slightly overhaul NSI pixmaps (jonasschnelli) +- #10660 `0c3542e` Allow to cancel the txdb upgrade via splashscreen keypress 'q' (jonasschnelli) + +### Wallet +- #9359 `f7ec7cf` Add test for CWalletTx::GetImmatureCredit() returning stale values (ryanofsky) +- #9576 `56ab672` [wallet] Remove redundant initialization (practicalswift) +- #9333 `fa625b0` Document CWalletTx::mapValue entries and remove erase of nonexistent "version" entry (ryanofsky) +- #9906 `72fb515` Disallow copy constructor CReserveKeys (instagibbs) +- #9369 `3178b2c` Factor out CWallet::nTimeSmart computation into a method (ryanofsky) +- #9830 `afcd7c0` Add safe flag to listunspent result (NicolasDorier) +- #9993 `c49355c` Initialize nRelockTime (pstratem) +- #9818 `3d857f3` Save watch only key timestamps when reimporting keys (ryanofsky) +- #9294 `f34cdcb` Use internal HD chain for change outputs (hd split) (jonasschnelli) +- #10164 `e183ea2` Wallet: reduce excess logic InMempool() (kewde) +- #10186 `c9ff4f8` Remove SYNC_TRANSACTION_NOT_IN_BLOCK magic number (jnewbery) +- #10226 `64c45aa` wallet: Use boost to more portably ensure -wallet specifies only a filename (luke-jr) +- #9827 `c91ca0a` Improve ScanForWalletTransactions return value (ryanofsky) +- #9951 `fa1ac28` Wallet database handling abstractions/simplifications (laanwj) +- #10265 `c29a0d4` [wallet] [moveonly] Check non-null pindex before potentially referencing (kallewoof) +- #10283 `a550f6e` Cleanup: reduce to one GetMinimumFee call signature (morcos) +- #10294 `e2b99b1` [Wallet] unset change position when there is no change (instagibbs) +- #10115 `d3dce0e` Avoid reading the old hd master key during wallet encryption (TheBlueMatt) +- #10341 `18c9deb` rpc/wallet: Workaround older UniValue which returns a std::string temporary for get_str (luke-jr) +- #10308 `94e5227` [wallet] Securely erase potentially sensitive keys/values (tjps) +- #10257 `ea1fd43` [test] Add test for getmemoryinfo (jimmysong) +- #10295 `ce8176d` [qt] Move some WalletModel functions into CWallet (ryanofsky) +- #10506 `7cc2c67` Fix bumpfee test after #10449 (ryanofsky) +- #10500 `098b01d` Avoid CWalletTx copies in GetAddressBalances and GetAddressGroupings (ryanofsky) +- #10455 `0747d33` Simplify feebumper minimum fee code slightly (ryanofsky) +- #10522 `2805d60` [wallet] Remove unused variables (practicalswift) +- #8694 `177433a` Basic multiwallet support (luke-jr) +- #10598 `7a74f88` Supress struct/class mismatch warnings introduced in #10284 (paveljanik) +- #9343 `209eef6` Don't create change at dust limit (morcos) +- #10744 `ed88e31` Use method name via __func__ macro (darksh1ne) +- #10712 `e8b9523` Add change output if necessary to reduce excess fee (morcos) +- #10816 `1c011ff` Properly forbid -salvagewallet and -zapwallettxes for multi wallet (morcos) +- #10235 `5cfdda2` Track keypool entries as internal vs external in memory (TheBlueMatt) +- #10330 `bf0a08b` [wallet] fix zapwallettxes interaction with persistent mempool (jnewbery) +- #10831 `0b01935` Batch flushing operations to the walletdb during top up and increase keypool size (gmaxwell) +- #10795 `7b6e8bc` No longer ever reuse keypool indexes (TheBlueMatt) +- #10849 `bde4f93` Multiwallet: simplest endpoint support (jonasschnelli) +- #10817 `9022aa3` Redefine Dust and add a discard_rate (morcos) +- #10883 `bf3b742` Rename -usewallet to -rpcwallet (morcos) +- #10604 `420238d` [wallet] [tests] Add listwallets RPC, include wallet name in `getwalletinfo` and add multiwallet test (jnewbery) +- #10885 `70888a3` Reject invalid wallets (promag) +- #10949 `af56397` Clarify help message for -discardfee (morcos) +- #10942 `2e857bb` Eliminate fee overpaying edge case when subtracting fee from recipients (morcos) +- #10995 `fa64636` Fix resendwallettransactions assert failure if -walletbroadcast=0 (TheBlueMatt) +- #11022 `653a46d` Basic keypool topup (jnewbery) +- #11081 `9fe1f6b` Add length check for CExtKey deserialization (jonasschnelli, guidovranken) +- #11044 `4ef8374` [wallet] Keypool topup cleanups (jnewbery) +- #11145 `e51bb71` Fix rounding bug in calculation of minimum change (morcos) +- #9605 `779f2f9` Use CScheduler for wallet flushing, remove ThreadFlushWalletDB (TheBlueMatt) +- #10108 `4e3efd4` ApproximateBestSubset should take inputs by reference, not value (RHavar) + +### Tests and QA +- #9744 `8efd1c8` Remove unused module from rpc-tests (34ro) +- #9657 `7ff4a53` Improve rpc-tests.py (jnewbery) +- #9766 `7146d96` Add --exclude option to rpc-tests.py (jnewbery) +- #9577 `d6064a8` Fix docstrings in qa tests (jnewbery) +- #9823 `a13a417` qa: Set correct path for binaries in rpc tests (MarcoFalke) +- #9847 `6206252` Extra test vector for BIP32 (sipa) +- #9350 `88c2ae3` [Trivial] Adding label for amount inside of tx_valid/tx_invalid.json (Christewart) +- #9888 `36afd4d` travis: Verify commits only for one target (MarcoFalke) +- #9904 `58861ad` test: Fail if InitBlockIndex fails (laanwj) +- #9828 `67c5cc1` Avoid -Wshadow warnings in wallet_tests (ryanofsky) +- #9832 `48c3429` [qa] assert_start_raises_init_error (NicolasDorier) +- #9739 `9d5fcbf` Fix BIP68 activation test (jnewbery) +- #9547 `d32581c` bench: Assert that division by zero is unreachable (practicalswift) +- #9843 `c78adbf` Fix segwit getblocktemplate test (jnewbery) +- #9929 `d5ce14e` tests: Delete unused function _rpchost_to_args (laanwj) +- #9555 `19be26a` [test] Avoid reading a potentially uninitialized variable in tx_invalid-test (transaction_tests.cpp) (practicalswift) +- #9945 `ac23a7c` Improve logging in bctest.py if there is a formatting mismatch (jnewbery) +- #9768 `8910b47` [qa] Add logging to test_framework.py (jnewbery) +- #9972 `21833f9` Fix extended rpc tests broken by #9768 (jnewbery) +- #9977 `857d1e1` QA: getblocktemplate_longpoll.py should always use >0 fee tx (sdaftuar) +- #9970 `3cc13ea` Improve readability of segwit.py, smartfees.py (sdaftuar) +- #9497 `2c781fb` CCheckQueue Unit Tests (JeremyRubin) +- #10024 `9225de2` [trivial] Use log.info() instead of print() in remaining functional test cases (jnewbery) +- #9956 `3192e52` Reorganise qa directory (jnewbery) +- #10017 `02d64bd` combine_logs.py - aggregates log files from multiple bitcoinds during functional tests (jnewbery) +- #10047 `dfef6b6` [tests] Remove unused variables and imports (practicalswift) +- #9701 `a230b05` Make bumpfee tests less fragile (ryanofsky) +- #10053 `ca20923` [test] Allow functional test cases to be skipped (jnewbery) +- #10052 `a0b1e57` [test] Run extended tests once daily in Travis (jnewbery) +- #10069 `1118493` [QA] Fix typo in fundrawtransaction test (NicolasDorier) +- #10083 `c044f03` [QA] Renaming rawTx into rawtx (NicolasDorier) +- #10073 `b1a4f27` Actually run assumevalid.py (jnewbery) +- #9780 `c412fd8` Suppress noisy output from qa tests in Travis (jnewbery) +- #10096 `79af9fb` Check that all test scripts in test/functional are being run (jnewbery) +- #10076 `5b029aa` [qa] combine_logs: Use ordered list for logfiles (MarcoFalke) +- #10107 `f2734c2` Remove unused variable. Remove accidental trailing semicolons in Python code (practicalswift) +- #10109 `8ac8041` Remove SingleNodeConnCB (jnewbery) +- #10114 `edc62c9` [tests] sync_with_ping should assert that ping hasn't timed out (jnewbery) +- #10128 `427d2fd` Speed Up CuckooCache tests (JeremyRubin) +- #10072 `12af74b` Remove sources of unreliablility in extended functional tests (jnewbery) +- #10077 `ebfd653` [qa] Add setnetworkactive smoke test (MarcoFalke) +- #10152 `080d7c7` [trivial] remove unused line in Travis config (jnewbery) +- #10159 `df1ca9e` [tests] color test results and sort alphabetically (jnewbery) +- #10124 `88799ea` [test] Suppress test logging spam (jnewbery) +- #10142 `ed09dd3` Run bitcoin_test-qt under minimal QPA platform (ryanofsky) +- #9949 `a27dbc5` [bench] Avoid function call arguments which are pointers to uninitialized values (practicalswift) +- #10187 `b44adf9` tests: Fix test_runner return value in case of skipped test (laanwj) +- #10197 `d86bb07` [tests] Functional test warnings (jnewbery) +- #10219 `9111df9` Tests: Order Python Tests Differently (jimmysong) +- #10229 `f3db4c6` Tests: Add test for getdifficulty (jimmysong) +- #10224 `2723bcd` [test] Add test for getaddednodeinfo (jimmysong) +- #10023 `c530c15` [tests] remove maxblocksinflight.py (functionality covered by other test) (jnewbery) +- #10097 `1b25b6d` Move zmq test skipping logic into individual test case (jnewbery) +- #10272 `54e2d87` [Tests] Prevent warning: variable 'x' is uninitialized (paveljanik) +- #10225 `e0a7e19` [test] Add aborttrescan tests (kallewoof) +- #10278 `8254a8a` [test] Add Unit Test for GetListenPort (jimmysong) +- #10280 `47535d7` [test] Unit test amount.h/amount.cpp (jimmysong) +- #10256 `80c3a73` [test] Add test for gettxout to wallet.py (jimmysong) +- #10264 `492d22f` [test] Add tests for getconnectioncount, getnettotals and ping (jimmysong) +- #10169 `8f3e384` [tests] Remove func test code duplication (jnewbery) +- #10198 `dc8fc0c` [tests] Remove is_network_split from functional test framework (jnewbery) +- #10255 `3c5e6c9` [test] Add test for listaddressgroupings (jimmysong) +- #10137 `75171f0` Remove unused import. Remove accidental trailing semicolons (practicalswift) +- #10307 `83073de` [tests] allow zmq test to be run in out-of-tree builds (jnewbery) +- #10344 `e927483` [tests] Fix abandonconflict.py intermittency (jnewbery) +- #10318 `170bc2c` [tests] fix wait_for_inv() (jnewbery) +- #10171 `fff72de` [tests] Add node methods to test framework (jnewbery) +- #10352 `23d78c4` test: Add elapsed time to RPC tracing (laanwj) +- #10342 `6a796b2` [tests] Improve mempool_persist test (jnewbery) +- #10287 `776ba23` [tests] Update Unit Test for addrman.h/addrman.cpp (jimmysong) +- #10365 `7ee5236` [tests] increase timeouts in sendheaders test (jnewbery) +- #10361 `f6241b3` qa: disablewallet: Check that wallet is really disabled (MarcoFalke) +- #10371 `4b766fc` [tests] Clean up addrman_tests.cpp (jimmysong) +- #10253 `87abe20` [test] Add test for getnetworkhashps (jimmysong) +- #10376 `8bd16ee` [tests] fix disconnect_ban intermittency (jnewbery) +- #10374 `5411997` qa: Warn when specified test is not found (MarcoFalke) +- #10405 `0542978` tests: Correct testcase in script_tests.json for large number OP_EQUAL (laanwj) +- #10429 `6b99daf` tests: fix spurious addrman test failure (theuni) +- #10433 `8e57256` [tests] improve tmpdir structure (jnewbery) +- #10415 `217b416` [tests] Speed up fuzzing by ~200x when using afl-fuzz (practicalswift) +- #10445 `b4b057a` Add test for empty chain and reorg consistency for gettxoutsetinfo (gmaxwell) +- #10423 `1aefc94` [tests] skipped tests should clean up after themselves (jnewbery) +- #10359 `329fc1d` [tests] functional tests should call BitcoinTestFramework start/stop node methods (jnewbery) +- #10514 `e103b3f` Bugfix: missing == 0 after randrange (sipa) +- #10515 `c871f32` [test] Add test for getchaintxstats (jimmysong) +- #10509 `bea5b00` Remove xvfb configuration from travis (ryanofsky) +- #10535 `30853e1` [qa] fundrawtx: Fix shutdown race (MarcoFalke) +- #9909 `300f8e7` tests: Add FindEarliestAtLeast test for edge cases (ryanofsky) +- #10331 `75e898c` Share config between util and functional tests (jnewbery) +- #10321 `e801084` Use FastRandomContext for all tests (sipa) +- #10524 `6c2d81f` [tests] Remove printf(...) (practicalswift) +- #10547 `71ab6e5` [tests] Use FastRandomContext instead of boost::random::{mt19937,uniform_int_distribution} (practicalswift) +- #10551 `6702617` [Tests] Wallet encryption functional tests (achow101) +- #10555 `643fa0b` [tests] various improvements to zmq_test.py (jnewbery) +- #10533 `d083bd9` [tests] Use cookie auth instead of rpcuser and rpcpassword (achow101) +- #10632 `c68a9a6` qa: Add stopatheight test (MarcoFalke) +- #10636 `4bc853b` [qa] util: Check return code after closing bitcoind proc (MarcoFalke) +- #10662 `e0a7801` Initialize randomness in benchmarks (achow101) +- #10612 `7c87a9c` The young person's guide to the test_framework (jnewbery) +- #10659 `acb1153` [qa] blockchain: Pass on closed connection during generate call (MarcoFalke) +- #10690 `416af3e` [qa] Bugfix: allow overriding extra_args in ComparisonTestFramework (sdaftuar) +- #10556 `65cc7aa` Move stop/start functions from utils.py into BitcoinTestFramework (jnewbery) +- #10704 `dd07f47` [tests] nits in dbcrash.py (jnewbery) +- #10743 `be82498` [test] don't run dbcrash.py on Travis (jnewbery) +- #10761 `d3b5870` [tests] fix replace_by_fee.py (jnewbery) +- #10759 `1d4805c` Fix multi_rpc test for hosts that dont default to utf8 (TheBlueMatt) +- #10190 `e4f226a` [tests] mining functional tests (including regression test for submitblock) (jnewbery) +- #10739 `1fc783f` test: Move variable `state` down where it is used (paveljanik) +- #9980 `fee0d80` Fix mem access violation merkleblock (Christewart) +- #10893 `0c173a1` [QA] Avoid running multiwallet.py twice (jonasschnelli) +- #10927 `9d5e8f9` test: Make sure wallet.backup is created in temp path (laanwj) +- #10899 `f29d5db` [test] Qt: Use _putenv_s instead of setenv on Windows builds (brianmcmichael) +- #10912 `5c8eb79` [tests] Fix incorrect memory_cleanse(…) call in crypto_tests.cpp (practicalswift) +- #11001 `fa8a063` [tests] Test disconnecting unsupported service bits logic (jnewbery) +- #10695 `929fd72` [qa] Rewrite BIP65/BIP66 functional tests (sdaftuar) +- #10963 `ecd2135` [bench] Restore format state of cout after printing with std::fixed/setprecision (practicalswift) +- #11025 `e5d26e4` qa: Fix inv race in example_test (MarcoFalke) +- #10765 `2c811e0` Tests: address placement should be deterministic by default (ReneNyffenegger) +- #11000 `ac016e1` test: Add resendwallettransactions functional tests (promag) +- #11032 `aeb3175` [qa] Fix block message processing error in sendheaders.py (sdaftuar) +- #10105 `0b9fb68` [tests] fixup - make all Travis test runs quiet, non just cron job runs (jnewbery) +- #10222 `6ce7337` [tests] test_runner - check unicode (jnewbery) +- #10327 `35da2ae` [tests] remove import-abort-rescan.py (jnewbery) +- #11023 `bf74d37` [tests] Add option to attach a python debugger if functional test fails (jnewbery) +- #10565 `8c2098a` [coverage] Remove subtrees and benchmarks from coverage report (achow101) + +### Miscellaneous +- #9871 `be8ba2c` Add a tree sha512 hash to merge commits (sipa) +- #9821 `d19d45a` util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD (laanwj) +- #9903 `ba80a68` Docs: add details to -rpcclienttimeout doc (ian-kelling) +- #9910 `53c300f` Docs: correct and elaborate -rpcbind doc (ian-kelling) +- #9905 `01b7cda` [contrib] gh-merge: Move second sha512 check to the end (MarcoFalke) +- #9880 `4df8213` Verify Tree-SHA512s in merge commits, enforce sigs are not SHA1 (TheBlueMatt) +- #9932 `00c13ea` Fix verify-commits on travis and always check top commit's tree (TheBlueMatt) +- #9952 `6996e06` Add historical release notes for 0.14.0 (laanwj) +- #9940 `fa99663` Fix verify-commits on OSX, update for new bad Tree-SHA512, point travis to different keyservers (TheBlueMatt) +- #9963 `8040ae6` util: Properly handle errors during log message formatting (laanwj) +- #9984 `cce056d` devtools: Make github-merge compute SHA512 from git, instead of worktree (laanwj) +- #9995 `8bcf934` [doc] clarify blockchain size and pruning (askmike) +- #9734 `0c17afc` Add updating of chainTxData to release process (sipa) +- #10063 `530fcbd` add missing spaces so that markdown recognizes headline (flack) +- #10085 `db1ae54` Docs: remove 'noconnect' option (jlopp) +- #10090 `8e4f7e7` Update bitcoin.conf with example for pruning (coinables) +- #9424 `1a5aaab` Change LogAcceptCategory to use uint32_t rather than sets of strings (gmaxwell) +- #10036 `fbf36ca` Fix init README format to render correctly on github (jlopp) +- #10058 `a2cd0b0` No need to use OpenSSL malloc/free (tjps) +- #10123 `471ed00` Allow debug logs to be excluded from specified component (jnewbery) +- #10104 `fadf078` linearize script: Option to use RPC cookie (achow101) +- #10162 `a3a2160` [trivial] Log calls to getblocktemplate (jnewbery) +- #10155 `928695b` build: Deduplicate version numbers (laanwj) +- #10211 `a86255b` [doc] Contributor fixes & new "finding reviewers" section (kallewoof) +- #10250 `1428f30` Fix some empty vector references (sipa) +- #10270 `95f5e44` Remove Clang workaround for Boost 1.46 (fanquake) +- #10263 `cb007e4` Trivial: fix fee estimate write error log message (CryptAxe) +- #9670 `bd9ec0e` contrib: github-merge improvements (laanwj) +- #10260 `1d75597` [doc] Minor corrections to osx dependencies (fanquake) +- #10189 `750c5a5` devtools/net: add a verifier for scriptable changes. Use it to make CNode::id private (theuni) +- #10322 `bc64b5a` Use hardware timestamps in RNG seeding (sipa) +- #10381 `7f2b9e0` Shadowing warnings are not enabled by default, update doc accordingly (paveljanik) +- #10380 `b6ee855` [doc] Removing comments about dirty entries on txmempool (madeo) +- #10383 `d0c37ee` [logging] log system time and mock time (jnewbery) +- #10404 `b45a52a` doc: Add logging to FinalizeNode() (sdaftuar) +- #10388 `526e839` Output line to debug.log when IsInitialBlockDownload latches to false (morcos) +- #10372 `15254e9` Add perf counter data to GetStrongRandBytes state in scheduler (TheBlueMatt) +- #10461 `55b72f3` Update style guide (sipa) +- #10486 `10e8c0a` devtools: Retry after signing fails in github-merge (laanwj) +- #10447 `f259263` Make bitcoind invalid argument error message specific (laanwj) +- #10495 `6a38b79` contrib: Update location of seeds.txt (laanwj) +- #10469 `b6b150b` Fixing typo in rpcdump.cpp help message (keystrike) +- #10451 `27b9931` contrib/init/bitcoind.openrcconf: Don't disable wallet by default (luke-jr) +- #10323 `00d3692` Update to latest libsecp256k1 master (sipa) +- #10422 `cec9e1e` Fix timestamp in fee estimate debug message (morcos) +- #10566 `5d034ee` [docs] Use the "domain name setup" image (previously unused) in the gitian docs (practicalswift) +- #10534 `a514ac3` Clarify prevector::erase and avoid swap-to-clear (sipa) +- #10575 `22ec768` Header include guideline (sipa) +- #10480 `fbf5d3b` Improve commit-check-script.sh (sipa) +- #10502 `1ad3d4e` scripted-diff: Remove BOOST_FOREACH, Q_FOREACH and PAIRTYPE (jtimon) +- #10377 `b63be2c` Use rdrand as entropy source on supported platforms (sipa) +- #9895 `228c319` Turn TryCreateDirectory() into TryCreateDirectories() (benma) +- #10602 `d76e84a` Make clang-format use C++11 features (e.g. A> instead of A >) (practicalswift) +- #10623 `c38f540` doc: Add 0.14.2 release notes (MarcoFalke) +- #10276 `b750b33` contrib/verifybinaries: allow filtering by platform (knocte) +- #10248 `01c4b14` Rewrite addrdb with less duplication using CHashVerifier (sipa) +- #10577 `232508f` Add an explanation of quickly hashing onto a non-power of two range (gmaxwell) +- #10608 `eee398f` Add a comment explaining the use of MAX_BLOCK_BASE_SIZE (gmaxwell) +- #10728 `7397af9` fix typo in help text for removeprunedfunds (AkioNak) +- #10193 `6dbcc74` scripted-diff: Remove #include (jtimon) +- #10676 `379aed0` document script-based return fields for validateaddress (instagibbs) +- #10651 `cef4b5c` Verify binaries from bitcoincore.org and bitcoin.org (TheBlueMatt) +- #10786 `ca4c545` Add PR description to merge commit in github-merge.py (sipa) +- #10812 `c5904e8` [utils] Allow bitcoin-cli's -rpcconnect option to be used with square brackets (jnewbery) +- #10842 `3895e25` Fix incorrect Doxygen tag (@ince → @since). Doxygen parameter name matching (practicalswift) +- #10681 `df0793f` add gdb attach process to test README (instagibbs) +- #10789 `1124328` Punctuation/grammer fixes in rpcwallet.cpp (stevendlander) +- #10655 `78f307b` Properly document target_confirmations in listsinceblock (RHavar) +- #10917 `5c003cb` developer-notes: add reference to snake_case and PascalCase (benma) +- #11003 `4b5a7ce` Docs: Capitalize bullet points in CONTRIBUTING guide (eklitzke) +- #10968 `98aa3f6` Add instructions for parallel gitian builds (coblee) +- #11076 `1c4b9b3` 0.15 release-notes nits: fix redundancy, remove accidental parenthesis & fix range style (practicalswift) +- #11090 `8f0121c` Update contributor names in release-notes.md (Derek701) +- #11056 `cbdd338` disable jni in builds (instagibbs) +- #11080 `2b59cfb` doc: Update build-openbsd for 6.1 (laanwj) +- #11119 `0a6af47` [doc] build-windows: Mention that only trusty works (MarcoFalke) +- #11108 `e8ad101` Changing -txindex requires -reindex, not -reindex-chainstate (TheBlueMatt) +- #9792 `342b9bc` FastRandomContext improvements and switch to ChaCha20 (sipa) +- #9505 `67ed40e` Prevector Quick Destruct (JeremyRubin) +- #10820 `ef37f20` Use cpuid intrinsics instead of asm code (sipa) +- #9999 `a328904` [LevelDB] Plug leveldb logs to bitcoin logs (NicolasDorier) +- #9693 `c5e9e42` Prevent integer overflow in ReadVarInt (gmaxwell) +- #10129 `351d0ad` scheduler: fix sub-second precision with boost < 1.50 (theuni) +- #10153 `fade788` logging: Fix off-by-one for shrinkdebugfile default (MarcoFalke) +- #10305 `c45da32` Fix potential NPD introduced in b297426c (TheBlueMatt) +- #10338 `daf3e7d` Maintain state across GetStrongRandBytes calls (sipa) +- #10544 `a4fe077` Update to LevelDB 1.20 (sipa) +- #10614 `cafe24f` random: fix crash on some 64bit platforms (theuni) +- #10714 `2a09a38` Avoid printing incorrect block indexing time due to uninitialized variable (practicalswift) +- #10837 `8bc6d1f` Fix resource leak on error in GetDevURandom (corebob) +- #10832 `89bb036` init: Factor out AppInitLockDataDirectory and fix startup core dump issue (laanwj) +- #10914 `b995a37` Add missing lock in CScheduler::AreThreadsServicingQueue() (TheBlueMatt) +- #10958 `659c096` Update to latest Bitcoin patches for LevelDB (sipa) +- #10919 `c1c671f` Fix more init bugs (TheBlueMatt) + Credits ======= From 0ced455b99154aa875ca07378c63167f13006360 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 7 Sep 2017 16:17:58 -0400 Subject: [PATCH 024/196] travis: filter out pyenv --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 12f91096cc95..3220e76b063b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,7 @@ env: before_install: - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") + - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/pyenv/d' | tr "\n" ":" | sed "s|::|:|g") install: - if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi From fa120bd01c7fc27eb9d3e4ecbf4b4ccc3b728686 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 10 Sep 2017 04:26:35 +0200 Subject: [PATCH 025/196] doc: Old fee_estimates.dat are discarded by 0.15.0 --- doc/release-notes.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 5a391462c727..3d25dd2317f6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -21,13 +21,17 @@ How to Upgrade If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the -installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) or `bitcoind`/`bitcoin-qt` (on Linux). The first time you run version 0.15.0, your chainstate database will be converted to a new format, which will take anywhere from a few minutes to half an hour, depending on the speed of your machine. +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee +estimates to be discarded. + Note that the block database format also changed in version 0.8.0 and there is no automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading directly from 0.7.x and earlier without redownloading the blockchain is not supported. From 7c53587101eaf206a6a6a11a9398d43f139eadcf Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 14 Sep 2017 16:16:47 +0200 Subject: [PATCH 026/196] doc: Clean out release notes on 0.15 branch Prepare for 0.15.1 Tree-SHA512: d306369ebf2090dd3f74ead6ca6b9f3f2d56bcde6eb6aaab22ac38a5f7ab6cdf3da1142ad6fe266f793f27bbed4247397375f6177f2c7ccc1a57de9acaa5a181 --- doc/release-notes.md | 799 +------------------------------------------ 1 file changed, 7 insertions(+), 792 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 3d25dd2317f6..9bf9e63c5c53 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,9 +1,9 @@ (note: this is a temporary file, to be added-to by anybody, and moved to release-notes at release time) -Bitcoin Core version *0.15.0* is now available from: +Bitcoin Core version *0.15.1* is now available from: - + This is a new major version release, including new features, various bugfixes and performance improvements, as well as updated translations. @@ -24,9 +24,9 @@ shut down (which might take a few minutes for older versions), then run the installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) or `bitcoind`/`bitcoin-qt` (on Linux). -The first time you run version 0.15.0, your chainstate database will be converted to a -new format, which will take anywhere from a few minutes to half an hour, -depending on the speed of your machine. +The first time you run version 0.15.0 or higher, your chainstate database will +be converted to a new format, which will take anywhere from a few minutes to +half an hour, depending on the speed of your machine. The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee @@ -60,801 +60,16 @@ frequently tested on them. Notable changes =============== -Performance Improvements ------------------------- -Version 0.15 contains a number of significant performance improvements, which make -Initial Block Download, startup, transaction and block validation much faster: -- The chainstate database (which is used for tracking UTXOs) has been changed - from a per-transaction model to a per-output model (See [PR 10195](https://github.com/bitcoin/bitcoin/pull/10195)). Advantages of this model - are that it: - - avoids the CPU overhead of deserializing and serializing the unused outputs; - - has more predictable memory usage; - - uses simpler code; - - is adaptable to various future cache flushing strategies. - - As a result, validating the blockchain during Initial Block Download (IBD) and reindex - is ~30-40% faster, uses 10-20% less memory, and flushes to disk far less frequently. - The only downside is that the on-disk database is 15% larger. During the conversion from the previous format - a few extra gigabytes may be used. -- Earlier versions experienced a spike in memory usage while flushing UTXO updates to disk. - As a result, only half of the available memory was actually used as cache, and the other half was - reserved to accommodate flushing. This is no longer the case (See [PR 10148](https://github.com/bitcoin/bitcoin/pull/10148)), and the entirety of - the available cache (see `-dbcache`) is now actually used as cache. This reduces the flushing - frequency by a factor 2 or more. -- In previous versions, signature validation for transactions has been cached when the - transaction is accepted to the mempool. Version 0.15 extends this to cache the entire script - validity (See [PR 10192](https://github.com/bitcoin/bitcoin/pull/10192)). This means that if a transaction in a block has already been accepted to the - mempool, the scriptSig does not need to be re-evaluated. Empirical tests show that - this results in new block validation being 40-50% faster. -- LevelDB has been upgraded to version 1.20 (See [PR 10544](https://github.com/bitcoin/bitcoin/pull/10544)). This version contains hardware acceleration for CRC - on architectures supporting SSE 4.2. As a result, synchronization and block validation are now faster. -- SHA256 hashing has been optimized for architectures supporting SSE 4 (See [PR 10821](https://github.com/bitcoin/bitcoin/pull/10821)). SHA256 is around - 50% faster on supported hardware, which results in around 5% faster IBD and block - validation. In version 0.15, SHA256 hardware optimization is disabled in release builds by - default, but can be enabled by using `--enable-experimental-asm` when building. -- Refill of the keypool no longer flushes the wallet between each key which resulted in a ~20x speedup in creating a new wallet. Part of this speedup was used to increase the default keypool to 1000 keys to make recovery more robust. (See [PR 10831](https://github.com/bitcoin/bitcoin/pull/10831)). - -Fee Estimation Improvements ---------------------------- - -Fee estimation has been significantly improved in version 0.15, with more accurate fee estimates used by the wallet and a wider range of options for advanced users of the `estimatesmartfee` and `estimaterawfee` RPCs (See [PR 10199](https://github.com/bitcoin/bitcoin/pull/10199)). - -### Changes to internal logic and wallet behavior - -- Internally, estimates are now tracked on 3 different time horizons. This allows for longer targets and means estimates adjust more quickly to changes in conditions. -- Estimates can now be *conservative* or *economical*. *Conservative* estimates use longer time horizons to produce an estimate which is less susceptible to rapid changes in fee conditions. *Economical* estimates use shorter time horizons and will be more affected by short-term changes in fee conditions. Economical estimates may be considerably lower during periods of low transaction activity (for example over weekends), but may result in transactions being unconfirmed if prevailing fees increase rapidly. -- By default, the wallet will use conservative fee estimates to increase the reliability of transactions being confirmed within the desired target. For transactions that are marked as replaceable, the wallet will use an economical estimate by default, since the fee can be 'bumped' if the fee conditions change rapidly (See [PR 10589](https://github.com/bitcoin/bitcoin/pull/10589)). -- Estimates can now be made for confirmation targets up to 1008 blocks (one week). -- More data on historical fee rates is stored, leading to more precise fee estimates. -- Transactions which leave the mempool due to eviction or other non-confirmed reasons are now taken into account by the fee estimation logic, leading to more accurate fee estimates. -- The fee estimation logic will make sure enough data has been gathered to return a meaningful estimate. If there is insufficient data, a fallback default fee is used. - -### Changes to fee estimate RPCs - -- The `estimatefee` RPC is now deprecated in favor of using only `estimatesmartfee` (which is the implementation used by the GUI) -- The `estimatesmartfee` RPC interface has been changed (See [PR 10707](https://github.com/bitcoin/bitcoin/pull/10707)): - - The `nblocks` argument has been renamed to `conf_target` (to be consistent with other RPC methods). - - An `estimate_mode` argument has been added. This argument takes one of the following strings: `CONSERVATIVE`, `ECONOMICAL` or `UNSET` (which defaults to `CONSERVATIVE`). - - The RPC return object now contains an `errors` member, which returns errors encountered during processing. - - If Bitcoin Core has not been running for long enough and has not seen enough blocks or transactions to produce an accurate fee estimation, an error will be returned (previously a value of -1 was used to indicate an error, which could be confused for a feerate). -- A new `estimaterawfee` RPC is added to provide raw fee data. External clients can query and use this data in their own fee estimation logic. - -Multi-wallet support --------------------- - -Bitcoin Core now supports loading multiple, separate wallets (See [PR 8694](https://github.com/bitcoin/bitcoin/pull/8694), [PR 10849](https://github.com/bitcoin/bitcoin/pull/10849)). The wallets are completely separated, with individual balances, keys and received transactions. - -Multi-wallet is enabled by using more than one `-wallet` argument when starting Bitcoin, either on the command line or in the Bitcoin config file. - -**In Bitcoin-Qt, only the first wallet will be displayed and accessible for creating and signing transactions.** GUI selectable multiple wallets will be supported in a future version. However, even in 0.15 other loaded wallets will remain synchronized to the node's current tip in the background. This can be useful if running a pruned node, since loading a wallet where the most recent sync is beyond the pruned height results in having to download and revalidate the whole blockchain. Continuing to synchronize all wallets in the background avoids this problem. - -Bitcoin Core 0.15.0 contains the following changes to the RPC interface and `bitcoin-cli` for multi-wallet: - -* When running Bitcoin Core with a single wallet, there are **no** changes to the RPC interface or `bitcoin-cli`. All RPC calls and `bitcoin-cli` commands continue to work as before. -* When running Bitcoin Core with multi-wallet, all *node-level* RPC methods continue to work as before. HTTP RPC requests should be send to the normal `:/` endpoint, and `bitcoin-cli` commands should be run as before. A *node-level* RPC method is any method which does not require access to the wallet. -* When running Bitcoin Core with multi-wallet, *wallet-level* RPC methods must specify the wallet for which they're intended in every request. HTTP RPC requests should be send to the `:/wallet//` endpoint, for example `127.0.0.1:8332/wallet/wallet1.dat/`. `bitcoin-cli` commands should be run with a `-rpcwallet` option, for example `bitcoin-cli -rpcwallet=wallet1.dat getbalance`. -* A new *node-level* `listwallets` RPC method is added to display which wallets are currently loaded. The names returned by this method are the same as those used in the HTTP endpoint and for the `rpcwallet` argument. - -Note that while multi-wallet is now fully supported, the RPC multi-wallet interface should be considered unstable for version 0.15.0, and there may backwards-incompatible changes in future versions. - -Replace-by-fee control in the GUI ---------------------------------- - -Bitcoin Core has supported creating opt-in replace-by-fee (RBF) transactions -since version 0.12.0, and since version 0.14.0 has included a `bumpfee` RPC method to -replace unconfirmed opt-in RBF transactions with a new transaction that pays -a higher fee. - -In version 0.15, creating an opt-in RBF transaction and replacing the unconfirmed -transaction with a higher-fee transaction are both supported in the GUI (See [PR 9592](https://github.com/bitcoin/bitcoin/pull/9592)). - -Removal of Coin Age Priority ----------------------------- - -In previous versions of Bitcoin Core, a portion of each block could be reserved for transactions based on the age and value of UTXOs they spent. This concept (Coin Age Priority) is a policy choice by miners, and there are no consensus rules around the inclusion of Coin Age Priority transactions in blocks. In practice, only a few miners continue to use Coin Age Priority for transaction selection in blocks. Bitcoin Core 0.15 removes all remaining support for Coin Age Priority (See [PR 9602](https://github.com/bitcoin/bitcoin/pull/9602)). This has the following implications: - -- The concept of *free transactions* has been removed. High Coin Age Priority transactions would previously be allowed to be relayed even if they didn't attach a miner fee. This is no longer possible since there is no concept of Coin Age Priority. The `-limitfreerelay` and `-relaypriority` options which controlled relay of free transactions have therefore been removed. -- The `-sendfreetransactions` option has been removed, since almost all miners do not include transactions which do not attach a transaction fee. -- The `-blockprioritysize` option has been removed. -- The `estimatepriority` and `estimatesmartpriority` RPCs have been removed. -- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. -- The `prioritisetransaction` RPC no longer takes a `priority_delta` argument, which is replaced by a `dummy` argument for backwards compatibility with clients using positional arguments. The RPC is still used to change the apparent fee-rate of the transaction by using the `fee_delta` argument. -- `-minrelaytxfee` can now be set to 0. If `minrelaytxfee` is set, then fees smaller than `minrelaytxfee` (per kB) are rejected from relaying, mining and transaction creation. This defaults to 1000 satoshi/kB. -- The `-printpriority` option has been updated to only output the fee rate and hash of transactions included in a block by the mining code. - -Mempool Persistence Across Restarts ------------------------------------ - -Version 0.14 introduced mempool persistence across restarts (the mempool is saved to a `mempool.dat` file in the data directory prior to shutdown and restores the mempool when the node is restarted). Version 0.15 allows this feature to be switched on or off using the `-persistmempool` command-line option (See [PR 9966](https://github.com/bitcoin/bitcoin/pull/9966)). By default, the option is set to true, and the mempool is saved on shutdown and reloaded on startup. If set to false, the `mempool.dat` file will not be loaded on startup or saved on shutdown. - -New RPC methods ---------------- - -Version 0.15 introduces several new RPC methods: - -- `abortrescan` stops current wallet rescan, e.g. when triggered by an `importprivkey` call (See [PR 10208](https://github.com/bitcoin/bitcoin/pull/10208)). -- `combinerawtransaction` accepts a JSON array of raw transactions and combines them into a single raw transaction (See [PR 10571](https://github.com/bitcoin/bitcoin/pull/10571)). -- `estimaterawfee` returns raw fee data so that customized logic can be implemented to analyze the data and calculate estimates. See [Fee Estimation Improvements](#fee-estimation-improvements) for full details on changes to the fee estimation logic and interface. -- `getchaintxstats` returns statistics about the total number and rate of transactions - in the chain (See [PR 9733](https://github.com/bitcoin/bitcoin/pull/9733)). -- `listwallets` lists wallets which are currently loaded. See the *Multi-wallet* section - of these release notes for full details (See [Multi-wallet support](#multi-wallet-support)). -- `uptime` returns the total runtime of the `bitcoind` server since its last start (See [PR 10400](https://github.com/bitcoin/bitcoin/pull/10400)). - -Low-level RPC changes ---------------------- - -- When using Bitcoin Core in multi-wallet mode, RPC requests for wallet methods must specify - the wallet that they're intended for. See [Multi-wallet support](#multi-wallet-support) for full details. - -- The new database model no longer stores information about transaction - versions of unspent outputs (See [Performance improvements](#performance-improvements)). This means that: - - The `gettxout` RPC no longer has a `version` field in the response. - - The `gettxoutsetinfo` RPC reports `hash_serialized_2` instead of `hash_serialized`, - which does not commit to the transaction versions of unspent outputs, but does - commit to the height and coinbase information. - - The `getutxos` REST path no longer reports the `txvers` field in JSON format, - and always reports 0 for transaction versions in the binary format - -- The `estimatefee` RPC is deprecated. Clients should switch to using the `estimatesmartfee` RPC, which returns better fee estimates. See [Fee Estimation Improvements](#fee-estimation-improvements) for full details on changes to the fee estimation logic and interface. - -- The `gettxoutsetinfo` response now contains `disk_size` and `bogosize` instead of - `bytes_serialized`. The first is a more accurate estimate of actual disk usage, but - is not deterministic. The second is unrelated to disk usage, but is a - database-independent metric of UTXO set size: it counts every UTXO entry as 50 + the - length of its scriptPubKey (See [PR 10426](https://github.com/bitcoin/bitcoin/pull/10426)). - -- `signrawtransaction` can no longer be used to combine multiple transactions into a single transaction. Instead, use the new `combinerawtransaction` RPC (See [PR 10571](https://github.com/bitcoin/bitcoin/pull/10571)). - -- `fundrawtransaction` no longer accepts a `reserveChangeKey` option. This option used to allow RPC users to fund a raw transaction using an key from the keypool for the change address without removing it from the available keys in the keypool. The key could then be re-used for a `getnewaddress` call, which could potentially result in confusing or dangerous behaviour (See [PR 10784](https://github.com/bitcoin/bitcoin/pull/10784)). - -- `estimatepriority` and `estimatesmartpriority` have been removed. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). - -- The `listunspent` RPC now takes a `query_options` argument (see [PR 8952](https://github.com/bitcoin/bitcoin/pull/8952)), which is a JSON object - containing one or more of the following members: - - `minimumAmount` - a number specifying the minimum value of each UTXO - - `maximumAmount` - a number specifying the maximum value of each UTXO - - `maximumCount` - a number specifying the minimum number of UTXOs - - `minimumSumAmount` - a number specifying the minimum sum value of all UTXOs - -- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). - -- The `dumpwallet` RPC now returns the full absolute path to the dumped wallet. It - used to return no value, even if successful (See [PR 9740](https://github.com/bitcoin/bitcoin/pull/9740)). - -- In the `getpeerinfo` RPC, the return object for each peer now returns an `addrbind` member, which contains the ip address and port of the connection to the peer. This is in addition to the `addrlocal` member which contains the ip address and port of the local node as reported by the peer (See [PR 10478](https://github.com/bitcoin/bitcoin/pull/10478)). - -- The `disconnectnode` RPC can now disconnect a node specified by node ID (as well as by IP address/port). To disconnect a node based on node ID, call the RPC with the new `nodeid` argument (See [PR 10143](https://github.com/bitcoin/bitcoin/pull/10143)). - -- The second argument in `prioritisetransaction` has been renamed from `priority_delta` to `dummy` since Bitcoin Core no longer has a concept of coin age priority. The `dummy` argument has no functional effect, but is retained for positional argument compatibility. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). - -- The `resendwallettransactions` RPC throws an error if the `-walletbroadcast` option is set to false (See [PR 10995](https://github.com/bitcoin/bitcoin/pull/10995)). - -- The second argument in the `submitblock` RPC argument has been renamed from `parameters` to `dummy`. This argument never had any effect, and the renaming is simply to communicate this fact to the user (See [PR 10191](https://github.com/bitcoin/bitcoin/pull/10191)) - (Clients should, however, use positional arguments for `submitblock` in order to be compatible with BIP 22.) - -- The `verbose` argument of `getblock` has been renamed to `verbosity` and now takes an integer from 0 to 2. Verbose level 0 is equivalent to `verbose=false`. Verbose level 1 is equivalent to `verbose=true`. Verbose level 2 will give the full transaction details of each transaction in the output as given by `getrawtransaction`. The old behavior of using the `verbose` named argument and a boolean value is still maintained for compatibility. - -- Error codes have been updated to be more accurate for the following error cases (See [PR 9853](https://github.com/bitcoin/bitcoin/pull/9853)): - - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for - example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR. - - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned - because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND. - - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned - because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR. - - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned - because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR. - - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address - or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED. - - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban - a node that has not previously been banned. Previously returned RPC_MISC_ERROR. - - `removeprunedfunds` now returns RPC_WALLET_ERROR if `bitcoind` is unable to remove - the transaction. Previously returned RPC_INTERNAL_ERROR. - - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not - exist in the wallet. Previously returned RPC_INTERNAL_ERROR. - - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change - address is provided. Previously returned RPC_INVALID_PARAMETER. - - `fundrawtransaction` now returns RPC_WALLET_ERROR if `bitcoind` is unable to create - the transaction. The error message provides further details. Previously returned - RPC_INTERNAL_ERROR. - - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has - descendants in the wallet. Previously returned RPC_MISC_ERROR. - - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has - descendants in the mempool. Previously returned RPC_MISC_ERROR. - - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has - has been mined or conflicts with a mined transaction. Previously returned - RPC_INVALID_ADDRESS_OR_KEY. - - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not - BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY. - - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already - been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST. - - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains - inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY. - - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change - outputs. Previously returned RPC_MISC_ERROR. - - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change - output. Previously returned RPC_MISC_ERROR. - - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned - RPC_MISC_ERROR. - - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned - RPC_MISC_ERROR. - - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the - fee. Previously returned RPC_MISC_ERROR. - -0.15.0 Change log +0.15.1 Change log ================= -### RPC and other APIs -- #9485 `61a640e` ZMQ example using python3 and asyncio (mcelrath) -- #9894 `0496e15` remove 'label' filter for rpc command help (instagibbs) -- #9853 `02bd6e9` Fix error codes from various RPCs (jnewbery) -- #9842 `598ef9c` Fix RPC failure testing (continuation of #9707) (jnewbery) -- #10038 `d34995a` Add mallocinfo mode to `getmemoryinfo` RPC (laanwj) -- #9500 `3568b30` [Qt][RPC] Autocomplete commands for 'help' command in debug console (achow101) -- #10056 `e6156a0` [zmq] Call va_end() on va_start()ed args (kallewoof) -- #10086 `7438cea` Trivial: move rpcserialversion into RPC option group (jlopp) -- #10150 `350b224` [rpc] Add logging rpc (jnewbery) -- #10208 `393160c` [wallet] Rescan abortability (kallewoof) -- #10143 `a987def` [net] Allow disconnectnode RPC to be called with node id (jnewbery) -- #10281 `0e8499c` doc: Add RPC interface guidelines (laanwj) -- #9733 `d4732f3` Add getchaintxstats RPC (sipa) -- #10310 `f4b15e2` [doc] Add hint about getmempoolentry to getrawmempool help (kallewoof) -- #8704 `96c850c` [RPC] Transaction details in getblock (achow101) -- #8952 `9390845` Add query options to listunspent RPC call (pedrobranco) -- #10413 `08ac35a` Fix docs (there's no rpc command setpaytxfee) (RHavar) -- #8384 `e317c0d` Add witness data output to TxInError messages (instagibbs) -- #9571 `4677151` RPC: getblockchaininfo returns BIP signaling statistics (pinheadmz) -- #10450 `ef2d062` Fix bumpfee rpc "errors" return value (ryanofsky) -- #10475 `39039b1` [RPC] getmempoolinfo mempoolminfee is a BTC/KB feerate (instagibbs) -- #10478 `296928e` rpc: Add listen address to incoming connections in `getpeerinfo` (laanwj) -- #10403 `08d0390` Fix importmulti failure to return rescan errors (ryanofsky) -- #9740 `9fec4da` Add friendly output to dumpwallet (aideca) -- #10426 `16f6c98` Replace bytes_serialized with bogosize (sipa) -- #10252 `980deaf` RPC/Mining: Restore API compatibility for prioritisetransaction (luke-jr) -- #9672 `46311e7` Opt-into-RBF for RPC & bitcoin-tx (luke-jr) -- #10481 `9c248e3` Decodehextx scripts sanity check (achow101) -- #10488 `fa1f106` Note that the prioritizetransaction dummy value is deprecated, and has no meaning (TheBlueMatt) -- #9738 `c94b89e` gettxoutproof() should return consistent result (jnewbery) -- #10191 `00350bd` [trivial] Rename unused RPC arguments 'dummy' (jnewbery) -- #10627 `b62b4c8` fixed listunspent rpc convert parameter (tnakagawa) -- #10412 `bef02fb` Improve wallet rescan API (ryanofsky) -- #10400 `1680ee0` [RPC] Add an uptime command that displays the amount of time (in seconds) bitcoind has been running (rvelhote) -- #10683 `d81bec7` rpc: Move the `generate` RPC call to rpcwallet (laanwj) -- #10710 `30bc0f6` REST/RPC example update (Mirobit) -- #10747 `9edda0c` [rpc] fix verbose argument for getblock in bitcoin-cli (jnewbery) -- #10589 `104f5f2` More economical fee estimates for RBF and RPC options to control (morcos) -- #10543 `b27b004` Change API to estimaterawfee (morcos) -- #10807 `afd2fca` getbalance example covers at least 6 confirms (instagibbs) -- #10707 `75b5643` Better API for estimatesmartfee RPC (morcos) -- #10784 `9e8d6a3` Do not allow users to get keys from keypool without reserving them (TheBlueMatt) -- #10857 `d445a2c` [RPC] Add a deprecation warning to getinfo's output (achow101) -- #10571 `adf170d` [RPC]Move transaction combining from signrawtransaction to new RPC (achow101) -- #10783 `041dad9` [RPC] Various rpc argument fixes (instagibbs) -- #9622 `6ef3c7e` [rpc] listsinceblock should include lost transactions when parameter is a reorg'd block (kallewoof) -- #10799 `8537187` Prevent user from specifying conflicting parameters to fundrawtx (TheBlueMatt) -- #10931 `0b11a07` Fix misleading "Method not found" multiwallet errors (ryanofsky) -- #10788 `f66c596` [RPC] Fix addwitnessaddress by replacing ismine with producesignature (achow101) -- #10999 `627c3c0` Fix amounts formatting in `decoderawtransaction` (laanwj) -- #11002 `4268426` [wallet] return correct error code from resendwallettransaction (jnewbery) -- #11029 `96a63a3` [RPC] trivial: gettxout no longer shows version of tx (FelixWeis) -- #11083 `6c2b008` Fix combinerawtransaction RPC help result section (jonasnick) -- #11027 `07164bb` [RPC] Only return hex field once in getrawtransaction (achow101) -- #10698 `5af6572` Be consistent in calling transactions "replaceable" for Opt-In RBF (TheBlueMatt) - -### Block and transaction handling -- #9801 `a8c5751` Removed redundant parameter from mempool.PrioritiseTransaction (gubatron) -- #9819 `1efc99c` Remove harmless read of unusued priority estimates (morcos) -- #9822 `b7547fa` Remove block file location upgrade code (benma) -- #9602 `30ff3a2` Remove coin age priority and free transactions - implementation (morcos) -- #9548 `47510ad` Remove min reasonable fee (morcos) -- #10249 `c73af54` Switch CCoinsMap from boost to std unordered_map (sipa) -- #9966 `2a183de` Control mempool persistence using a command line parameter (jnewbery) -- #10199 `318ea50` Better fee estimates (morcos) -- #10196 `bee3529` Bugfix: PrioritiseTransaction updates the mempool tx counter (sdaftuar) -- #10195 `1088b02` Switch chainstate db and cache to per-txout model (sipa) -- #10284 `c2ab38b` Always log debug information for fee calculation in CreateTransaction (morcos) -- #10503 `efbcf2b` Use REJECT_DUPLICATE for already known and conflicted txn (sipa) -- #10537 `b3eb0d6` Few Minor per-utxo assert-semantics re-adds and tweak (TheBlueMatt) -- #10626 `8c841a3` doc: Remove outdated minrelaytxfee comment (MarcoFalke) -- #10559 `234ffc6` Change semantics of HaveCoinInCache to match HaveCoin (morcos) -- #10581 `7878353` Simplify return values of GetCoin/HaveCoin(InCache) (sipa) -- #10684 `a381f6a` Remove no longer used mempool.exists(outpoint) (morcos) -- #10148 `d4e551a` Use non-atomic flushing with block replay (sipa) -- #10685 `30c2130` Clarify CCoinsViewMemPool documentation (TheBlueMatt) -- #10558 `90a002e` Address nits from per-utxo change (morcos) -- #10706 `6859ad2` Improve wallet fee logic and fix GUI bugs (morcos) -- #10526 `754aa02` Force on-the-fly compaction during pertxout upgrade (sipa) -- #10985 `d896d5c` Add undocumented -forcecompactdb to force LevelDB compactions (sipa) -- #10292 `e4bbd3d` Improved efficiency in COutPoint constructors (mm-s) -- #10290 `8d6d43e` Add -stopatheight for benchmarking (sipa) - -### P2P protocol and network code -- #9726 `7639d38` netbase: Do not print an error on connection timeouts through proxy (laanwj) -- #9805 `5b583ef` Add seed.btc.petertodd.org to mainnet DNS seeds (petertodd) -- #9861 `22f609f` Trivial: Debug log ambiguity fix for peer addrs (keystrike) -- #9774 `90cb2a2` Enable host lookups for -proxy and -onion parameters (jmcorgan) -- #9558 `7b585cf` Clarify assumptions made about when BlockCheck is called (TheBlueMatt) -- #10135 `e19586a` [p2p] Send the correct error code in reject messages (jnewbery) -- #9665 `eab00d9` Use cached [compact] blocks to respond to getdata messages (TheBlueMatt) -- #10215 `a077a90` Check interruptNet during dnsseed lookups (TheBlueMatt) -- #10234 `faf2dea` [net] listbanned RPC and QT should show correct banned subnets (jnewbery) -- #10134 `314ebdf` [qa] Fixes segwit block relay test after inv-direct-fetch was disabled (sdaftuar) -- #10351 `3f57c55` removed unused code in INV message (Greg-Griffith) -- #10061 `ae78609` [net] Added SetSocketNoDelay() utility function (tjps) -- #10408 `28c6e8d` Net: Improvements to Tor control port parser (str4d) -- #10460 `5c63d66` Broadcast address every day, not 9 hours (sipa) -- #10471 `400fdd0` Denote functions CNode::GetRecvVersion() and CNode::GetRefCount() as const (pavlosantoniou) -- #10345 `67700b3` [P2P] Timeout for headers sync (sdaftuar) -- #10564 `8d9f45e` Return early in IsBanned (gmaxwell) -- #10587 `de8db47` Net: Fix resource leak in ReadBinaryFile(...) (practicalswift) -- #9549 `b33ca14` [net] Avoid possibility of NULL pointer dereference in MarkBlockAsInFlight(...) (practicalswift) -- #10446 `2772dc9` net: avoid extra dns query per seed (theuni) -- #10824 `9dd6a2b` Avoid unnecessary work in SetNetworkActive (promag) -- #10948 `df3a6f4` p2p: Hardcoded seeds update pre-0.15 branch (laanwj) -- #10977 `02f4c4a` [net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest&) (practicalswift) -- #10982 `c8b62c7` Disconnect network service bits 6 and 8 until Aug 1, 2018 (TheBlueMatt) -- #11012 `0e5cff6` Make sure to clean up mapBlockSource if we've already seen the block (theuni) - -### Validation -- #9725 `67023e9` CValidationInterface Cleanups (TheBlueMatt) -- #10178 `2584925` Remove CValidationInterface::UpdatedTransaction (TheBlueMatt) -- #10201 `a6548a4` pass Consensus::Params& to functions in validation.cpp and make them static (mariodian) -- #10297 `431a548` Simplify DisconnectBlock arguments/return value (sipa) -- #10464 `f94b7d5` Introduce static DoWarning (simplify UpdateTip) (jtimon) -- #10569 `2e7d8f8` Fix stopatheight (achow101) -- #10192 `2935b46` Cache full script execution results in addition to signatures (TheBlueMatt) -- #10179 `21ed30a` Give CValidationInterface Support for calling notifications on the CScheduler Thread (TheBlueMatt) -- #10557 `66270a4` Make check to distinguish between orphan txs and old txs more efficient (morcos) -- #10775 `7c2400c` nCheckDepth chain height fix (romanornr) -- #10821 `16240f4` Add SSE4 optimized SHA256 (sipa) -- #10854 `04d395e` Avoid using sizes on non-fixed-width types to derive protocol constants (gmaxwell) -- #10945 `2a50b11` Update defaultAssumeValid according to release-process.md (gmaxwell) -- #10986 `2361208` Update chain transaction statistics (sipa) -- #11028 `6bdf4b3` Avoid masking of difficulty adjustment errors by checkpoints (sipa) -- #9533 `cb598cf` Allow non-power-of-2 signature cache sizes (sipa) -- #9208 `acd9957` Improve DisconnectTip performance (sdaftuar) -- #10618 `f90603a` Remove confusing MAX_BLOCK_BASE_SIZE (gmaxwell) -- #10758 `bd92424` Fix some chainstate-init-order bugs (TheBlueMatt) -- #10550 `b7296bc` Don't return stale data from CCoinsViewCache::Cursor() (ryanofsky) -- #10998 `2507fd5` Fix upgrade cancel warnings (TheBlueMatt) -- #9868 `cbdb473` Abstract out the command line options for block assembly (sipa) - -### Build system -- #9727 `5f0556d` Remove fallbacks for boost_filesystem < v3 (laanwj) -- #9788 `50a2265` gitian: bump descriptors for master (theuni) -- #9794 `7ca2f54` Minor update to qrencode package builder (mitchellcash) -- #9514 `2cc0df1` release: Windows signing script (theuni) -- #9921 `8b789d8` build: Probe MSG_DONTWAIT in the same way as MSG_NOSIGNAL (laanwj) -- #10011 `32d1b34` build: Fix typo s/HAVE_DONTWAIT/HAVE_MSG_DONTWAIT (laanwj) -- #9946 `90dd9e6` Fix build errors if spaces in path or parent directory (pinheadmz) -- #10136 `81da4c7` build: Disable Wshadow warning (laanwj) -- #10166 `64962ae` Ignore Doxyfile generated from Doxyfile.in template (paveljanik) -- #10239 `0416ea9` Make Boost use std::atomic internally (sipa) -- #10228 `27faa6c` build: regenerate bitcoin-config.h as necessary (theuni) -- #10273 `8979f45` [scripts] Minor improvements to `macdeployqtplus` script (chrisgavin) -- #10325 `a26280b` 0.15.0 Depends Updates (fanquake) -- #10328 `79aeff6` Update contrib/debian to latest Ubuntu PPA upload (TheBlueMatt) -- #7522 `d25449f` Bugfix: Only use git for build info if the repository is actually the right one (luke-jr) -- #10489 `e654d61` build: silence gcc7's implicit fallthrough warning (theuni) -- #10549 `ad1a13e` Avoid printing generic and duplicated "checking for QT" during ./configure (drizzt) -- #10628 `8465b68` [depends] expat 2.2.1 (fanquake) -- #10806 `db825d2` build: verify that the assembler can handle crc32 functions (theuni) -- #10766 `b4d03be` Building Environment: Set ARFLAGS to cr (ReneNyffenegger) -- #10803 `91edda8` Explicitly search for bdb5.3 (pstratem) -- #10855 `81560b0` random: only use getentropy on openbsd (theuni) -- #10508 `1caafa6` Run Qt wallet tests on travis (ryanofsky) -- #10851 `e222618` depends: fix fontconfig with newer glibc (theuni) -- #10971 `88b1e4b` build: fix missing sse42 in depends builds (theuni) -- #11097 `129b03f` gitian: quick hack to fix version string in releases (theuni) -- #10039 `919aaf6` Fix compile errors with Qt 5.3.2 and Boost 1.55.0 (ryanofsky) -- #10168 `7032021` Fix build warning from #error text (jnewbery) -- #10301 `318392c` Check if sys/random.h is required for getentropy (jameshilliard) - -### GUI -- #9724 `1a9fd5c` Qt/Intro: Add explanation of IBD process (luke-jr) -- #9834 `b00ba62` qt: clean up initialize/shutdown signals (benma) -- #9481 `ce01e62` [Qt] Show more significant warning if we fall back to the default fee (jonasschnelli) -- #9974 `b9f930b` Add basic Qt wallet test (ryanofsky) -- #9690 `a387d3a` Change 'Clear' button string to 'Reset' (da2x) -- #9592 `9c7b7cf` [Qt] Add checkbox in the GUI to opt-in to RBF when creating a transaction (ryanofsky) -- #10098 `2b477e6` Make qt wallet test compatible with qt4 (ryanofsky) -- #9890 `1fa4ae6` Add a button to open the config file in a text editor (ericshawlinux) -- #10156 `51833a1` Fix for issues with startup and multiple monitors on windows (AllanDoensen) -- #10177 `de01da7` Changed "Send" button default status from true to false (KibbledJiveElkZoo) -- #10221 `e96486c` Stop treating coinbase outputs differently in GUI: show them at 1conf (TheBlueMatt) -- #10231 `987a6c0` [Qt] Reduce a significant cs_main lock freeze (jonasschnelli) -- #10242 `f6f3b58` [qt] Don't call method on null WalletModel object (ryanofsky) -- #10093 `a3e756b` [Qt] Don't add arguments of sensitive command to console window (jonasschnelli) -- #10362 `95546c8` [GUI] Add OSX keystroke to RPCConsole info (spencerlievens) -- #9697 `962cd3f` [Qt] simple fee bumper with user verification (jonasschnelli) -- #10390 `e477516` [wallet] remove minimum total fee option (instagibbs) -- #10420 `4314544` Add Qt tests for wallet spends & bumpfee (ryanofsky) -- #10454 `c1c9a95` Fix broken q4 test build (ryanofsky) -- #10449 `64beb13` Overhaul Qt fee bumper (jonasschnelli) -- #10582 `7c72fb9` Pass in smart fee slider value to coin control dialog (morcos) -- #10673 `4c72cc3` [qt] Avoid potential null pointer dereference in TransactionView::exportClicked() (practicalswift) -- #10769 `8fdd23a` [Qt] replace fee slider with a Dropdown, extend conf. targets (jonasschnelli) -- #10870 `412b466` [Qt] Use wallet 0 in rpc console if running with multiple wallets (jonasschnelli) -- #10988 `a9dd111` qt: Increase BLOCK_CHAIN_SIZE constants (laanwj) -- #10644 `e292140` Slightly overhaul NSI pixmaps (jonasschnelli) -- #10660 `0c3542e` Allow to cancel the txdb upgrade via splashscreen keypress 'q' (jonasschnelli) - -### Wallet -- #9359 `f7ec7cf` Add test for CWalletTx::GetImmatureCredit() returning stale values (ryanofsky) -- #9576 `56ab672` [wallet] Remove redundant initialization (practicalswift) -- #9333 `fa625b0` Document CWalletTx::mapValue entries and remove erase of nonexistent "version" entry (ryanofsky) -- #9906 `72fb515` Disallow copy constructor CReserveKeys (instagibbs) -- #9369 `3178b2c` Factor out CWallet::nTimeSmart computation into a method (ryanofsky) -- #9830 `afcd7c0` Add safe flag to listunspent result (NicolasDorier) -- #9993 `c49355c` Initialize nRelockTime (pstratem) -- #9818 `3d857f3` Save watch only key timestamps when reimporting keys (ryanofsky) -- #9294 `f34cdcb` Use internal HD chain for change outputs (hd split) (jonasschnelli) -- #10164 `e183ea2` Wallet: reduce excess logic InMempool() (kewde) -- #10186 `c9ff4f8` Remove SYNC_TRANSACTION_NOT_IN_BLOCK magic number (jnewbery) -- #10226 `64c45aa` wallet: Use boost to more portably ensure -wallet specifies only a filename (luke-jr) -- #9827 `c91ca0a` Improve ScanForWalletTransactions return value (ryanofsky) -- #9951 `fa1ac28` Wallet database handling abstractions/simplifications (laanwj) -- #10265 `c29a0d4` [wallet] [moveonly] Check non-null pindex before potentially referencing (kallewoof) -- #10283 `a550f6e` Cleanup: reduce to one GetMinimumFee call signature (morcos) -- #10294 `e2b99b1` [Wallet] unset change position when there is no change (instagibbs) -- #10115 `d3dce0e` Avoid reading the old hd master key during wallet encryption (TheBlueMatt) -- #10341 `18c9deb` rpc/wallet: Workaround older UniValue which returns a std::string temporary for get_str (luke-jr) -- #10308 `94e5227` [wallet] Securely erase potentially sensitive keys/values (tjps) -- #10257 `ea1fd43` [test] Add test for getmemoryinfo (jimmysong) -- #10295 `ce8176d` [qt] Move some WalletModel functions into CWallet (ryanofsky) -- #10506 `7cc2c67` Fix bumpfee test after #10449 (ryanofsky) -- #10500 `098b01d` Avoid CWalletTx copies in GetAddressBalances and GetAddressGroupings (ryanofsky) -- #10455 `0747d33` Simplify feebumper minimum fee code slightly (ryanofsky) -- #10522 `2805d60` [wallet] Remove unused variables (practicalswift) -- #8694 `177433a` Basic multiwallet support (luke-jr) -- #10598 `7a74f88` Supress struct/class mismatch warnings introduced in #10284 (paveljanik) -- #9343 `209eef6` Don't create change at dust limit (morcos) -- #10744 `ed88e31` Use method name via __func__ macro (darksh1ne) -- #10712 `e8b9523` Add change output if necessary to reduce excess fee (morcos) -- #10816 `1c011ff` Properly forbid -salvagewallet and -zapwallettxes for multi wallet (morcos) -- #10235 `5cfdda2` Track keypool entries as internal vs external in memory (TheBlueMatt) -- #10330 `bf0a08b` [wallet] fix zapwallettxes interaction with persistent mempool (jnewbery) -- #10831 `0b01935` Batch flushing operations to the walletdb during top up and increase keypool size (gmaxwell) -- #10795 `7b6e8bc` No longer ever reuse keypool indexes (TheBlueMatt) -- #10849 `bde4f93` Multiwallet: simplest endpoint support (jonasschnelli) -- #10817 `9022aa3` Redefine Dust and add a discard_rate (morcos) -- #10883 `bf3b742` Rename -usewallet to -rpcwallet (morcos) -- #10604 `420238d` [wallet] [tests] Add listwallets RPC, include wallet name in `getwalletinfo` and add multiwallet test (jnewbery) -- #10885 `70888a3` Reject invalid wallets (promag) -- #10949 `af56397` Clarify help message for -discardfee (morcos) -- #10942 `2e857bb` Eliminate fee overpaying edge case when subtracting fee from recipients (morcos) -- #10995 `fa64636` Fix resendwallettransactions assert failure if -walletbroadcast=0 (TheBlueMatt) -- #11022 `653a46d` Basic keypool topup (jnewbery) -- #11081 `9fe1f6b` Add length check for CExtKey deserialization (jonasschnelli, guidovranken) -- #11044 `4ef8374` [wallet] Keypool topup cleanups (jnewbery) -- #11145 `e51bb71` Fix rounding bug in calculation of minimum change (morcos) -- #9605 `779f2f9` Use CScheduler for wallet flushing, remove ThreadFlushWalletDB (TheBlueMatt) -- #10108 `4e3efd4` ApproximateBestSubset should take inputs by reference, not value (RHavar) - -### Tests and QA -- #9744 `8efd1c8` Remove unused module from rpc-tests (34ro) -- #9657 `7ff4a53` Improve rpc-tests.py (jnewbery) -- #9766 `7146d96` Add --exclude option to rpc-tests.py (jnewbery) -- #9577 `d6064a8` Fix docstrings in qa tests (jnewbery) -- #9823 `a13a417` qa: Set correct path for binaries in rpc tests (MarcoFalke) -- #9847 `6206252` Extra test vector for BIP32 (sipa) -- #9350 `88c2ae3` [Trivial] Adding label for amount inside of tx_valid/tx_invalid.json (Christewart) -- #9888 `36afd4d` travis: Verify commits only for one target (MarcoFalke) -- #9904 `58861ad` test: Fail if InitBlockIndex fails (laanwj) -- #9828 `67c5cc1` Avoid -Wshadow warnings in wallet_tests (ryanofsky) -- #9832 `48c3429` [qa] assert_start_raises_init_error (NicolasDorier) -- #9739 `9d5fcbf` Fix BIP68 activation test (jnewbery) -- #9547 `d32581c` bench: Assert that division by zero is unreachable (practicalswift) -- #9843 `c78adbf` Fix segwit getblocktemplate test (jnewbery) -- #9929 `d5ce14e` tests: Delete unused function _rpchost_to_args (laanwj) -- #9555 `19be26a` [test] Avoid reading a potentially uninitialized variable in tx_invalid-test (transaction_tests.cpp) (practicalswift) -- #9945 `ac23a7c` Improve logging in bctest.py if there is a formatting mismatch (jnewbery) -- #9768 `8910b47` [qa] Add logging to test_framework.py (jnewbery) -- #9972 `21833f9` Fix extended rpc tests broken by #9768 (jnewbery) -- #9977 `857d1e1` QA: getblocktemplate_longpoll.py should always use >0 fee tx (sdaftuar) -- #9970 `3cc13ea` Improve readability of segwit.py, smartfees.py (sdaftuar) -- #9497 `2c781fb` CCheckQueue Unit Tests (JeremyRubin) -- #10024 `9225de2` [trivial] Use log.info() instead of print() in remaining functional test cases (jnewbery) -- #9956 `3192e52` Reorganise qa directory (jnewbery) -- #10017 `02d64bd` combine_logs.py - aggregates log files from multiple bitcoinds during functional tests (jnewbery) -- #10047 `dfef6b6` [tests] Remove unused variables and imports (practicalswift) -- #9701 `a230b05` Make bumpfee tests less fragile (ryanofsky) -- #10053 `ca20923` [test] Allow functional test cases to be skipped (jnewbery) -- #10052 `a0b1e57` [test] Run extended tests once daily in Travis (jnewbery) -- #10069 `1118493` [QA] Fix typo in fundrawtransaction test (NicolasDorier) -- #10083 `c044f03` [QA] Renaming rawTx into rawtx (NicolasDorier) -- #10073 `b1a4f27` Actually run assumevalid.py (jnewbery) -- #9780 `c412fd8` Suppress noisy output from qa tests in Travis (jnewbery) -- #10096 `79af9fb` Check that all test scripts in test/functional are being run (jnewbery) -- #10076 `5b029aa` [qa] combine_logs: Use ordered list for logfiles (MarcoFalke) -- #10107 `f2734c2` Remove unused variable. Remove accidental trailing semicolons in Python code (practicalswift) -- #10109 `8ac8041` Remove SingleNodeConnCB (jnewbery) -- #10114 `edc62c9` [tests] sync_with_ping should assert that ping hasn't timed out (jnewbery) -- #10128 `427d2fd` Speed Up CuckooCache tests (JeremyRubin) -- #10072 `12af74b` Remove sources of unreliablility in extended functional tests (jnewbery) -- #10077 `ebfd653` [qa] Add setnetworkactive smoke test (MarcoFalke) -- #10152 `080d7c7` [trivial] remove unused line in Travis config (jnewbery) -- #10159 `df1ca9e` [tests] color test results and sort alphabetically (jnewbery) -- #10124 `88799ea` [test] Suppress test logging spam (jnewbery) -- #10142 `ed09dd3` Run bitcoin_test-qt under minimal QPA platform (ryanofsky) -- #9949 `a27dbc5` [bench] Avoid function call arguments which are pointers to uninitialized values (practicalswift) -- #10187 `b44adf9` tests: Fix test_runner return value in case of skipped test (laanwj) -- #10197 `d86bb07` [tests] Functional test warnings (jnewbery) -- #10219 `9111df9` Tests: Order Python Tests Differently (jimmysong) -- #10229 `f3db4c6` Tests: Add test for getdifficulty (jimmysong) -- #10224 `2723bcd` [test] Add test for getaddednodeinfo (jimmysong) -- #10023 `c530c15` [tests] remove maxblocksinflight.py (functionality covered by other test) (jnewbery) -- #10097 `1b25b6d` Move zmq test skipping logic into individual test case (jnewbery) -- #10272 `54e2d87` [Tests] Prevent warning: variable 'x' is uninitialized (paveljanik) -- #10225 `e0a7e19` [test] Add aborttrescan tests (kallewoof) -- #10278 `8254a8a` [test] Add Unit Test for GetListenPort (jimmysong) -- #10280 `47535d7` [test] Unit test amount.h/amount.cpp (jimmysong) -- #10256 `80c3a73` [test] Add test for gettxout to wallet.py (jimmysong) -- #10264 `492d22f` [test] Add tests for getconnectioncount, getnettotals and ping (jimmysong) -- #10169 `8f3e384` [tests] Remove func test code duplication (jnewbery) -- #10198 `dc8fc0c` [tests] Remove is_network_split from functional test framework (jnewbery) -- #10255 `3c5e6c9` [test] Add test for listaddressgroupings (jimmysong) -- #10137 `75171f0` Remove unused import. Remove accidental trailing semicolons (practicalswift) -- #10307 `83073de` [tests] allow zmq test to be run in out-of-tree builds (jnewbery) -- #10344 `e927483` [tests] Fix abandonconflict.py intermittency (jnewbery) -- #10318 `170bc2c` [tests] fix wait_for_inv() (jnewbery) -- #10171 `fff72de` [tests] Add node methods to test framework (jnewbery) -- #10352 `23d78c4` test: Add elapsed time to RPC tracing (laanwj) -- #10342 `6a796b2` [tests] Improve mempool_persist test (jnewbery) -- #10287 `776ba23` [tests] Update Unit Test for addrman.h/addrman.cpp (jimmysong) -- #10365 `7ee5236` [tests] increase timeouts in sendheaders test (jnewbery) -- #10361 `f6241b3` qa: disablewallet: Check that wallet is really disabled (MarcoFalke) -- #10371 `4b766fc` [tests] Clean up addrman_tests.cpp (jimmysong) -- #10253 `87abe20` [test] Add test for getnetworkhashps (jimmysong) -- #10376 `8bd16ee` [tests] fix disconnect_ban intermittency (jnewbery) -- #10374 `5411997` qa: Warn when specified test is not found (MarcoFalke) -- #10405 `0542978` tests: Correct testcase in script_tests.json for large number OP_EQUAL (laanwj) -- #10429 `6b99daf` tests: fix spurious addrman test failure (theuni) -- #10433 `8e57256` [tests] improve tmpdir structure (jnewbery) -- #10415 `217b416` [tests] Speed up fuzzing by ~200x when using afl-fuzz (practicalswift) -- #10445 `b4b057a` Add test for empty chain and reorg consistency for gettxoutsetinfo (gmaxwell) -- #10423 `1aefc94` [tests] skipped tests should clean up after themselves (jnewbery) -- #10359 `329fc1d` [tests] functional tests should call BitcoinTestFramework start/stop node methods (jnewbery) -- #10514 `e103b3f` Bugfix: missing == 0 after randrange (sipa) -- #10515 `c871f32` [test] Add test for getchaintxstats (jimmysong) -- #10509 `bea5b00` Remove xvfb configuration from travis (ryanofsky) -- #10535 `30853e1` [qa] fundrawtx: Fix shutdown race (MarcoFalke) -- #9909 `300f8e7` tests: Add FindEarliestAtLeast test for edge cases (ryanofsky) -- #10331 `75e898c` Share config between util and functional tests (jnewbery) -- #10321 `e801084` Use FastRandomContext for all tests (sipa) -- #10524 `6c2d81f` [tests] Remove printf(...) (practicalswift) -- #10547 `71ab6e5` [tests] Use FastRandomContext instead of boost::random::{mt19937,uniform_int_distribution} (practicalswift) -- #10551 `6702617` [Tests] Wallet encryption functional tests (achow101) -- #10555 `643fa0b` [tests] various improvements to zmq_test.py (jnewbery) -- #10533 `d083bd9` [tests] Use cookie auth instead of rpcuser and rpcpassword (achow101) -- #10632 `c68a9a6` qa: Add stopatheight test (MarcoFalke) -- #10636 `4bc853b` [qa] util: Check return code after closing bitcoind proc (MarcoFalke) -- #10662 `e0a7801` Initialize randomness in benchmarks (achow101) -- #10612 `7c87a9c` The young person's guide to the test_framework (jnewbery) -- #10659 `acb1153` [qa] blockchain: Pass on closed connection during generate call (MarcoFalke) -- #10690 `416af3e` [qa] Bugfix: allow overriding extra_args in ComparisonTestFramework (sdaftuar) -- #10556 `65cc7aa` Move stop/start functions from utils.py into BitcoinTestFramework (jnewbery) -- #10704 `dd07f47` [tests] nits in dbcrash.py (jnewbery) -- #10743 `be82498` [test] don't run dbcrash.py on Travis (jnewbery) -- #10761 `d3b5870` [tests] fix replace_by_fee.py (jnewbery) -- #10759 `1d4805c` Fix multi_rpc test for hosts that dont default to utf8 (TheBlueMatt) -- #10190 `e4f226a` [tests] mining functional tests (including regression test for submitblock) (jnewbery) -- #10739 `1fc783f` test: Move variable `state` down where it is used (paveljanik) -- #9980 `fee0d80` Fix mem access violation merkleblock (Christewart) -- #10893 `0c173a1` [QA] Avoid running multiwallet.py twice (jonasschnelli) -- #10927 `9d5e8f9` test: Make sure wallet.backup is created in temp path (laanwj) -- #10899 `f29d5db` [test] Qt: Use _putenv_s instead of setenv on Windows builds (brianmcmichael) -- #10912 `5c8eb79` [tests] Fix incorrect memory_cleanse(…) call in crypto_tests.cpp (practicalswift) -- #11001 `fa8a063` [tests] Test disconnecting unsupported service bits logic (jnewbery) -- #10695 `929fd72` [qa] Rewrite BIP65/BIP66 functional tests (sdaftuar) -- #10963 `ecd2135` [bench] Restore format state of cout after printing with std::fixed/setprecision (practicalswift) -- #11025 `e5d26e4` qa: Fix inv race in example_test (MarcoFalke) -- #10765 `2c811e0` Tests: address placement should be deterministic by default (ReneNyffenegger) -- #11000 `ac016e1` test: Add resendwallettransactions functional tests (promag) -- #11032 `aeb3175` [qa] Fix block message processing error in sendheaders.py (sdaftuar) -- #10105 `0b9fb68` [tests] fixup - make all Travis test runs quiet, non just cron job runs (jnewbery) -- #10222 `6ce7337` [tests] test_runner - check unicode (jnewbery) -- #10327 `35da2ae` [tests] remove import-abort-rescan.py (jnewbery) -- #11023 `bf74d37` [tests] Add option to attach a python debugger if functional test fails (jnewbery) -- #10565 `8c2098a` [coverage] Remove subtrees and benchmarks from coverage report (achow101) - -### Miscellaneous -- #9871 `be8ba2c` Add a tree sha512 hash to merge commits (sipa) -- #9821 `d19d45a` util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD (laanwj) -- #9903 `ba80a68` Docs: add details to -rpcclienttimeout doc (ian-kelling) -- #9910 `53c300f` Docs: correct and elaborate -rpcbind doc (ian-kelling) -- #9905 `01b7cda` [contrib] gh-merge: Move second sha512 check to the end (MarcoFalke) -- #9880 `4df8213` Verify Tree-SHA512s in merge commits, enforce sigs are not SHA1 (TheBlueMatt) -- #9932 `00c13ea` Fix verify-commits on travis and always check top commit's tree (TheBlueMatt) -- #9952 `6996e06` Add historical release notes for 0.14.0 (laanwj) -- #9940 `fa99663` Fix verify-commits on OSX, update for new bad Tree-SHA512, point travis to different keyservers (TheBlueMatt) -- #9963 `8040ae6` util: Properly handle errors during log message formatting (laanwj) -- #9984 `cce056d` devtools: Make github-merge compute SHA512 from git, instead of worktree (laanwj) -- #9995 `8bcf934` [doc] clarify blockchain size and pruning (askmike) -- #9734 `0c17afc` Add updating of chainTxData to release process (sipa) -- #10063 `530fcbd` add missing spaces so that markdown recognizes headline (flack) -- #10085 `db1ae54` Docs: remove 'noconnect' option (jlopp) -- #10090 `8e4f7e7` Update bitcoin.conf with example for pruning (coinables) -- #9424 `1a5aaab` Change LogAcceptCategory to use uint32_t rather than sets of strings (gmaxwell) -- #10036 `fbf36ca` Fix init README format to render correctly on github (jlopp) -- #10058 `a2cd0b0` No need to use OpenSSL malloc/free (tjps) -- #10123 `471ed00` Allow debug logs to be excluded from specified component (jnewbery) -- #10104 `fadf078` linearize script: Option to use RPC cookie (achow101) -- #10162 `a3a2160` [trivial] Log calls to getblocktemplate (jnewbery) -- #10155 `928695b` build: Deduplicate version numbers (laanwj) -- #10211 `a86255b` [doc] Contributor fixes & new "finding reviewers" section (kallewoof) -- #10250 `1428f30` Fix some empty vector references (sipa) -- #10270 `95f5e44` Remove Clang workaround for Boost 1.46 (fanquake) -- #10263 `cb007e4` Trivial: fix fee estimate write error log message (CryptAxe) -- #9670 `bd9ec0e` contrib: github-merge improvements (laanwj) -- #10260 `1d75597` [doc] Minor corrections to osx dependencies (fanquake) -- #10189 `750c5a5` devtools/net: add a verifier for scriptable changes. Use it to make CNode::id private (theuni) -- #10322 `bc64b5a` Use hardware timestamps in RNG seeding (sipa) -- #10381 `7f2b9e0` Shadowing warnings are not enabled by default, update doc accordingly (paveljanik) -- #10380 `b6ee855` [doc] Removing comments about dirty entries on txmempool (madeo) -- #10383 `d0c37ee` [logging] log system time and mock time (jnewbery) -- #10404 `b45a52a` doc: Add logging to FinalizeNode() (sdaftuar) -- #10388 `526e839` Output line to debug.log when IsInitialBlockDownload latches to false (morcos) -- #10372 `15254e9` Add perf counter data to GetStrongRandBytes state in scheduler (TheBlueMatt) -- #10461 `55b72f3` Update style guide (sipa) -- #10486 `10e8c0a` devtools: Retry after signing fails in github-merge (laanwj) -- #10447 `f259263` Make bitcoind invalid argument error message specific (laanwj) -- #10495 `6a38b79` contrib: Update location of seeds.txt (laanwj) -- #10469 `b6b150b` Fixing typo in rpcdump.cpp help message (keystrike) -- #10451 `27b9931` contrib/init/bitcoind.openrcconf: Don't disable wallet by default (luke-jr) -- #10323 `00d3692` Update to latest libsecp256k1 master (sipa) -- #10422 `cec9e1e` Fix timestamp in fee estimate debug message (morcos) -- #10566 `5d034ee` [docs] Use the "domain name setup" image (previously unused) in the gitian docs (practicalswift) -- #10534 `a514ac3` Clarify prevector::erase and avoid swap-to-clear (sipa) -- #10575 `22ec768` Header include guideline (sipa) -- #10480 `fbf5d3b` Improve commit-check-script.sh (sipa) -- #10502 `1ad3d4e` scripted-diff: Remove BOOST_FOREACH, Q_FOREACH and PAIRTYPE (jtimon) -- #10377 `b63be2c` Use rdrand as entropy source on supported platforms (sipa) -- #9895 `228c319` Turn TryCreateDirectory() into TryCreateDirectories() (benma) -- #10602 `d76e84a` Make clang-format use C++11 features (e.g. A> instead of A >) (practicalswift) -- #10623 `c38f540` doc: Add 0.14.2 release notes (MarcoFalke) -- #10276 `b750b33` contrib/verifybinaries: allow filtering by platform (knocte) -- #10248 `01c4b14` Rewrite addrdb with less duplication using CHashVerifier (sipa) -- #10577 `232508f` Add an explanation of quickly hashing onto a non-power of two range (gmaxwell) -- #10608 `eee398f` Add a comment explaining the use of MAX_BLOCK_BASE_SIZE (gmaxwell) -- #10728 `7397af9` fix typo in help text for removeprunedfunds (AkioNak) -- #10193 `6dbcc74` scripted-diff: Remove #include (jtimon) -- #10676 `379aed0` document script-based return fields for validateaddress (instagibbs) -- #10651 `cef4b5c` Verify binaries from bitcoincore.org and bitcoin.org (TheBlueMatt) -- #10786 `ca4c545` Add PR description to merge commit in github-merge.py (sipa) -- #10812 `c5904e8` [utils] Allow bitcoin-cli's -rpcconnect option to be used with square brackets (jnewbery) -- #10842 `3895e25` Fix incorrect Doxygen tag (@ince → @since). Doxygen parameter name matching (practicalswift) -- #10681 `df0793f` add gdb attach process to test README (instagibbs) -- #10789 `1124328` Punctuation/grammer fixes in rpcwallet.cpp (stevendlander) -- #10655 `78f307b` Properly document target_confirmations in listsinceblock (RHavar) -- #10917 `5c003cb` developer-notes: add reference to snake_case and PascalCase (benma) -- #11003 `4b5a7ce` Docs: Capitalize bullet points in CONTRIBUTING guide (eklitzke) -- #10968 `98aa3f6` Add instructions for parallel gitian builds (coblee) -- #11076 `1c4b9b3` 0.15 release-notes nits: fix redundancy, remove accidental parenthesis & fix range style (practicalswift) -- #11090 `8f0121c` Update contributor names in release-notes.md (Derek701) -- #11056 `cbdd338` disable jni in builds (instagibbs) -- #11080 `2b59cfb` doc: Update build-openbsd for 6.1 (laanwj) -- #11119 `0a6af47` [doc] build-windows: Mention that only trusty works (MarcoFalke) -- #11108 `e8ad101` Changing -txindex requires -reindex, not -reindex-chainstate (TheBlueMatt) -- #9792 `342b9bc` FastRandomContext improvements and switch to ChaCha20 (sipa) -- #9505 `67ed40e` Prevector Quick Destruct (JeremyRubin) -- #10820 `ef37f20` Use cpuid intrinsics instead of asm code (sipa) -- #9999 `a328904` [LevelDB] Plug leveldb logs to bitcoin logs (NicolasDorier) -- #9693 `c5e9e42` Prevent integer overflow in ReadVarInt (gmaxwell) -- #10129 `351d0ad` scheduler: fix sub-second precision with boost < 1.50 (theuni) -- #10153 `fade788` logging: Fix off-by-one for shrinkdebugfile default (MarcoFalke) -- #10305 `c45da32` Fix potential NPD introduced in b297426c (TheBlueMatt) -- #10338 `daf3e7d` Maintain state across GetStrongRandBytes calls (sipa) -- #10544 `a4fe077` Update to LevelDB 1.20 (sipa) -- #10614 `cafe24f` random: fix crash on some 64bit platforms (theuni) -- #10714 `2a09a38` Avoid printing incorrect block indexing time due to uninitialized variable (practicalswift) -- #10837 `8bc6d1f` Fix resource leak on error in GetDevURandom (corebob) -- #10832 `89bb036` init: Factor out AppInitLockDataDirectory and fix startup core dump issue (laanwj) -- #10914 `b995a37` Add missing lock in CScheduler::AreThreadsServicingQueue() (TheBlueMatt) -- #10958 `659c096` Update to latest Bitcoin patches for LevelDB (sipa) -- #10919 `c1c671f` Fix more init bugs (TheBlueMatt) - Credits ======= Thanks to everyone who directly contributed to this release: -- ロハン ダル -- Ahmad Kazi -- aideca -- Akio Nakamura -- Alex Morcos -- Allan Doensen -- Andres G. Aragoneses -- Andrew Chow -- Angel Leon -- Awemany -- Bob McElrath -- Brian McMichael -- BtcDrak -- Charlie Lee -- Chris Gavin -- Chris Stewart -- Cory Fields -- CryptAxe -- Dag Robole -- Daniel Aleksandersen -- Daniel Cousens -- darksh1ne -- Dimitris Tsapakidis -- Eric Shaw -- Evan Klitzke -- fanquake -- Felix Weis -- flack -- Guido Vranken -- Greg Griffith -- Gregory Maxwell -- Gregory Sanders -- Ian Kelling -- Jack Grigg -- James Evans -- James Hilliard -- Jameson Lopp -- Jeremy Rubin -- Jimmy Song -- João Barbosa -- Johnathan Corgan -- John Newbery -- Jonas Schnelli -- Jorge Timón -- Karl-Johan Alm -- kewde -- KibbledJiveElkZoo -- Kirit Thadaka -- kobake -- Kyle Honeycutt -- Lawrence Nahum -- Luke Dashjr -- Marco Falke -- Marcos Mayorga -- Marijn Stollenga -- Mario Dian -- Mark Friedenbach -- Marko Bencun -- Masahiko Hyuga -- Matt Corallo -- Matthew Zipkin -- Matthias Grundmann -- Michael Goldstein -- Michael Rotarius -- Mikerah -- Mike van Rossum -- Mitchell Cash -- Nicolas Dorier -- Patrick Strateman -- Pavel Janík -- Pavlos Antoniou -- Pavol Rusnak -- Pedro Branco -- Peter Todd -- Pieter Wuille -- practicalswift -- René Nyffenegger -- Ricardo Velhote -- romanornr -- Russell Yanofsky -- Rusty Russell -- Ryan Havar -- shaolinfry -- Shigeya Suzuki -- Simone Madeo -- Spencer Lievens -- Steven D. Lander -- Suhas Daftuar -- Takashi Mitsuta -- Thomas Snider -- Timothy Redaelli -- tintinweb -- tnaka -- Warren Togami -- Wladimir J. van der Laan +(fill this in) As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From 46c8d23dad216d990564014f4c8000b79fd36f4e Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 14 Sep 2017 15:32:24 -0400 Subject: [PATCH 027/196] Fix Qt 0.14.2->0.15.0 segfault if "total at least" is selected A button was removed, so now button(1) is nullptr Github-Pull: #11332 Rebased-From: cdaf3a1f9e93be273ebf3e470dc709828c55476c Tree-SHA512: 0a49bf4e9ab08e5869170c8a212da60c9a6b90c36427d788de384aa4be6d87bb5e00a21edf78eed34f81bbc554b6f15565bb9b493dafcbfe9d6f4664d7424d9d --- src/qt/sendcoinsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index a01886c3ea8a..38a475227e55 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -128,7 +128,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p ui->groupFee->setId(ui->radioCustomFee, 1); ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true); ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0); - ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true); + ui->groupCustomFee->button(0)->setChecked(true); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); From 843233277d312f9878c464fb05451b90937b01fc Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 15 Sep 2017 14:58:49 +0200 Subject: [PATCH 028/196] build: Bump version to 0.15.0.1 Tree-SHA512: 7ee9ff3941737aae3086cabcd792c6a00054e911045b4ee198bdc03ffed01328bce504bf7d4fb177e78da8c01812d1a5081dca13e767433aa9ac441e979102e6 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 70033ac0fc7a..71e22dc28cc6 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 15) define(_CLIENT_VERSION_REVISION, 0) -define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2017) define(_COPYRIGHT_HOLDERS,[The %s developers]) From 7123b95bea5b4bb9419ecab316adaca5ed1ef1bd Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 15 Sep 2017 15:20:20 +0200 Subject: [PATCH 029/196] doc: Bump manpages to 0.15.0.1 Tree-SHA512: 8097788934031d0ef47ebac8ddda10e4d124c14e8d0ccee697faba971a68ad7bfcc2f838ae53b1110719ade879743187d170c4d2e69446343c6e2e89febf633c --- doc/man/bitcoin-cli.1 | 17 +++++-- doc/man/bitcoin-qt.1 | 109 ++++++++++++++++++++++++------------------ doc/man/bitcoin-tx.1 | 13 +++-- doc/man/bitcoind.1 | 109 ++++++++++++++++++++++++------------------ 4 files changed, 145 insertions(+), 103 deletions(-) diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1 index 0493241b1e07..c4512c07d25b 100644 --- a/doc/man/bitcoin-cli.1 +++ b/doc/man/bitcoin-cli.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIN-CLI "1" "February 2017" "bitcoin-cli v0.14.99.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH BITCOIN-CLI "1" "September 2017" "bitcoin-cli v0.15.0.1" "User Commands" .SH NAME -bitcoin-cli \- manual page for bitcoin-cli v0.14.99.0 +bitcoin-cli \- manual page for bitcoin-cli v0.15.0.1 .SH DESCRIPTION -Bitcoin Core RPC client version v0.14.99.0 +Bitcoin Core RPC client version v0.15.0.1\-dirty .SS "Usage:" .TP bitcoin\-cli [options] [params] @@ -64,12 +64,19 @@ Password for JSON\-RPC connections .HP \fB\-rpcclienttimeout=\fR .IP -Timeout during HTTP requests (default: 900) +Timeout in seconds during HTTP requests, or 0 for no timeout. (default: +900) .HP \fB\-stdin\fR .IP Read extra arguments from standard input, one per line until EOF/Ctrl\-D (recommended for sensitive information such as passphrases) +.HP +\fB\-rpcwallet=\fR +.IP +Send RPC for non\-default wallet on RPC server (argument is wallet +filename in bitcoind directory, required if bitcoind/\-Qt runs +with multiple wallets) .SH COPYRIGHT Copyright (C) 2009-2017 The Bitcoin Core developers diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1 index ce252612e57a..f83b0b0644fc 100644 --- a/doc/man/bitcoin-qt.1 +++ b/doc/man/bitcoin-qt.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIN-QT "1" "February 2017" "bitcoin-qt v0.14.99.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH BITCOIN-QT "1" "September 2017" "bitcoin-qt v0.15.0.1" "User Commands" .SH NAME -bitcoin-qt \- manual page for bitcoin-qt v0.14.99.0 +bitcoin-qt \- manual page for bitcoin-qt v0.15.0.1 .SH DESCRIPTION -Bitcoin Core version v0.14.99.0 (64\-bit) +Bitcoin Core version v0.15.0.1\-dirty (64\-bit) Usage: .IP bitcoin\-qt [command\-line options] @@ -32,9 +32,9 @@ block hash) If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: -00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90, +0000000000000000003b9ce759c2a087d52abc4266f8f4ebd6d768b89defa50a, testnet: -00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc) +0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1) .HP \fB\-conf=\fR .IP @@ -46,7 +46,7 @@ Specify data directory .HP \fB\-dbcache=\fR .IP -Set database cache size in megabytes (4 to 16384, default: 300) +Set database cache size in megabytes (4 to 16384, default: 450) .HP \fB\-loadblock=\fR .IP @@ -65,6 +65,10 @@ Keep the transaction memory pool below megabytes (default: 300) Do not keep transactions in the mempool longer than hours (default: 336) .HP +\fB\-persistmempool\fR +.IP +Whether to save the mempool on shutdown and load on restart (default: 1) +.HP \fB\-blockreconstructionextratxn=\fR .IP Extra transactions to keep in memory for compact block reconstructions @@ -72,7 +76,7 @@ Extra transactions to keep in memory for compact block reconstructions .HP \fB\-par=\fR .IP -Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 = +Set the number of script verification threads (\fB\-6\fR to 16, 0 = auto, <0 = leave that many cores free, default: 0) .HP \fB\-pid=\fR @@ -131,8 +135,8 @@ for IPv6 .HP \fB\-connect=\fR .IP -Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to -disable automatic connections +Connect only to the specified node(s); \fB\-connect\fR=\fI\,0\/\fR disables automatic +connections .HP \fB\-discover\fR .IP @@ -146,7 +150,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def \fB\-dnsseed\fR .IP Query for peer addresses via DNS lookup, if low on addresses (default: 1 -unless \fB\-connect\fR/\-noconnect) +unless \fB\-connect\fR used) .HP \fB\-externalip=\fR .IP @@ -158,8 +162,7 @@ Always query for peer addresses via DNS lookup (default: 0) .HP \fB\-listen\fR .IP -Accept connections from outside (default: 1 if no \fB\-proxy\fR or -\fB\-connect\fR/\-noconnect) +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) .HP \fB\-listenonion\fR .IP @@ -214,11 +217,6 @@ Connect through SOCKS5 proxy Randomize credentials for every proxy connection. This enables Tor stream isolation (default: 1) .HP -\fB\-rpcserialversion\fR -.IP -Sets the serialization of raw transaction or block hex returned in -non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) -.HP \fB\-seednode=\fR .IP Connect to a node to retrieve peer addresses, and disconnect @@ -253,16 +251,6 @@ 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 .HP -\fB\-whitelistrelay\fR -.IP -Accept relayed transactions received from whitelisted peers even when -not relaying transactions (default: 1) -.HP -\fB\-whitelistforcerelay\fR -.IP -Force relay of transactions from whitelisted peers even if they violate -local relay policy (default: 1) -.HP \fB\-maxuploadtarget=\fR .IP Tries to keep outbound traffic under the given target (in MiB per 24h), @@ -276,13 +264,21 @@ Do not load the wallet and disable wallet RPC calls .HP \fB\-keypool=\fR .IP -Set key pool size to (default: 100) +Set key pool size to (default: 1000) .HP \fB\-fallbackfee=\fR .IP A fee rate (in BTC/kB) that will be used when fee estimation has insufficient data (default: 0.0002) .HP +\fB\-discardfee=\fR +.IP +The fee rate (in BTC/kB) that indicates your tolerance for discarding +change by adding it to the fee (default: 0.0001). Note: An output +is discarded if it is dust at this rate, but we will always +discard up to the dust relay fee and a discard fee above that is +limited by the fee estimate for the longest target +.HP \fB\-mintxfee=\fR .IP Fees (in BTC/kB) smaller than this are considered zero fee for @@ -370,10 +366,16 @@ Append comment to the user agent string .IP Output debugging information (default: 0, supplying is optional). If is not supplied or if = 1, -output all debugging information. can be: addrman, -alert, bench, cmpctblock, coindb, db, http, libevent, lock, -mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, -selectcoins, tor, zmq, qt. +output all debugging information. can be: net, tor, +mempool, http, bench, zmq, db, rpc, estimatefee, addrman, +selectcoins, reindex, cmpctblock, rand, prune, proxy, mempoolrej, +libevent, coindb, qt, leveldb. +.HP +\fB\-debugexclude=\fR +.IP +Exclude debugging information for a category. Can be used in conjunction +with \fB\-debug\fR=\fI\,1\/\fR to output debug logs for all categories except one +or more specified categories. .HP \fB\-help\-debug\fR .IP @@ -387,11 +389,6 @@ Include IP addresses in debug output (default: 0) .IP Prepend debug output with timestamp (default: 1) .HP -\fB\-minrelaytxfee=\fR -.IP -Fees (in BTC/kB) smaller than this are considered zero fee for relaying, -mining and transaction creation (default: 0.00001) -.HP \fB\-maxtxfee=\fR .IP Maximum total fees (in BTC) to use in a single wallet transaction or raw @@ -431,6 +428,21 @@ Maximum size of data in data carrier transactions we relay and mine \fB\-mempoolreplacement\fR .IP Enable transaction replacement in the memory pool (default: 1) +.HP +\fB\-minrelaytxfee=\fR +.IP +Fees (in BTC/kB) smaller than this are considered zero fee for relaying, +mining and transaction creation (default: 0.00001) +.HP +\fB\-whitelistrelay\fR +.IP +Accept relayed transactions received from whitelisted peers even when +not relaying transactions (default: 1) +.HP +\fB\-whitelistforcerelay\fR +.IP +Force relay of transactions from whitelisted peers even if they violate +local relay policy (default: 1) .PP Block creation options: .HP @@ -442,11 +454,6 @@ Set maximum BIP141 block weight (default: 3000000) .IP Set maximum block size in bytes (default: 750000) .HP -\fB\-blockprioritysize=\fR -.IP -Set maximum size of high\-priority/low\-fee transactions in bytes -(default: 0) -.HP \fB\-blockmintxfee=\fR .IP Set lowest fee rate (in BTC/kB) for transactions to be included in block @@ -462,11 +469,14 @@ Accept command line and JSON\-RPC commands .IP Accept public REST requests (default: 0) .HP -\fB\-rpcbind=\fR +\fB\-rpcbind=\fR[:port] .IP -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) +Bind to given address to listen for JSON\-RPC connections. This option is +ignored unless \fB\-rpcallowip\fR is also passed. Port is optional and +overrides \fB\-rpcport\fR. Use [host]:port notation for IPv6. This +option can be specified multiple times (default: 127.0.0.1 and +::1 i.e., localhost, or if \fB\-rpcallowip\fR has been specified, +0.0.0.0 and :: i.e., all addresses) .HP \fB\-rpccookiefile=\fR .IP @@ -501,6 +511,11 @@ 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 .HP +\fB\-rpcserialversion\fR +.IP +Sets the serialization of raw transaction or block hex returned in +non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) +.HP \fB\-rpcthreads=\fR .IP Set the number of threads to service RPC calls (default: 4) diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1 index 98adf2f5b1e5..82f124aaacd1 100644 --- a/doc/man/bitcoin-tx.1 +++ b/doc/man/bitcoin-tx.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIN-TX "1" "February 2017" "bitcoin-tx v0.14.99.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH BITCOIN-TX "1" "September 2017" "bitcoin-tx v0.15.0.1" "User Commands" .SH NAME -bitcoin-tx \- manual page for bitcoin-tx v0.14.99.0 +bitcoin-tx \- manual page for bitcoin-tx v0.15.0.1 .SH DESCRIPTION -Bitcoin Core bitcoin\-tx utility version v0.14.99.0 +Bitcoin Core bitcoin\-tx utility version v0.15.0.1\-dirty .SS "Usage:" .TP bitcoin\-tx [options] [commands] @@ -63,6 +63,11 @@ nversion=N .IP Set TX version to N .IP +replaceable(=N) +.IP +Set RBF opt\-in sequence number for input N (if not provided, opt\-in all +available inputs) +.IP outaddr=VALUE:ADDRESS .IP Add address\-based output to TX diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1 index fb066e0c6f31..4a88d7a179d2 100644 --- a/doc/man/bitcoind.1 +++ b/doc/man/bitcoind.1 @@ -1,9 +1,9 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH BITCOIND "1" "February 2017" "bitcoind v0.14.99.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH BITCOIND "1" "September 2017" "bitcoind v0.15.0.1" "User Commands" .SH NAME -bitcoind \- manual page for bitcoind v0.14.99.0 +bitcoind \- manual page for bitcoind v0.15.0.1 .SH DESCRIPTION -Bitcoin Core Daemon version v0.14.99.0 +Bitcoin Core Daemon version v0.15.0.1\-dirty .SS "Usage:" .TP bitcoind [options] @@ -33,9 +33,9 @@ block hash) If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: -00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90, +0000000000000000003b9ce759c2a087d52abc4266f8f4ebd6d768b89defa50a, testnet: -00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc) +0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1) .HP \fB\-conf=\fR .IP @@ -51,7 +51,7 @@ Specify data directory .HP \fB\-dbcache=\fR .IP -Set database cache size in megabytes (4 to 16384, default: 300) +Set database cache size in megabytes (4 to 16384, default: 450) .HP \fB\-loadblock=\fR .IP @@ -70,6 +70,10 @@ Keep the transaction memory pool below megabytes (default: 300) Do not keep transactions in the mempool longer than hours (default: 336) .HP +\fB\-persistmempool\fR +.IP +Whether to save the mempool on shutdown and load on restart (default: 1) +.HP \fB\-blockreconstructionextratxn=\fR .IP Extra transactions to keep in memory for compact block reconstructions @@ -77,7 +81,7 @@ Extra transactions to keep in memory for compact block reconstructions .HP \fB\-par=\fR .IP -Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 = +Set the number of script verification threads (\fB\-6\fR to 16, 0 = auto, <0 = leave that many cores free, default: 0) .HP \fB\-pid=\fR @@ -136,8 +140,8 @@ for IPv6 .HP \fB\-connect=\fR .IP -Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to -disable automatic connections +Connect only to the specified node(s); \fB\-connect\fR=\fI\,0\/\fR disables automatic +connections .HP \fB\-discover\fR .IP @@ -151,7 +155,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def \fB\-dnsseed\fR .IP Query for peer addresses via DNS lookup, if low on addresses (default: 1 -unless \fB\-connect\fR/\-noconnect) +unless \fB\-connect\fR used) .HP \fB\-externalip=\fR .IP @@ -163,8 +167,7 @@ Always query for peer addresses via DNS lookup (default: 0) .HP \fB\-listen\fR .IP -Accept connections from outside (default: 1 if no \fB\-proxy\fR or -\fB\-connect\fR/\-noconnect) +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) .HP \fB\-listenonion\fR .IP @@ -219,11 +222,6 @@ Connect through SOCKS5 proxy Randomize credentials for every proxy connection. This enables Tor stream isolation (default: 1) .HP -\fB\-rpcserialversion\fR -.IP -Sets the serialization of raw transaction or block hex returned in -non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) -.HP \fB\-seednode=\fR .IP Connect to a node to retrieve peer addresses, and disconnect @@ -258,16 +256,6 @@ 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 .HP -\fB\-whitelistrelay\fR -.IP -Accept relayed transactions received from whitelisted peers even when -not relaying transactions (default: 1) -.HP -\fB\-whitelistforcerelay\fR -.IP -Force relay of transactions from whitelisted peers even if they violate -local relay policy (default: 1) -.HP \fB\-maxuploadtarget=\fR .IP Tries to keep outbound traffic under the given target (in MiB per 24h), @@ -281,13 +269,21 @@ Do not load the wallet and disable wallet RPC calls .HP \fB\-keypool=\fR .IP -Set key pool size to (default: 100) +Set key pool size to (default: 1000) .HP \fB\-fallbackfee=\fR .IP A fee rate (in BTC/kB) that will be used when fee estimation has insufficient data (default: 0.0002) .HP +\fB\-discardfee=\fR +.IP +The fee rate (in BTC/kB) that indicates your tolerance for discarding +change by adding it to the fee (default: 0.0001). Note: An output +is discarded if it is dust at this rate, but we will always +discard up to the dust relay fee and a discard fee above that is +limited by the fee estimate for the longest target +.HP \fB\-mintxfee=\fR .IP Fees (in BTC/kB) smaller than this are considered zero fee for @@ -375,10 +371,16 @@ Append comment to the user agent string .IP Output debugging information (default: 0, supplying is optional). If is not supplied or if = 1, -output all debugging information. can be: addrman, -alert, bench, cmpctblock, coindb, db, http, libevent, lock, -mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, -selectcoins, tor, zmq. +output all debugging information. can be: net, tor, +mempool, http, bench, zmq, db, rpc, estimatefee, addrman, +selectcoins, reindex, cmpctblock, rand, prune, proxy, mempoolrej, +libevent, coindb, qt, leveldb. +.HP +\fB\-debugexclude=\fR +.IP +Exclude debugging information for a category. Can be used in conjunction +with \fB\-debug\fR=\fI\,1\/\fR to output debug logs for all categories except one +or more specified categories. .HP \fB\-help\-debug\fR .IP @@ -392,11 +394,6 @@ Include IP addresses in debug output (default: 0) .IP Prepend debug output with timestamp (default: 1) .HP -\fB\-minrelaytxfee=\fR -.IP -Fees (in BTC/kB) smaller than this are considered zero fee for relaying, -mining and transaction creation (default: 0.00001) -.HP \fB\-maxtxfee=\fR .IP Maximum total fees (in BTC) to use in a single wallet transaction or raw @@ -436,6 +433,21 @@ Maximum size of data in data carrier transactions we relay and mine \fB\-mempoolreplacement\fR .IP Enable transaction replacement in the memory pool (default: 1) +.HP +\fB\-minrelaytxfee=\fR +.IP +Fees (in BTC/kB) smaller than this are considered zero fee for relaying, +mining and transaction creation (default: 0.00001) +.HP +\fB\-whitelistrelay\fR +.IP +Accept relayed transactions received from whitelisted peers even when +not relaying transactions (default: 1) +.HP +\fB\-whitelistforcerelay\fR +.IP +Force relay of transactions from whitelisted peers even if they violate +local relay policy (default: 1) .PP Block creation options: .HP @@ -447,11 +459,6 @@ Set maximum BIP141 block weight (default: 3000000) .IP Set maximum block size in bytes (default: 750000) .HP -\fB\-blockprioritysize=\fR -.IP -Set maximum size of high\-priority/low\-fee transactions in bytes -(default: 0) -.HP \fB\-blockmintxfee=\fR .IP Set lowest fee rate (in BTC/kB) for transactions to be included in block @@ -467,11 +474,14 @@ Accept command line and JSON\-RPC commands .IP Accept public REST requests (default: 0) .HP -\fB\-rpcbind=\fR +\fB\-rpcbind=\fR[:port] .IP -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) +Bind to given address to listen for JSON\-RPC connections. This option is +ignored unless \fB\-rpcallowip\fR is also passed. Port is optional and +overrides \fB\-rpcport\fR. Use [host]:port notation for IPv6. This +option can be specified multiple times (default: 127.0.0.1 and +::1 i.e., localhost, or if \fB\-rpcallowip\fR has been specified, +0.0.0.0 and :: i.e., all addresses) .HP \fB\-rpccookiefile=\fR .IP @@ -506,6 +516,11 @@ 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 .HP +\fB\-rpcserialversion\fR +.IP +Sets the serialization of raw transaction or block hex returned in +non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1) +.HP \fB\-rpcthreads=\fR .IP Set the number of threads to service RPC calls (default: 4) From f266f2668bf8fd73015bf8265f0d00f5e858b577 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 15 Sep 2017 13:37:22 +0000 Subject: [PATCH 030/196] qt: Translations update pre-0.15.0.1 Tree-SHA512: 942fbba8a959ec5430afeecbb663731944fd646fa3b997252e599d835faff12f329d1b70509b161275c3c88845de031357c8317d7f7c801e24be488912cf4035 --- src/qt/locale/bitcoin_de.ts | 2 +- src/qt/locale/bitcoin_es_ES.ts | 38 +- src/qt/locale/bitcoin_hu.ts | 1621 ++++++++++++++++++++++++++++++-- src/qt/locale/bitcoin_it.ts | 30 +- src/qt/locale/bitcoin_nb.ts | 8 + src/qt/locale/bitcoin_nl.ts | 4 +- src/qt/locale/bitcoin_pt_PT.ts | 52 +- src/qt/locale/bitcoin_ro_RO.ts | 108 +++ src/qt/locale/bitcoin_th.ts | 16 + src/qt/locale/bitcoin_tr_TR.ts | 24 +- src/qt/locale/bitcoin_zh_CN.ts | 114 ++- 11 files changed, 1897 insertions(+), 120 deletions(-) diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index dcd228600546..d6f4ee2f744c 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -3067,7 +3067,7 @@ Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d) - Geben Sie immer die Transaktionen, die Sie von freigegebenen Peers erhalten haben, weiter (Voreinstellung: %d) + Immer übermittelte Transaktionen von freigegebenen Peers akzeptieren, auch wenn keine Transaktionen übermittelt werden (Standard: %d) Bind to given address and always listen on it. Use [host]:port notation for IPv6 diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts index 1413cc1adf58..aaeccb825969 100644 --- a/src/qt/locale/bitcoin_es_ES.ts +++ b/src/qt/locale/bitcoin_es_ES.ts @@ -3,23 +3,23 @@ AddressBookPage Right-click to edit address or label - Haz clic derecho para editar la dirección o etiqueta + Haga clic en el botón derecho para editar la dirección o etiqueta Create a new address - Crear una nueva dirección + Cree una nueva dirección &New - &Nuevo + Y Nuevo Copy the currently selected address to the system clipboard - Copiar la dirección seleccionada al portapapeles del sistema + Copie la dirección seleccionada al portapapeles del sistema &Copy - &Copiar + Y Copiar C&lose @@ -27,19 +27,19 @@ Delete the currently selected address from the list - Eliminar la dirección seleccionada de la lista + Elimine la dirección seleccionada de la lista Export the data in the current tab to a file - Exportar los datos en la ficha actual a un archivo + Exporte los datos en la ficha actual a un archivo &Export - &Exportar + Y Exportar &Delete - &Eliminar + Y Eliminar Choose the address to send coins to @@ -55,15 +55,15 @@ Sending addresses - Enviando direcciones + Direcciones para hacer pagos Receiving addresses - Recibiendo direcciones + Direcciones para recibir pagos 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 recepción antes de enviar monedas. + Estas son sus direcciones Bitcoin para enviar pagos. Verifique siempre la cantidad y la dirección de destino antes de enviar monedas. These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. @@ -87,15 +87,15 @@ Comma separated file (*.csv) - Archivo separado de coma (*.csv) + Archivo separado mediante coma (*.csv) Exporting Failed - Falló la exportación + No se ha podido completar 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. + Se ha producido un error intentando guardar la lista de direcciones en %1. Por favor inténtelo de nuevo. @@ -117,15 +117,15 @@ AskPassphraseDialog Passphrase Dialog - Diálogo de contraseña + Cuadro de diálogo de la frase de contraseña Enter passphrase - Introducir contraseña + Introduzca frase de contraseña New passphrase - Nueva contraseña + Repita la nueva frase de contraseña Repeat new passphrase @@ -137,7 +137,7 @@ Encrypt wallet - Monedero encriptado + Encripte el Monedero This operation needs your wallet passphrase to unlock the wallet. diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index 5c98319c6bd3..15afc2e665c5 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -41,10 +41,58 @@ &Delete &Törlés + + Choose the address to send coins to + Válassza ki a címet küldéshez + + + Choose the address to receive coins with + Válassza ki a címet fogadáshoz + + + C&hoose + K&iválaszt + + + Sending addresses + Küldési cím + + + Receiving addresses + Fogadási cím + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Ezek a Bitcoin címeid kifizetések küldéséhez. Mindíg ellenőrizd az összeget és a fogadó címet mielőtt coinokat küldenél. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Ezek a Bitcoin címeid kifizetések fogadásához. Ajánlott új címet használni minden új fogadáshoz. + &Copy Address &Cím másolása + + Copy &Label + Másolás és Címkézés + + + &Edit + Szerkesztés + + + Export Address List + Címlista exportálása + + + Comma separated file (*.csv) + Vesszővel elválasztott adatokat tartalmazó fájl + + + Exporting Failed + Hiba az exportálás során + AddressTableModel @@ -52,7 +100,15 @@ Label Címke - + + Address + Cím + + + (no label) + (nincs címke) + + AskPassphraseDialog @@ -71,11 +127,96 @@ Repeat new passphrase Új jelszó újra + + 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>. + Gépelje be az új kulcsmondatot a pénztárcához.<br/> +Kérem a kulcsmondatban használjon <b> tíz vagy több véletlenszerű karaktert </b>, vagy <b> nyolc vagy több szót </b>. + + + Encrypt wallet + Tárca titkosítása + + + This operation needs your wallet passphrase to unlock the wallet. + Ehhez a művelethez szükség van a tárcához tartozó kulcsmondathoz, hogy kinyithassa azt. + + + Unlock wallet + Tárca kinyitása + + + This operation needs your wallet passphrase to decrypt the wallet. + Ehhez a művelethez szükség van a tárcához tartozó kulcsmondathoz, hogy a titkosítás megszűnjön. + Decrypt wallet Tárca dekódolása - + + Change passphrase + Kulcsmondat megváltoztatása + + + Enter the old passphrase and new passphrase to the wallet. + Gépelje be a tárcához tartozó régi, és új kulcsmondatot + + + Confirm wallet encryption + Tárca titkosításának megerősítése + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Figyelem: Ha titkosítja a tárcáját és elveszíti a jelszavát, akkor <b>AZ ÖSSZES BITCOINJA ELVESZIK</b>! + + + Are you sure you wish to encrypt your wallet? + Biztosan titkosítani akarja a tárcát? + + + Wallet encrypted + Tárca titkosítva + + + %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. + A %1 most bezár, hogy befejezze a titkosítást. Ne feledje, hogy a tárca titkosítása nem nyújt teljes védelmet azzal szemben, hogy kártékony programok megfertőzzék a számítógépét és ellopják a bitcoinjait. + + + 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. + FONTOS: A tárca-fájl minden korábbi biztonsági mentését cserélje le ezzel az újonnan generált, titkosított tárca-fájllal. Biztonsági okokból a tárca-fájl korábbi, titkosítás nélküli mentései használhatatlanná válnak, amint elkezdi használni az új, titkosított tárcát. + + + Wallet encryption failed + A tárca titkosítása sikertelen. + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Tárca titkosítása belső hiba miatt sikertelen. A tárcád nem lett titkosítva. + + + The supplied passphrases do not match. + A megadott jelszavak nem egyeznek. + + + Wallet unlock failed + Tárca megnyitása sikertelen + + + The passphrase entered for the wallet decryption was incorrect. + A tárca titkosításának feloldásához megadott jelszó helytelen. + + + Wallet decryption failed + Tárca titkosításának feloldása sikertelen + + + Wallet passphrase was successfully changed. + Tárca jelszava sikeresen megváltoztatva. + + + Warning: The Caps Lock key is on! + Vigyázat: a Caps Lock be van kapcsolva! + + BanTableModel @@ -129,6 +270,10 @@ &About %1 &A %1-ról + + Show information about %1 + %1 információ megjelenítése + About &Qt A &Qt-ról @@ -141,6 +286,10 @@ &Options... &Opciók... + + Modify configuration options for %1 + %1 beállítások módosítása + &Encrypt Wallet... Tárca &titkosítása... @@ -165,6 +314,18 @@ Open &URI... &URI azonosító megnyitása... + + Click to disable network activity. + Kattintson a hálózati tevékenység letiltásához. + + + Network activity disabled. + Hálózati tevékenység letiltva. + + + Click to enable network activity again. + Kattintson a hálózati tevékenység újbóli engedélyezéséhez. + Reindexing blocks on disk... Lemezen lévő blokkok újraindexelése... @@ -269,6 +430,14 @@ %n active connection(s) to Bitcoin network %n aktív kapcsolat a Bitcoin hálózathoz%n aktív kapcsolat a Bitcoin hálózathoz + + Indexing blocks on disk... + Lemezen lévő blokkok indexelése... + + + Processing blocks on disk... + Lemezen lévő blokkok feldolgozása... + Processed %n block(s) of transaction history. %n blokk feldolgozva a tranzakció előzményből.%n blokk feldolgozva a tranzakció előzményből. @@ -301,6 +470,18 @@ Up to date Naprakész + + Show the %1 help message to get a list with possible Bitcoin command-line options + A %1 súgó megjelenítése a Bitcoin lehetséges parancssori kapcsolóinak listájával + + + %1 client + %1 kliens + + + Connecting to peers... + Csatlakozás párokhoz... + Catching up... Frissítés... @@ -343,6 +524,14 @@ Incoming transaction Beérkező tranzakció + + HD key generation is <b>enabled</b> + HD kulcs generálás <b>engedélyezett</b> + + + HD key generation is <b>disabled</b> + HD kulcs generálás <b>tiltva</b> + Wallet is <b>encrypted</b> and currently <b>unlocked</b> A tárca <b>titkosítva</b> és jelenleg <b>nyitva</b>. @@ -351,7 +540,11 @@ Wallet is <b>encrypted</b> and currently <b>locked</b> Tárca <b>kódolva</b> és jelenleg <b>zárva</b>. - + + A fatal error occurred. Bitcoin can no longer continue safely and will quit. + Végzetes hiba történt. A Bitcoin működése nem biztonságos és hamarosan leáll. + + CoinControlDialog @@ -422,7 +615,83 @@ Confirmed Megerősítve - + + Copy address + Cím másolása + + + Copy label + Címke másolása + + + Copy amount + Összeg másolása + + + Copy transaction ID + Tranzakció azonosító másolása + + + Lock unspent + Elköltetlen összeg zárolása + + + Unlock unspent + Elköltetlen összeg zárolásának a feloldása + + + Copy quantity + Mennyiség másolása + + + Copy fee + Díj másolása + + + Copy bytes + Byte-ok másolása + + + Copy dust + Porszemek másolása + + + Copy change + Visszajáró másolása + + + (%1 locked) + (%1 zárolva) + + + yes + igen + + + no + nem + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Ez a címke pirosra változik, ha bármely fogadóhoz, a porszem határértéknél kevesebb összeg érkezik. + + + Can vary +/- %1 satoshi(s) per input. + Megadott értékenként +/- %1 satoshi-val változhat. + + + (no label) + (nincs címke) + + + change from %1 (%2) + visszajáró %1-ből (%2) + + + (change) + (visszajáró) + + EditAddressDialog @@ -445,7 +714,39 @@ &Address &Cím - + + New receiving address + Új fogadó cím + + + New sending address + Új küldő cím + + + Edit receiving address + Fogadó cím szerkesztése + + + Edit sending address + Küldő cím szerkesztése + + + The entered address "%1" is not a valid Bitcoin address. + A megadott "%1" cím nem egy érvényes Bitcoin-cím. + + + The entered address "%1" is already in the address book. + A megadott "%1" cím már szerepel a címjegyzékben. + + + Could not unlock wallet. + Tárca feloldása sikertelen + + + New key generation failed. + Új kulcs generálása sikertelen. + + FreespaceChecker @@ -475,6 +776,10 @@ (%1-bit) (%1-bit) + + About %1 + A %1 -ról + Command-line options Parancssoros opciók @@ -487,13 +792,49 @@ command-line options parancssoros opciók - + + UI Options: + Kezelőfelület beállításai: + + + Choose data directory on startup (default: %u) + Adatkönyvtár kiválasztása induláskor (alapértelmezett: %u) + + + Set language, for example "de_DE" (default: system locale) + Nyelvbeállítás, például "de_DE" (alapértelmezett: rendszer nyelve) + + + Start minimized + Indítás lekicsinyítve + + + Set SSL root certificates for payment request (default: -system-) + SLL gyökér-igazolások megadása fizetési kérelmekhez (alapértelmezett: -system-) + + + Show splash screen on startup (default: %u) + Indítóképernyő mutatása induláskor (alapértelmezett: %u) + + + Reset all settings changed in the GUI + A grafikus felület összes megváltoztatott beállításának a visszaállítása + + Intro Welcome Üdvözlünk + + Welcome to %1. + Üdvözlünk a %1 -ban. + + + As this is the first time the program is launched, you can choose where %1 will store its data. + Mivel ez a program első indulása, megváltoztathatja, hogy a %1 hova mentse az adatokat. + Use the default data directory Az alapértelmezett adat könyvtár használata @@ -521,15 +862,51 @@ Form Űrlap + + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. + A legutóbbi tranzakciók még lehet, hogy nem látszanak, ezért előfordulhat, hogy a pénztárca egyenlege nem a valós állapotot mutatja. Ha a pénztárca befejezte a szinkronizációt a bitcoin hálózattal, utána már az aktuális egyenleget fogja mutatni, amint alant részletesen látszik. + + + Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network. + A hálózat nem fogadja el azoknak a bitcoinoknak az elköltését, amelyek érintettek a még nem látszódó tranzakciókban. + + + Number of blocks left + Hátralévő blokkok száma + + + Unknown... + Ismeretlen... + Last block time Utolsó blokk ideje + + Progress + Folyamat + + + Progress increase per hour + A folyamat előrehaladása óránként + + + calculating... + számítás folyamatban... + + + Estimated time left until synced + Hozzávetőlegesen a hátralévő idő a szinkronizáció befejezéséig + Hide Elrejtés - + + Unknown. Syncing Headers (%1)... + Ismeretlen. Fejlécek szinkronizálása (%1)... + + OpenURIDialog @@ -548,7 +925,11 @@ Select payment request file Fizetési kérelmi fájl kiválasztása - + + Select payment request file to open + Válassza ki a megnyitni kívánt fizetési kérelem fájlt + + OptionsDialog @@ -559,6 +940,14 @@ &Main &Fő + + Automatically start %1 after logging in to the system. + %1 automatikus indítása a rendszerbe való belépés után. + + + &Start %1 on system login + &Induljon el a %1 a rendszerbe való belépéskor + Size of &database cache A&datbázis gyorsítótár mérete @@ -567,6 +956,10 @@ MB MB + + Number of script &verification threads + A szkript &igazolási szálak száma + Accept connections from outside Külső kapcsolatok elfogadása @@ -579,10 +972,22 @@ IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) A proxy IP címe (pl.: 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. + Az alkalmazásból való kilépés helyett az eszköztárba kicsinyíti az alkalmazást az ablak bezárásakor. Ez esetben az alkalmazás csak a Kilépés menüponttal zárható be. + + + 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 |. + Harmadik féltől származó URL-ek (pl. egy blokk felfedező) amelyek a tranzakciós fülön jelennek meg mint a környezetérzékeny menü tételei. %s az URL-ben helyettesítve a tranzakciós hash-el. Több URL esetén, függőleges vonal választja el őket. + Third party transaction URLs Harmadik fél tranzakció URL-ek + + Active command-line options that override above options: + Aktív parancssori beállítások, melyek felülírják a fenti beállításokat: + Reset all client options to default. Minden kliensbeállítás alapértelmezettre állítása. @@ -595,6 +1000,10 @@ &Network &Hálózat + + (0 = auto, <0 = leave that many cores free) + (0 = automatikus, <0 = ennyi processzormagot hagyjon szabadon) + W&allet T&árca @@ -603,6 +1012,18 @@ Expert Szakértő + + Enable coin &control features + Pénzküldés beállításainak engedélyezése + + + 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. + Ha letiltja a jóváhagyatlan változások elköltését, akkor egy tranzakcióból származó változást nem lehet használni, amíg legalább egy jóváhagyás nem történik. Ez befolyásolja az egyenlegének a kiszámítását is. + + + &Spend unconfirmed change + &Költése a a jóváhagyatlan változásnak + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. A Bitcoin-kliens portjának automatikus megnyitása a routeren. Ez csak akkor működik, ha a routered támogatja az UPnP-t és az engedélyezve is van rajta. @@ -615,6 +1036,10 @@ Connect to the Bitcoin network through a SOCKS5 proxy. Csatlakozás a Bitcoin hálózatához SOCKS5 proxyn keresztül + + &Connect through SOCKS5 proxy (default proxy): + &Kapcsolódás SOCKS5 proxyn keresztül (alapértelmezett proxy): + Proxy &IP: Proxy &IP: @@ -627,6 +1052,10 @@ Port of the proxy (e.g. 9050) Proxy portja (pl.: 9050) + + Used for reaching peers via: + Párok elérésére használjuk ezen keresztül: + IPv4 IPv4 @@ -639,10 +1068,26 @@ Tor Tor + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Csatlakozás a Bitcoin hálózathoz külön SOCKS5 proxy használatával a Tor rejtett szolgáltatásainak eléréséhez. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Más SOCKS5 proxy használata a párok eléréséhez, a Tor rejtett szolgáltatásain keresztül: + &Window &Ablak + + &Hide the icon from the system tray. + &Rejtse el az ikont a rendszer tálcáról. + + + Hide tray icon + Tálcaikon elrejtése + Show only a tray icon after minimizing the window. Kicsinyítés után csak eszköztár-ikont mutass @@ -663,6 +1108,10 @@ User Interface &language: Felhasználófelület nye&lve: + + The user interface language can be set here. This setting will take effect after restarting %1. + A felhasználói felület nyelvét tudja itt beállítani. Ez a beállítás csak a %1 újraindítása után lép életbe. + &Unit to show amounts in: &Mértékegység: @@ -671,6 +1120,10 @@ Choose the default subdivision unit to show in the interface and when sending coins. Válaszd ki az interfészen és érmék küldésekor megjelenítendő alapértelmezett alegységet. + + Whether to show coin control features or not. + Mutassa a pénzküldés beállításait vagy ne. + &OK &OK @@ -695,6 +1148,14 @@ Client restart required to activate changes. A változtatások aktiválásahoz újra kell indítani a klienst. + + Client will be shut down. Do you want to proceed? + A kliens le fog állni. Szeretné folytatni? + + + This change would require a client restart. + Ehhez a változtatáshoz újra kellene indítani a klienst. + The supplied proxy address is invalid. A megadott proxy cím nem érvényes. @@ -750,6 +1211,10 @@ Your current total balance Aktuális egyenleged + + Your current balance in watch-only addresses + A csak megfigyelt címeinek az egyenlege + Spendable: Elkölthető: @@ -758,17 +1223,121 @@ Recent transactions A legutóbbi tranzakciók - - - PaymentServer - - - PeerTableModel - User Agent - User Agent + Unconfirmed transactions to watch-only addresses + A csak megfigyelt címek hitelesítetlen tranzakciói - + + Mined balance in watch-only addresses that has not yet matured + A csak megfigyelt címek bányászott, még éretlen egyenlege + + + Current total balance in watch-only addresses + A csak megfigyelt címek jelenlegi teljes egyenlege + + + + PaymentServer + + Payment request error + Hiba történt a fizetési kérelem során + + + Cannot start bitcoin: click-to-pay handler + A bitcoin nem tud elindulni: click-to-pay kezelő + + + URI handling + URI kezelés + + + Invalid payment address %1 + Érvénytelen fizetési cím %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + Nem sikerült az URI elemzése! Ezt okozhatja érvénytelen Bitcoin cím, vagy rossz URI paraméterezés. + + + Payment request file handling + Fizetés kérelmi fájl kezelése + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Nem sikerült beolvasni a fizetési kérelmi fájlt! Ezt érvénytelen fizetési kérelmi fájl okozhatja. + + + Payment request rejected + A fizetési kérelem visszautasítva + + + Payment request network doesn't match client network. + A fizetési kérelmi hálózat nem egyezik a kliens hálózatával. + + + Payment request expired. + A fizetési kérelem lejárt. + + + Payment request is not initialized. + A fizetési kérelem nem inicializálódott + + + Invalid payment request. + Érvénytelen fizetési kérelem + + + Requested payment amount of %1 is too small (considered dust). + A %1 fizetésre kért összege túl kevés (porszemnek minősül). + + + Refund from %1 + Visszatérítés a %1 -tól + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + A fizetési kérelem %1 túl nagy (%2 byte, csak %3 byte engedélyezett). + + + Error communicating with %1: %2 + Hiba a kommuniáció során %1 -el: %2 + + + Payment request cannot be parsed! + Nem sikerült elemezni a fizetési kérelmet! + + + Bad response from server %1 + Rossz válasz a kiszolgálótól %1 + + + Network request error + Hálózati kérelem hiba + + + Payment acknowledged + Fizetés elfogadva + + + + PeerTableModel + + User Agent + User Agent + + + Node/Service + Csomópont/Szolgáltatás + + + NodeId + Csomópont Azonosító + + + Ping + Ping + + QObject @@ -811,13 +1380,41 @@ %1 and %2 %1 és %2 - + + %1 didn't yet exit safely... + %1 még nem lépett ki biztonságosan... + + QObject::QObject - + + Error: Specified data directory "%1" does not exist. + Hiba: A megadott "%1" adatkönyvtár nem létezik. + + + Error: %1 + Hiba: %1 + + QRImageWidget - + + &Save Image... + &Kép Mentése + + + &Copy Image + &Kép Másolása + + + Save QR Code + QR Kód Mentése + + + PNG Image (*.png) + PNG kép (*.png) + + RPCConsole @@ -844,6 +1441,10 @@ Using BerkeleyDB version Használt BerkeleyDB verzió + + Datadir + Adatkönyvtár + Startup time Bekapcsolás ideje @@ -868,6 +1469,14 @@ Current number of blocks Aktuális blokkok száma + + Memory Pool + Memória Halom + + + Current number of transactions + Jelenlegi tranzakciók száma + Memory usage Memóriahasználat @@ -892,14 +1501,46 @@ Select a peer to view detailed information. Peer kijelölése a részletes információkért + + Whitelisted + Engedélyezett + + + Direction + Irány + Version Verzió + + Starting Block + Kezdő Blokk + + + Synced Headers + Szinkronizált Fejlécek + + + Synced Blocks + Szinkronizált Blokkok + 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. + A %1 debug log fájl megnyitása a jelenlegi könyvtárból. Ez néhány másodpercig eltarthat nagyobb log fájlok esetén. + + + Decrease font size + Betűméret kicsinyítése + + + Increase font size + Betűméret növelése + Services Szolgáltatások @@ -920,6 +1561,22 @@ Ping Time Ping idő + + The duration of a currently outstanding ping. + A jelenlegi kiváló ping időtartama. + + + Ping Wait + Ping Várakozás + + + Min Ping + Minimum Ping + + + Time Offset + Idő Eltolódás + Last block time Utolsó blokk ideje @@ -976,6 +1633,22 @@ 1 &year 1 &év + + &Disconnect + &Szétkapcsol + + + Ban for + Kitiltás oka + + + &Unban + &Feloldja a kitiltást + + + Welcome to the %1 RPC console. + Üdv a %1 RPC konzoljában. + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Navigálhat a fel és le nyilakkal, és <b>Ctrl-L</b> -vel törölheti a képernyőt. @@ -984,6 +1657,10 @@ Type <b>help</b> for an overview of available commands. Írd be azt, hogy <b>help</b> az elérhető parancsok áttekintéséhez. + + Network activity disabled + Hálózati tevékenység letiltva. + %1 B %1 B @@ -1000,6 +1677,10 @@ %1 GB %1 GB + + (node id: %1) + (csomópont azonosító: %1) + via %1 %1 által @@ -1043,6 +1724,30 @@ &Message: &Üzenet: + + 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. + Egy előzőleg használt fogadó cím újrafelhasználása. A címek újrafelhasználása biztonsági és adatvédelmi problémát jelent. Ne használja ezt a funkciót, kivéve, ha egy korábbi fizetési kérelmet szeretne megismételni. + + + R&euse an existing receiving address (not recommended) + &Újrafelhasznál egy létező fogadó címet (nem ajánlott) + + + 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. + Egy opcionális üzenet csatolása a fizetési kérelemhez, amely megjelenik a kérelem megnyitásakor. Megjegyzés: Az üzenet nem lesz elküldve a fizetséggel a Bitcoin hálózaton keresztül. + + + An optional label to associate with the new receiving address. + Egy opcionális címke, amit hozzá lehet rendelni az új fogadó címhez. + + + Use this form to request payments. All fields are <b>optional</b>. + Használja ezt az űrlapot fizetési kérelmekhez. Minden mező <b>opcionális</b> + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + Egy opcionálisan kérhető összeg. Hagyja üresen, vagy írjon be nullát, ha nem kívánja használni. + Clear all fields of the form. Minden mező törlése @@ -1059,6 +1764,10 @@ &Request payment &Fizetés kérése + + Show the selected request (does the same as double clicking an entry) + Mutassa meg a kiválasztott kérelmet (ugyanaz, mint a duplaklikk) + Show Mutat @@ -1071,7 +1780,23 @@ Remove Eltávolítás - + + Copy URI + URI másolása + + + Copy label + Címke másolása + + + Copy message + Üzenet másolása + + + Copy amount + Összeg másolása + + ReceiveRequestDialog @@ -1090,24 +1815,84 @@ &Save Image... &Kép mentése + + Request payment to %1 + Fizetés kérése a %1 -hez + + + Payment information + Fizetési információ + + + URI + URI + + + Address + Cím + + + Amount + Összeg + Label Címke - + + Message + Üzenet + + + Resulting URI too long, try to reduce the text for label / message. + A keletkezett URI túl hosszú, próbálja meg csökkenteni a cimke / üzenet szövegének méretét. + + + Error encoding URI into QR Code. + Hiba lépett fel az URI QR kóddá alakításakor. + + RecentRequestsTableModel + + Date + Dátum + Label Címke - + + Message + Üzenet + + + (no label) + (nincs címke) + + + (no message) + (nincs üzenet) + + + (no amount requested) + (nem kért összeget) + + + Requested + Kért + + SendCoinsDialog Send Coins Érmék küldése + + Coin Control Features + Pénzküldés beállításai + Inputs... Bemenetek... @@ -1144,6 +1929,14 @@ Change: Visszajáró: + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + Ha ezt a beállítást engedélyezi, de a visszajáró cím érvénytelen, a visszajáró egy újonnan generált címre lesz küldve. + + + Custom change address + Egyedi visszajáró cím + Transaction Fee: Tranzakciós díj @@ -1152,6 +1945,10 @@ Choose... Válassz... + + collapse fee-settings + díj beállítások bezárása + per kilobyte kilobájtonként @@ -1208,123 +2005,307 @@ S&end &Küldés - - - SendCoinsEntry - A&mount: - Összeg: + Copy quantity + Mennyiség másolása - Pay &To: - Címzett: + Copy amount + Összeg másolása - &Label: - Címke: + Copy fee + Díj másolása - Choose previously used address - Válassz egy korábban már használt címet + Copy bytes + Byte-ok másolása - Alt+A - Alt+A + Copy dust + Porszemek másolása - Paste address from clipboard - Cím beillesztése a vágólapról + Copy change + Visszajáró másolása - Alt+P - Alt+P + Are you sure you want to send? + Biztosan el akarja küldeni? - Remove this entry - Ez a bejegyzés eltávolítása + added as transaction fee + hozzáadva, mint tranzakciós díj - Message: - Üzenet: + Total Amount %1 + Teljes Összeg %1 - Pay To: - Címzett: + or + vagy - Memo: - Jegyzet: + Confirm send coins + Összeg küldésének megerősítése - - - SendConfirmationDialog - - - ShutdownWindow - Do not shut down the computer until this window disappears. - Ne állítsd le a számítógépet amíg ez az ablak el nem tűnik. + The recipient address is not valid. Please recheck. + A fogadó címe érvénytelen. Kérem ellenőrizze. - - - SignVerifyMessageDialog - Signatures - Sign / Verify a Message - Aláírások - üzenet aláírása/ellenőrzése + The amount to pay must be larger than 0. + A fizetendő összegnek nagyobbnak kell lennie 0-nál. - &Sign Message - Üzenet aláírása... + The amount exceeds your balance. + Az összeg meghaladja az egyenlegét. - Choose previously used address - Válassz egy korábban már használt címet + The total exceeds your balance when the %1 transaction fee is included. + A küldeni kívánt összeg és a %1 tranzakciós díj együtt meghaladja az egyenlegén rendelkezésre álló összeget. - Alt+A - Alt+A + Duplicate address found: addresses should only be used once each. + Többször szerepel ugyanaz a cím: egy címet csak egyszer használjon. - Paste address from clipboard - Cím beillesztése a vágólapról + Transaction creation failed! + Tranzakció létrehozása sikertelen! - Alt+P - Alt+P + The transaction was rejected with the following reason: %1 + Tranzakció visszautasítva a következő indokkal: %1 - Enter the message you want to sign here - Ide írja az aláírandó üzenetet + A fee higher than %1 is considered an absurdly high fee. + Magasabb díj mint %1 abszurd magas díjnak számít. - Signature - Aláírás + Payment request expired. + A fizetési kérelem lejárt. - Copy the current signature to the system clipboard - A jelenleg kiválasztott aláírás másolása a rendszer-vágólapra + Pay only the required fee of %1 + Csak a szükséges %1 díj fizetése - Sign the message to prove you own this Bitcoin address - Üzenet + Warning: Invalid Bitcoin address + Figyelmeztetés: Érvénytelen Bitcoin cím - Sign &Message - Üzenet &aláírása + Warning: Unknown change address + Figyelmeztetés: Ismeretlen visszajáró cím - Clear &All - Mindent &töröl + Confirm custom change address + Egyedi visszajáró cím jóváhagyása - &Verify Message - Üzenet ellenőrzése + The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure? + A cím, amelyet a visszajárónak megadott, nincs ebben a tárcában. Bármennyi vagy minden összeg elküldhető a tárcájából erre a címre. Biztos benne? - Verify &Message + (no label) + (nincs címke) + + + + SendCoinsEntry + + A&mount: + Összeg: + + + Pay &To: + Címzett: + + + &Label: + Címke: + + + Choose previously used address + Válassz egy korábban már használt címet + + + The Bitcoin address to send the payment to + Erre a Bitcoin címre küldje az összeget + + + Alt+A + Alt+A + + + Paste address from clipboard + Cím beillesztése a vágólapról + + + Alt+P + Alt+P + + + Remove this entry + Ez a bejegyzés eltávolítása + + + S&ubtract fee from amount + &Vonja le a díjat az összegből + + + Message: + Üzenet: + + + Enter a label for this address to add it to the list of used addresses + Adjon egy címkét ehhez a címhez, hogy bekerüljön a használt címek közé + + + Pay To: + Címzett: + + + Memo: + Jegyzet: + + + Enter a label for this address to add it to your address book + Adjon egy címkét ehhez a címhez, hogy bekerüljön a címtárába + + + + SendConfirmationDialog + + Yes + Igen + + + + ShutdownWindow + + %1 is shutting down... + A %1 leáll... + + + Do not shut down the computer until this window disappears. + Ne állítsd le a számítógépet amíg ez az ablak el nem tűnik. + + + + SignVerifyMessageDialog + + Signatures - Sign / Verify a Message + Aláírások - üzenet aláírása/ellenőrzése + + + &Sign Message + Üzenet aláírása... + + + The Bitcoin address to sign the message with + Bitcoin cím, amivel alá kívánja írni az üzenetet + + + Choose previously used address + Válassz egy korábban már használt címet + + + Alt+A + Alt+A + + + Paste address from clipboard + Cím beillesztése a vágólapról + + + Alt+P + Alt+P + + + Enter the message you want to sign here + Ide írja az aláírandó üzenetet + + + Signature + Aláírás + + + Copy the current signature to the system clipboard + A jelenleg kiválasztott aláírás másolása a rendszer-vágólapra + + + Sign the message to prove you own this Bitcoin address + Üzenet + + + Sign &Message + Üzenet &aláírása + + + Clear &All + Mindent &töröl + + + &Verify Message Üzenet ellenőrzése - + + The Bitcoin address the message was signed with + Bitcoin cím, amivel aláírta az üzenetet + + + Verify the message to ensure it was signed with the specified Bitcoin address + Ellenőrizze az üzenetet, hogy valóban a megjelölt Bitcoin címmel van-e aláírva + + + Verify &Message + Üzenet ellenőrzése + + + Click "Sign Message" to generate signature + Klikkeljen az "Üzenet Aláírása" -ra, hogy aláírást generáljon + + + The entered address is invalid. + A megadott cím nem érvényes. + + + Please check the address and try again. + Kérem ellenőrizze a címet és próbálja meg újra. + + + Wallet unlock was cancelled. + Tárca megnyitása megszakítva + + + Private key for the entered address is not available. + A megadott cím privát kulcsa nem található. + + + Message signing failed. + Üzenet aláírása sikertelen. + + + Message signed. + Üzenet aláírva. + + + The signature could not be decoded. + Az aláírást nem sikerült dekódolni. + + + Please check the signature and try again. + Kérem ellenőrizze az aláírást és próbálja újra. + + + Message verification failed. + Az üzenet igazolása sikertelen. + + + Message verified. + Üzenet ellenőrizve. + + SplashScreen @@ -1341,7 +2322,147 @@ TransactionDesc - + + Open until %1 + %1 -ig megnyitva + + + %1/offline + %1/offline + + + 0/unconfirmed, %1 + 0/megerősítetlen, %1 + + + in memory pool + a memória halomban + + + not in memory pool + nincs a memória halomban + + + abandoned + elhagyott + + + %1/unconfirmed + %1/megerősítetlen + + + %1 confirmations + %1 megerősítés + + + Status + Állapot + + + , has not been successfully broadcast yet + , még nem sikerült közvetíteni + + + Date + Dátum + + + Source + Forrás + + + Generated + Generálva + + + From + Küldő: + + + unknown + ismeretlen + + + To + Címzett + + + own address + saját cím + + + watch-only + csak megfigyelés + + + label + címke + + + Credit + Jóváírás + + + not accepted + elutasítva + + + Debit + Terhelés + + + Total debit + Teljes terhelés + + + Transaction fee + Tranzakciós díj + + + Net amount + Nettó összeg + + + Message + Üzenet + + + Comment + Megjegyzés + + + Transaction ID + Tranzakció Azonosító + + + Merchant + Kereskedő + + + Debug information + Debug információ + + + Transaction + Tranzakció + + + Inputs + Bemenetek + + + Amount + Összeg + + + true + igaz + + + false + hamis + + TransactionDescDialog @@ -1351,17 +2472,237 @@ TransactionTableModel + + Date + Dátum + + + Type + Típus + Label Címke + + Open until %1 + %1 -ig megnyitva + + + Offline + Offline + + + Unconfirmed + Megerősítetlen + + + Abandoned + Elhagyott + + + Confirming (%1 of %2 recommended confirmations) + Megerősítés (%1 az ajánlott %2 megerősítésből) + + + Confirmed (%1 confirmations) + Megerősítve (%1 megerősítés) + + + Conflicted + Konfliktusos + + + Immature (%1 confirmations, will be available after %2) + Éretlen (%1 megerősítés, %2 után lesz elérhető) + + + This block was not received by any other nodes and will probably not be accepted! + Ezt a blokkot egyetlen másik csomópont sem kapta meg, így valószínűleg nem lesz elfogadva! + + + Generated but not accepted + Generálva, de nincs elfogadva + + + Received from + Fogadva innen + + + Sent to + Elküldve ide + + + Payment to yourself + Magadnak kifizetve + + + Mined + Kibányászva + + + watch-only + csak megfigyelés + + + (n/a) + (nincs adat) + + + (no label) + (nincs címke) + + + Transaction status. Hover over this field to show number of confirmations. + Tranzakció állapota. Húzza ide az egeret, hogy lássa a megerősítések számát. + + + Date and time that the transaction was received. + Tranzakció fogadásának dátuma és időpontja. + + + Type of transaction. + Tranzakció típusa. + + + Whether or not a watch-only address is involved in this transaction. + Egy csak megfigyelt cím érintett vagy nem ebben a tranzakcióban. + TransactionView + + All + Mind + + + Today + Ma + + + This week + Ezen a héten + + + This month + Ebben a hónapban + + + Last month + Múlt hónapban + + + This year + Ebben az évben + + + Range... + Tartomány... + + + Sent to + Elküldve ide + + + To yourself + Magának + + + Mined + Kibányászva + + + Other + Más + + + Enter address or label to search + Írja be a keresendő címet vagy címkét + + + Min amount + Minimális összeg + + + Copy address + Cím másolása + + + Copy label + Címke másolása + + + Copy amount + Összeg másolása + + + Copy transaction ID + Tranzakció azonosító másolása + + + Copy full transaction details + Tranzakció részleteinek teljes másolása + + + Edit label + Címke szerkesztése + + + Show transaction details + Tranzakció részletesen + + + Export Transaction History + Tranzakciós előzmények exportálása + + + Comma separated file (*.csv) + Vesszővel elválasztott adatokat tartalmazó fájl + + + Confirmed + Megerősítve + + + Watch-only + Csak megfigyelés + + + Date + Dátum + + + Type + Típus + Label Címke + + Address + Cím + + + ID + Azonosító + + + Exporting Failed + Hiba az exportálás során + + + There was an error trying to save the transaction history to %1. + Hiba történt a tranzakciós előzmények %1 helyre való mentésekor. + + + Exporting Successful + Sikeres Exportálás + + + Range: + Tartomány: + UnitDisplayStatusBarControl @@ -1371,10 +2712,42 @@ WalletModel - + + Send Coins + Érmék Küldése + + WalletView - + + &Export + &Exportálás + + + Export the data in the current tab to a file + Jelenlegi nézet adatainak exportálása fájlba + + + Backup Wallet + Biztonsági másolat készítése a Tárcáról + + + Wallet Data (*.dat) + Tárca Fájl (*.dat) + + + Backup Failed + Biztonsági másolat készítése sikertelen + + + Backup Successful + Sikeres biztonsági mentés + + + The wallet data was successfully saved to %1. + A tárca adatai sikeresen elmentve %1. + + bitcoin-core @@ -1400,6 +2773,14 @@ Parancssoros és JSON-RPC parancsok elfogadása + + Distributed under the MIT software license, see the accompanying file %s or %s + MIT szoftver licenc alapján terjesztve, tekintse meg a hozzátartozó fájlt %s or %s + + + Error: A fatal internal error occurred, see debug.log for details + Hiba: Fatális belső hiba történt, nézze meg a debug.log -ot a részletekért + Run in the background as a daemon and accept commands Háttérben futtatás daemonként és parancsok elfogadása @@ -1409,6 +2790,10 @@ Bitcoin Core Bitcoin Core + + The %s developers + A %s fejlesztők + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Parancs, amit akkor hajt végre, amikor egy tárca-tranzakció megváltozik (%s a parancsban lecserélődik a blokk TxID-re) @@ -1543,10 +2928,18 @@ Loading addresses... Címek betöltése... + + Warning: Unknown block versions being mined! It's possible unknown rules are in effect + Figyelem: Ismeretlen blokkokat bányásznak! Lehetséges, hogy ismeretlen szabályok érvényesek. + (default: %s) (alapértelmezett: %s) + + How many blocks to check at startup (default: %u, 0 = all) + Hány blokkot ellenőrizzen induláskor (alapértelmezett: %u, 0 = mindet) + Include IP addresses in debug output (default: %u) IP-címek megjelenítése a naplóban (alapértelmezett: %u) @@ -1555,6 +2948,54 @@ Invalid -proxy address: '%s' Érvénytelen -proxy cím: '%s' + + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + Kapcsolatonkénti maximum fogadó buffer, <n>*1000 byte (alapértelmezett: %u) + + + Maximum per-connection send buffer, <n>*1000 bytes (default: %u) + Kapcsolatonkénti maximum küldő buffer, <n>*1000 byte (alapértelmezett: %u) + + + Set key pool size to <n> (default: %u) + Kulcs halmaz méretének a beállítása <n>(alapértelmezett: %u) + + + Specify configuration file (default: %s) + Konfigurációs fájl megadása (alapértelmezett: %s) + + + Specify connection timeout in milliseconds (minimum: 1, default: %d) + Csatlakozás időtúllépése milliszekundumban (minimum: 1, alapértelmezett: %d) + + + Specify pid file (default: %s) + Pid-fájl megadása (alapértelmezett: %s) + + + Spend unconfirmed change when sending transactions (default: %u) + Tranzakciók küldésekor a jóváhagyatlan visszajáró elköltése (alapértelmezés: %u) + + + Starting network threads... + Hálózati szálak indítása... + + + This is the minimum transaction fee you pay on every transaction. + Ez a minimum tranzakciós díj, amelyet tranzakciónként kifizet. + + + This is the transaction fee you will pay if you send a transaction. + Ez a tranzakció díja, amelyet kifizet, ha tranzakciót indít. + + + Transaction amounts must not be negative + Tranzakció összege nem lehet negatív + + + Transaction must have at least one recipient + Legalább egy címzett kell a tranzakcióhoz + Unknown network specified in -onlynet: '%s' Ismeretlen hálózat lett megadva -onlynet: '%s' diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index d38459c6ff8e..62e4e7b0db49 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -3,7 +3,7 @@ AddressBookPage Right-click to edit address or label - Tasto destro per modificare l'indirizzo o l'etichetta + Fare clic con il tasto destro del mouse per modificare l'indirizzo o l'etichetta Create a new address @@ -881,6 +881,10 @@ Form Modulo + + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. + Transazioni recenti potrebbero non essere visibili ancora, perciò il saldo del tuo portafoglio potrebbe non essere corretto. Questa informazione risulterà corretta quando il tuo portafoglio avrà terminato la sincronizzazione con la rete bitcoin, come indicato in dettaglio più sotto. + Number of blocks left Numero di blocchi mancanti @@ -1431,6 +1435,14 @@ Per specificare più URL separarli con una barra verticale "|". QObject::QObject + + Error: Specified data directory "%1" does not exist. + Errore: La cartella dati "%1" specificata non esiste. + + + Error: Cannot parse configuration file: %1. Only use key=value syntax. + Errore: impossibile interpretare il file di configurazione: %1. Usare esclusivamente la sintassi chiave=valore. + Error: %1 Errore: %1 @@ -2165,6 +2177,10 @@ Per specificare più URL separarli con una barra verticale "|". Pay only the required fee of %1 Paga solamente la commissione richiesta di %1 + + Estimated to begin confirmation within %n block(s). + Inizio delle conferme stimato entro %n blocchi.Inizio delle conferme stimato entro %n blocchi. + Warning: Invalid Bitcoin address Attenzione: Indirizzo Bitcoin non valido @@ -2592,6 +2608,10 @@ Per specificare più URL separarli con una barra verticale "|". Unconfirmed Non confermata + + Abandoned + Abbandonato + Confirmed (%1 confirmations) Confermata (%1 conferme) @@ -2608,6 +2628,10 @@ Per specificare più URL separarli con una barra verticale "|". Received with Ricevuto tramite + + Received from + Ricevuto da + Sent to Inviato a @@ -2715,6 +2739,10 @@ Per specificare più URL separarli con una barra verticale "|". Min amount Importo minimo + + Abandon transaction + Abbandona transazione + Copy address Copia indirizzo diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 14919c440dfc..46862dfe81c8 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -433,6 +433,14 @@ %n active connection(s) to Bitcoin network %n aktiv forbindelse til Bitcoin-nettverket%n aktive forbindelser til Bitcoin-nettverket + + Indexing blocks on disk... + Indekserer blokker på disk... + + + Processing blocks on disk... + Prosesserer blokker på disk... + Processed %n block(s) of transaction history. Lastet %n blokk med transaksjonshistorikk.Lastet %n blokker med transaksjonshistorikk. diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index c8b0d17593fb..3b6616473fd7 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -3455,7 +3455,7 @@ Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) - Transactiekosten (in %s/kB) kleiner dan dit worden beschouw dat geen transactiekosten in rekening worden gebracht voor doorgeven, mijnen en transactiecreatie (standaard: %s) + Transactiekosten (in %s/kB) kleiner dan dit worden beschouw dat geen transactiekosten in rekening worden gebracht voor doorgeven, delven en transactiecreatie (standaard: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3663,7 +3663,7 @@ Equivalent bytes per sigop in transactions for relay and mining (default: %u) - Equivalent byter per sigop in transactions voor doorsturen en mijnen (standaard: %u) + Equivalente bytes per sigop in transacties voor doorsturen en delven (standaard: %u) Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index a45bb5923971..03f52d752fef 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -2161,10 +2161,18 @@ The total exceeds your balance when the %1 transaction fee is included. O total excede o seu saldo quando a taxa de transação %1 está incluída. + + Duplicate address found: addresses should only be used once each. + Endereço duplicado encontrado: os endereços devem ser usados ​​apenas uma vez. + Transaction creation failed! A criação da transação falhou! + + The transaction was rejected with the following reason: %1 + A transação foi rejeitada pelo seguinte motivo: %1 + A fee higher than %1 is considered an absurdly high fee. Uma taxa superior a %1 é considerada uma taxa altamente absurda. @@ -2173,10 +2181,18 @@ Payment request expired. Pedido de pagamento expirado. + + %n block(s) + %n bloco%n blocos + Pay only the required fee of %1 Pague apenas a taxa obrigatória de %1 + + Estimated to begin confirmation within %n block(s). + Estimativa para iniciar a confirmação dentro de %n bloco.Estimativa para iniciar a confirmação dentro de %n blocos. + Warning: Invalid Bitcoin address Aviso: endereço Bitcoin inválido @@ -2189,6 +2205,10 @@ Confirm custom change address Confirmar endereço de troco personalizado + + The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure? + O endereço que você selecionou para alterar não faz parte desta carteira. Qualquer ou todos os fundos em sua carteira podem ser enviados para este endereço. Você tem certeza? + (no label) (sem etiqueta) @@ -2272,7 +2292,11 @@ Memo: Memorando: - + + 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 seu catálogo de endereços + + SendConfirmationDialog @@ -2446,6 +2470,10 @@ TransactionDesc + + Open for %n more block(s) + Abrir para %n ou mais blocoAbrir para %n ou mais blocos + Open until %1 Aberto até %1 @@ -2486,6 +2514,10 @@ , has not been successfully broadcast yet , ainda não foi transmitido com sucesso + + , broadcast through %n node(s) + , transmitido através de %n nó, transmitido através de %n nós + Date Data @@ -2743,6 +2775,10 @@ Other Outras + + Enter address or label to search + Digite o endereço ou o rótulo para pesquisar + Min amount Valor mín. @@ -2845,7 +2881,11 @@ WalletFrame - + + No wallet has been loaded. + Nenhuma carteira foi carregada + + WalletModel @@ -2970,6 +3010,10 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Executar o comando quando uma transação da carteira muda (no comando, %s é substituído pela Id. da Transação) + + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. + Por favor verifique que a data e hora do seu computador estão certos! Se o relógio não estiver certo, o %s não funcionará corretamente. + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Defina o número de processos de verificação (%u até %d, 0 = automático, <0 = ldisponibiliza esse número de núcleos livres, por defeito: %d) @@ -3498,6 +3542,10 @@ Warning: Unknown block versions being mined! It's possible unknown rules are in effect Atenção: Versões desconhecidas de blocos estão a ser mineradas! É possível que regras desconhecias estão a ser efetuadas + + %s is set very high! + %s está demasiado elevado! + (default: %s) (predefinição: %s) diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index 3d3a4b04316f..de23b8a1a730 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -41,9 +41,61 @@ &Delete &Şterge + + C&hoose + &Alegeţi + + + Sending addresses + Adresa destinatarului + + + Receiving addresses + Adresa de primire + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Acestea sunt adresele tale Bitcoin pentru efectuarea platilor. Intotdeauna verifica atent suma de plata si adresa beneficiarului inainte de a trimite monede. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Acestea sunt adresele tale Bitcoin pentru receptionarea platilor. Este recomandat sa folosesti mereu o adresa noua pentru primirea platilor. + + + &Copy Address + &Copiază adresa + + + Copy &Label + Copiaza si eticheteaza + + + &Edit + &Editare + + + Export Address List + Exportă listă de adrese + + + Comma separated file (*.csv) + Fisier .csv cu separator - virgula + + + Exporting Failed + Exportarea a eșuat + AddressTableModel + + Label + Etichetă + + + Address + Adresă + AskPassphraseDialog @@ -63,6 +115,30 @@ Repeat new passphrase Repetaţi noua frază de acces + + Encrypt wallet + Criptare portofel + + + Unlock wallet + Deblocare portofel + + + Decrypt wallet + Decriptare portofel + + + Change passphrase + Schimbă parola + + + Confirm wallet encryption + Confirmaţi criptarea portofelului + + + Wallet encrypted + Portofel criptat + BanTableModel @@ -1230,13 +1306,25 @@ &Save Image... &Salvează imaginea... + + Address + Adresă + Amount Cantitate + + Label + Etichetă + RecentRequestsTableModel + + Label + Etichetă + SendCoinsDialog @@ -1547,9 +1635,29 @@ TransactionTableModel + + Label + Etichetă + TransactionView + + Comma separated file (*.csv) + Fisier .csv cu separator - virgula + + + Label + Etichetă + + + Address + Adresă + + + Exporting Failed + Exportarea a eșuat + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_th.ts b/src/qt/locale/bitcoin_th.ts index a83f8312a09c..2bed5ece23f4 100644 --- a/src/qt/locale/bitcoin_th.ts +++ b/src/qt/locale/bitcoin_th.ts @@ -13,6 +13,10 @@ &New ใหม่ + + Copy the currently selected address to the system clipboard + คัดลอกที่อยู่ที่เลือกอยู่ไปยังคลิบบอร์ดของระบบ + &Copy คัดลอก @@ -21,6 +25,14 @@ C&lose ปิด + + Delete the currently selected address from the list + ลบที่อยู่ที่เลือกไว้ออกจากรายการ + + + Export the data in the current tab to a file + ส่งออกข้อมูลที่อยู่ในแถบนี้ไปในไฟล์ + &Export ส่งออก @@ -196,6 +208,10 @@ &Export ส่งออก + + Export the data in the current tab to a file + ส่งออกข้อมูลที่อยู่ในแถบนี้ไปในไฟล์ + bitcoin-core diff --git a/src/qt/locale/bitcoin_tr_TR.ts b/src/qt/locale/bitcoin_tr_TR.ts index 0a50a38dbff7..c97cab823082 100644 --- a/src/qt/locale/bitcoin_tr_TR.ts +++ b/src/qt/locale/bitcoin_tr_TR.ts @@ -80,7 +80,11 @@ Address adres - + + (no label) + (etiket yok) + + AskPassphraseDialog @@ -152,6 +156,10 @@ CoinControlDialog + + (no label) + (etiket yok) + EditAddressDialog @@ -231,10 +239,18 @@ Label etiket + + (no label) + (etiket yok) + SendCoinsDialog - + + (no label) + (etiket yok) + + SendCoinsEntry @@ -265,6 +281,10 @@ Label etiket + + (no label) + (etiket yok) + TransactionView diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 2094d67dd8a2..754b49fd455e 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -197,7 +197,7 @@ The supplied passphrases do not match. - 提供的密码不yi'zhi。 + 提供的密码不一致。 Wallet unlock failed @@ -531,6 +531,14 @@ Incoming transaction 流入交易 + + HD key generation is <b>enabled</b> + HD密钥生成<b>启用</b> + + + HD key generation is <b>disabled</b> + HD密钥生成<b>禁用</b> + Wallet is <b>encrypted</b> and currently <b>unlocked</b> 钱包已被<b>加密</b>,当前为<b>解锁</b>状态 @@ -918,7 +926,11 @@ Hide 隐藏 - + + Unknown. Syncing Headers (%1)... + 未知状态。同步区块头(%1) + + OpenURIDialog @@ -2638,7 +2650,11 @@ This pane shows a detailed description of the transaction 当前面板显示了交易的详细信息 - + + Details for %1 + %1 详情 + + TransactionTableModel @@ -2665,6 +2681,10 @@ Unconfirmed 未确认的 + + Abandoned + 已丢弃 + Confirming (%1 of %2 recommended confirmations) 确认中 (推荐 %2个确认,已经有 %1个确认) @@ -2982,6 +3002,10 @@ 接受命令行和 JSON-RPC 命令 + + Distributed under the MIT software license, see the accompanying file %s or %s + 在MIT协议下分发,参见附带的 %s 文件或 %s + If <category> is not supplied or if <category> = 1, output all debugging information. 如果<category>未提供或<category> = 1,输出所有调试信息。 @@ -3040,14 +3064,34 @@ Bind to given address and always listen on it. Use [host]:port notation for IPv6 绑定指定的IP地址开始监听。IPv6地址请使用[host]:port 格式 + + Cannot obtain a lock on data directory %s. %s is probably already running. + 无法给数据目录 %s 上锁。%s 可能已经在运行。 + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup 删除钱包的所有交易记录,且只有用 -rescan参数启动客户端才能重新取回交易记录 + + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + 读取 %s 时发生错误!所有的密钥都可以正确读取,但是交易记录或地址簿数据可能已经丢失或出错。 + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) 当最佳区块变化时执行命令 (命令行中的 %s 会被替换成区块哈希值) + + 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) + 最大的单次钱包或原始转账费用(%s),设置太低可能导致大尺寸交易失败(默认:%s) + + + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. + 请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。 + + + Please contribute if you find %s useful. Visit %s for further information about the software. + 如果你认为%s对你比较有用的话,请对我们进行一些捐赠支持。请访问%s网站来获取有关这个软件的更多信息。 + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) 设置脚本验证的程序 (%u 到 %d, 0 = 自动, <0 = 保留自由的核心, 默认值: %d) @@ -3060,6 +3104,10 @@ Use UPnP to map the listening port (default: 1 when listening and no -proxy) 使用UPnP暴露本机监听端口(默认:1 当正在监听且不使用代理) + + %s corrupt, salvage failed + %s 已损坏,抢救备份失败 + -maxmempool must be at least %d MB -maxmempool 最小为%d MB @@ -3072,6 +3120,10 @@ Append comment to the user agent string 为用户代理字符串附加说明 + + Attempt to recover private keys from a corrupt wallet on startup + 启动时尝试从已损坏的钱包文件中恢复私钥 + Block creation options: 数据块创建选项: @@ -3080,6 +3132,10 @@ Cannot resolve -%s address: '%s' 无法解析 - %s 地址: '%s' + + Chain selection options: + 区块链选择选项: + Connection options: 连接选项: @@ -3136,6 +3192,14 @@ Error loading %s 载入 %s 时发生错误 + + Error loading %s: Wallet corrupted + %s 加载出错:钱包损坏 + + + Error loading %s: Wallet requires newer version of %s + %s 加载错误:请升级到最新版 %s + Error loading block database 导入数据块数据库出错 @@ -3164,6 +3228,10 @@ Invalid -onion address: '%s' 无效的 -onion 地址:“%s” + + Invalid amount for -%s=<amount>: '%s' + 非法金额 -%s=<amount>: '%s' + Invalid amount for -fallbackfee=<amount>: '%s' -fallbackfee 的无效数额=<amount>: '%s' @@ -3172,6 +3240,10 @@ Keep the transaction memory pool below <n> megabytes (default: %u) 保持交易内存池大小低于<n>MB(默认:%u) + + Loading banlist... + 加载黑名单 + Location of the auth cookie (default: data dir) 认证Cookie的位置 (默认: data目录) @@ -3184,6 +3256,10 @@ Only connect to nodes in network <net> (ipv4, ipv6 or onion) 只连接 <net>网络中的节点 (ipv4, ipv6 或 onion) + + Print this help message and exit + 打印出这段帮助信息并退出 + Print version and exit 打印版本信息并退出 @@ -3196,6 +3272,10 @@ Prune mode is incompatible with -txindex. 修剪模式与 -txindex 不兼容。 + + Rebuild chain state from the currently indexed blocks + 从当前索引的区块中重建链状态 + Set database cache size in megabytes (%d to %d, default: %d) 设置以MB为单位的数据库缓存大小(%d 到 %d, 默认值: %d) @@ -3212,6 +3292,10 @@ The source code is available from %s. 源代码可以在 %s 获得。 + + Unable to bind to %s on this computer. %s is probably already running. + 无法在本机绑定 %s 端口。%s 可能已经在运行。 + Unsupported argument -benchmark ignored, use -debug=bench. 忽略不支持的选项 -benchmark,使用 -debug=bench @@ -3513,6 +3597,10 @@ Support filtering of blocks and transaction with bloom filters (default: %u) 支持用 Bloom 过滤器来过滤区块和交易(默认值: %u) + + This is the transaction fee you may pay when fee estimates are not available. + 这是在费用估计不可用时你可能会支付的交易费。 + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. 网络版本字符串的总长度 (%i) 超过最大长度 (%i) 了。请减少 uacomment 参数的数目或长度。 @@ -3537,6 +3625,10 @@ Warning: Unknown block versions being mined! It's possible unknown rules are in effect 警告: 未知的区块版本被挖掘!未知规则可能已生效 + + %s is set very high! + %s非常高! + (default: %s) (默认: %s) @@ -3597,6 +3689,10 @@ Set key pool size to <n> (default: %u) 设置私钥池大小为 <n> (默认:%u) + + Set maximum BIP141 block weight (default: %d) + 设置BIP141最大区块权重 (默认: %d) + Set the number of threads to service RPC calls (default: %d) 设置RPC服务线程数 (默认: %d) @@ -3621,10 +3717,22 @@ Starting network threads... 正在启动网络线程... + + This is the transaction fee you will pay if you send a transaction. + 如果发送交易,这是你交易付款时所要付的手续费。 + Threshold for disconnecting misbehaving peers (default: %u) 断开 非礼节点的阀值 (默认: %u) + + Transaction amounts must not be negative + 交易金额不不可为负数 + + + Transaction must have at least one recipient + 交易必须包含至少一个接收人 + Unknown network specified in -onlynet: '%s' -onlynet 指定的是未知网络:%s From fb7b5293844ea6adc5dcf5ad0a0c5890b4495939 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 15 Sep 2017 15:59:43 +0200 Subject: [PATCH 031/196] doc: Release notes for 0.15.0.1 Tree-SHA512: ce2e874659ea59fa3f1f34a02ed910f655db2ec5b030ef40f89dca0b90932a3b579768db4e7f30773ca9cbbf72891369efe34fdbf111669c3bb583e8c69eda85 --- doc/release-notes.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 9bf9e63c5c53..32bf667734fd 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,12 +1,8 @@ -(note: this is a temporary file, to be added-to by anybody, and moved to -release-notes at release time) +Bitcoin Core version *0.15.0.1* is now available from: -Bitcoin Core version *0.15.1* is now available from: + - - -This is a new major version release, including new features, various bugfixes -and performance improvements, as well as updated translations. +This is a minor bug fix for 0.15.0. Please report bugs using the issue tracker at GitHub: @@ -60,16 +56,28 @@ frequently tested on them. Notable changes =============== +GUI startup crash issue +------------------------- + +After upgrade to 0.15.0, some clients would crash at startup because a custom +fee setting was configured that no longer exists in the GUI. This is a minimal +patch to avoid this issue from occuring. + +0.15.0.1 Change log +==================== +- #11332 `46c8d23` Fix possible crash with invalid nCustomFeeRadio in QSettings (achow101, TheBlueMatt) -0.15.1 Change log -================= +Also the manpages were updated, as this was forgotten for 0.15.0. Credits ======= Thanks to everyone who directly contributed to this release: -(fill this in) +- Andrew Chow +- Matt Corallo +- Jonas Schnelli +- Wladimir J. van der Laan As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From 9e8aae31c103e1d76365c34ce1fe1dd68e93912b Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Wed, 9 Aug 2017 17:24:15 +0900 Subject: [PATCH 032/196] [wallet] Close DB on error. Github-Pull: #11017 Rebased-From: 03bc719a85cb4928cb4b43d0bc4142f72cb01b23 --- src/wallet/db.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index b12d46e40a10..d2fe4866fae3 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -101,8 +101,10 @@ bool CDBEnv::Open(const fs::path& pathIn) DB_RECOVER | nEnvFlags, S_IRUSR | S_IWUSR); - if (ret != 0) + if (ret != 0) { + dbenv->close(0); return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + } fDbEnvInit = true; fMockDb = false; @@ -196,9 +198,9 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco DB_BTREE, // Database type DB_CREATE, // Flags 0); - if (ret > 0) - { + if (ret > 0) { LogPrintf("Cannot create database file %s\n", filename); + pdbCopy->close(0); return false; } @@ -536,8 +538,10 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) env->CloseDb(strFile); if (pdbCopy->close(0)) fSuccess = false; - delete pdbCopy; + } else { + pdbCopy->close(0); } + delete pdbCopy; } if (fSuccess) { Db dbA(env->dbenv, 0); From fc2aa09cf382f024f461e103f2500e95ddb692e5 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 2 Jun 2017 14:30:36 -0400 Subject: [PATCH 033/196] [tests] Introduce TestNode TestNode is a class responsible for all state related to a bitcoind node under test. It stores local state, is responsible for tracking the bitcoind process and delegates unrecognised messages to the RPC connection. This commit changes start_nodes and stop_nodes to start and stop the bitcoind nodes in parallel, making test setup and teardown much faster. Github-Pull: #10711 Rebased-From: 7897338918dac072e788b8ab2919d4559f311bef --- test/functional/blockchain.py | 4 +- test/functional/bumpfee.py | 3 +- test/functional/fundrawtransaction.py | 3 +- test/functional/getblocktemplate_longpoll.py | 2 +- test/functional/keypool.py | 3 +- test/functional/multiwallet.py | 12 +- test/functional/rpcbind_test.py | 4 +- .../test_framework/test_framework.py | 115 ++++++--------- test/functional/test_framework/test_node.py | 134 ++++++++++++++++++ test/functional/test_framework/util.py | 4 +- test/functional/wallet-dump.py | 3 +- test/functional/wallet-encryption.py | 3 +- 12 files changed, 193 insertions(+), 97 deletions(-) create mode 100755 test/functional/test_framework/test_node.py diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index a7034e6bcdba..0812e1b0df90 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -139,13 +139,13 @@ def _test_stopatheight(self): self.nodes[0].generate(6) assert_equal(self.nodes[0].getblockcount(), 206) self.log.debug('Node should not stop at this height') - assert_raises(subprocess.TimeoutExpired, lambda: self.bitcoind_processes[0].wait(timeout=3)) + assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3)) try: self.nodes[0].generate(1) except (ConnectionError, http.client.BadStatusLine): pass # The node already shut down before response self.log.debug('Node should stop at this height...') - self.bitcoind_processes[0].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) self.nodes[0] = self.start_node(0, self.options.tmpdir) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index 9237f0924012..3c488f609a3e 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -41,8 +41,7 @@ def setup_network(self, split=False): self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) # Encrypt wallet for test_locked_wallet_fails test - self.nodes[1].encryptwallet(WALLET_PASSPHRASE) - self.bitcoind_processes[1].wait() + self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE) self.nodes[1] = self.start_node(1, self.options.tmpdir, extra_args[1]) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index e52e773918b0..f2f4efcf28f1 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -451,8 +451,7 @@ def run_test(self): self.stop_node(0) self.stop_node(2) self.stop_node(3) - self.nodes[1].encryptwallet("test") - self.bitcoind_processes[1].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[1].node_encrypt_wallet("test") self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) # This test is not meant to test fee estimation and we'd like diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index bbe1dda5f734..cca30e2688e4 100755 --- a/test/functional/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -17,7 +17,7 @@ def __init__(self, node): self.longpollid = templat['longpollid'] # create a new connection to the node, we can't use the same # connection from two threads - self.node = get_rpc_proxy(node.url, 1, timeout=600) + self.node = get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir) def run(self): self.node.getblocktemplate({'longpollid':self.longpollid}) diff --git a/test/functional/keypool.py b/test/functional/keypool.py index e8be559918d5..3e7bb0ee0720 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -17,8 +17,7 @@ def run_test(self): assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid']) # Encrypt wallet and wait to terminate - nodes[0].encryptwallet('test') - self.bitcoind_processes[0].wait() + nodes[0].node_encrypt_wallet('test') # Restart node 0 nodes[0] = self.start_node(0, self.options.tmpdir) # Keep creating keys diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index 5679f4050376..fc6e8e325f60 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -35,11 +35,15 @@ def run_test(self): self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) - w1 = self.nodes[0] / "wallet/w1" + w1 = self.nodes[0].get_wallet_rpc("w1") + w2 = self.nodes[0].get_wallet_rpc("w2") + w3 = self.nodes[0].get_wallet_rpc("w3") + wallet_bad = self.nodes[0].get_wallet_rpc("bad") + w1.generate(1) # accessing invalid wallet fails - assert_raises_jsonrpc(-18, "Requested wallet does not exist or is not loaded", (self.nodes[0] / "wallet/bad").getwalletinfo) + assert_raises_jsonrpc(-18, "Requested wallet does not exist or is not loaded", wallet_bad.getwalletinfo) # accessing wallet RPC without using wallet endpoint fails assert_raises_jsonrpc(-19, "Wallet file not specified", self.nodes[0].getwalletinfo) @@ -50,14 +54,12 @@ def run_test(self): w1_name = w1_info['walletname'] assert_equal(w1_name, "w1") - # check w1 wallet balance - w2 = self.nodes[0] / "wallet/w2" + # check w2 wallet balance w2_info = w2.getwalletinfo() assert_equal(w2_info['immature_balance'], 0) w2_name = w2_info['walletname'] assert_equal(w2_name, "w2") - w3 = self.nodes[0] / "wallet/w3" w3_name = w3.getwalletinfo()['walletname'] assert_equal(w3_name, "w3") diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index 951685aa7606..20808207b2bc 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -37,7 +37,7 @@ def run_bind_test(self, allow_ips, connect_to, addresses, expected): base_args += ['-rpcallowip=' + x for x in allow_ips] binds = ['-rpcbind='+addr for addr in addresses] self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to) - pid = self.bitcoind_processes[0].pid + pid = self.nodes[0].process.pid assert_equal(set(get_bind_addrs(pid)), set(expected)) self.stop_nodes() @@ -49,7 +49,7 @@ def run_allowip_test(self, allow_ips, rpchost, rpcport): base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) # connect to node through non-loopback interface - node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0) + node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) node.getnetworkinfo() self.stop_nodes() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index e562d119385f..7903bb00451b 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -5,15 +5,12 @@ """Base class for RPC testing.""" from collections import deque -import errno from enum import Enum -import http.client import logging import optparse import os import pdb import shutil -import subprocess import sys import tempfile import time @@ -21,6 +18,7 @@ from .authproxy import JSONRPCException from . import coverage +from .test_node import TestNode from .util import ( MAX_NODES, PortSeed, @@ -28,12 +26,9 @@ check_json_precision, connect_nodes_bi, disconnect_nodes, - get_rpc_proxy, initialize_datadir, - get_datadir_path, log_filename, p2p_port, - rpc_url, set_node_times, sync_blocks, sync_mempools, @@ -70,7 +65,6 @@ def __init__(self): self.num_nodes = 4 self.setup_clean_chain = False self.nodes = [] - self.bitcoind_processes = {} self.mocktime = 0 def add_options(self, parser): @@ -213,64 +207,62 @@ def main(self): def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): """Start a bitcoind and return RPC connection to it""" - datadir = os.path.join(dirname, "node" + str(i)) + if extra_args is None: + extra_args = [] if binary is None: binary = os.getenv("BITCOIND", "bitcoind") - args = [binary, "-datadir=" + datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(self.mocktime), "-uacomment=testnode%d" % i] - if extra_args is not None: - args.extend(extra_args) - self.bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr) - self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") - self._wait_for_bitcoind_start(self.bitcoind_processes[i], datadir, i, rpchost) - self.log.debug("initialize_chain: RPC successfully started") - proxy = get_rpc_proxy(rpc_url(datadir, i, rpchost), i, timeout=timewait) + node = TestNode(i, dirname, extra_args, rpchost, timewait, binary, stderr, self.mocktime, coverage_dir=self.options.coveragedir) + node.start() + node.wait_for_rpc_connection() - if self.options.coveragedir: - coverage.write_all_rpc_commands(self.options.coveragedir, proxy) + if self.options.coveragedir is not None: + coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) - return proxy + return node def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): """Start multiple bitcoinds, return RPC connections to them""" if extra_args is None: - extra_args = [None] * num_nodes + extra_args = [[]] * num_nodes if binary is None: binary = [None] * num_nodes assert_equal(len(extra_args), num_nodes) assert_equal(len(binary), num_nodes) - rpcs = [] + nodes = [] try: for i in range(num_nodes): - rpcs.append(self.start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i])) + nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) + nodes[i].start() + for node in nodes: + node.wait_for_rpc_connection() except: # If one node failed to start, stop the others - # TODO: abusing self.nodes in this way is a little hacky. - # Eventually we should do a better job of tracking nodes - self.nodes.extend(rpcs) self.stop_nodes() - self.nodes = [] raise - return rpcs + + if self.options.coveragedir is not None: + for node in nodes: + coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) + + return nodes def stop_node(self, i): """Stop a bitcoind test node""" - - self.log.debug("Stopping node %d" % i) - try: - self.nodes[i].stop() - except http.client.CannotSendRequest as e: - self.log.exception("Unable to stop node") - return_code = self.bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) - del self.bitcoind_processes[i] - assert_equal(return_code, 0) + self.nodes[i].stop_node() + while not self.nodes[i].is_node_stopped(): + time.sleep(0.1) def stop_nodes(self): """Stop multiple bitcoind test nodes""" + for node in self.nodes: + # Issue RPC to stop nodes + node.stop_node() - for i in range(len(self.nodes)): - self.stop_node(i) - assert not self.bitcoind_processes.values() # All connections must be gone now + for node in self.nodes: + # Wait for nodes to stop + while not node.is_node_stopped(): + time.sleep(0.1) def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: @@ -279,6 +271,8 @@ def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_m self.stop_node(i) except Exception as e: assert 'bitcoind exited' in str(e) # node must have shutdown + self.nodes[i].running = False + self.nodes[i].process = None if expected_msg is not None: log_stderr.seek(0) stderr = log_stderr.read().decode('utf-8') @@ -292,7 +286,7 @@ def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_m raise AssertionError(assert_msg) def wait_for_node_exit(self, i, timeout): - self.bitcoind_processes[i].wait(timeout) + self.nodes[i].process.wait(timeout) def split_network(self): """ @@ -389,18 +383,13 @@ def _initialize_chain(self, test_dir, num_nodes, cachedir): args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"] if i > 0: args.append("-connect=127.0.0.1:" + str(p2p_port(0))) - self.bitcoind_processes[i] = subprocess.Popen(args) - self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") - self._wait_for_bitcoind_start(self.bitcoind_processes[i], datadir, i) - self.log.debug("initialize_chain: RPC successfully started") + self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) + self.nodes[i].args = args + self.nodes[i].start() - self.nodes = [] - for i in range(MAX_NODES): - try: - self.nodes.append(get_rpc_proxy(rpc_url(get_datadir_path(cachedir, i), i), i)) - except: - self.log.exception("Error connecting to node %d" % i) - sys.exit(1) + # Wait for RPC connections to be ready + for node in self.nodes: + node.wait_for_rpc_connection() # Create a 200-block-long chain; each of the 4 first nodes # gets 25 mature blocks and 25 immature. @@ -444,30 +433,6 @@ def _initialize_chain_clean(self, test_dir, num_nodes): for i in range(num_nodes): initialize_datadir(test_dir, i) - def _wait_for_bitcoind_start(self, process, datadir, i, rpchost=None): - """Wait for bitcoind to start. - - This means that RPC is accessible and fully initialized. - Raise an exception if bitcoind exits during initialization.""" - while True: - if process.poll() is not None: - raise Exception('bitcoind exited with status %i during initialization' % process.returncode) - try: - # Check if .cookie file to be created - rpc = get_rpc_proxy(rpc_url(datadir, i, rpchost), i, coveragedir=self.options.coveragedir) - rpc.getblockcount() - break # break out of loop on success - except IOError as e: - if e.errno != errno.ECONNREFUSED: # Port not yet open? - raise # unknown IO error - except JSONRPCException as e: # Initialization phase - if e.error['code'] != -28: # RPC in warmup? - raise # unknown JSON RPC exception - except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting - if "No RPC credentials" not in str(e): - raise - time.sleep(0.25) - class ComparisonTestFramework(BitcoinTestFramework): """Test framework for doing p2p comparison testing diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py new file mode 100755 index 000000000000..66f89d43f4fc --- /dev/null +++ b/test/functional/test_framework/test_node.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Class for bitcoind node under test""" + +import errno +import http.client +import logging +import os +import subprocess +import time + +from .util import ( + assert_equal, + get_rpc_proxy, + rpc_url, +) +from .authproxy import JSONRPCException + +class TestNode(): + """A class for representing a bitcoind node under test. + + This class contains: + + - state about the node (whether it's running, etc) + - a Python subprocess.Popen object representing the running process + - an RPC connection to the node + + To make things easier for the test writer, a bit of magic is happening under the covers. + Any unrecognised messages will be dispatched to the RPC connection.""" + + def __init__(self, i, dirname, extra_args, rpchost, timewait, binary, stderr, mocktime, coverage_dir): + self.index = i + self.datadir = os.path.join(dirname, "node" + str(i)) + self.rpchost = rpchost + self.rpc_timeout = timewait + if binary is None: + self.binary = os.getenv("BITCOIND", "bitcoind") + else: + self.binary = binary + self.stderr = stderr + self.coverage_dir = coverage_dir + # Most callers will just need to add extra args to the standard list below. For those callers that need more flexibity, they can just set the args property directly. + self.extra_args = extra_args + self.args = [self.binary, "-datadir=" + self.datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime), "-uacomment=testnode%d" % i] + + self.running = False + self.process = None + self.rpc_connected = False + self.rpc = None + self.url = None + self.log = logging.getLogger('TestFramework.node%d' % i) + + def __getattr__(self, *args, **kwargs): + """Dispatches any unrecognised messages to the RPC connection.""" + assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection" + return self.rpc.__getattr__(*args, **kwargs) + + def start(self): + """Start the node.""" + self.process = subprocess.Popen(self.args + self.extra_args, stderr=self.stderr) + self.running = True + self.log.debug("bitcoind started, waiting for RPC to come up") + + def wait_for_rpc_connection(self): + """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" + + # Wait for up to 10 seconds for the RPC server to respond + for _ in range(40): + assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode + try: + self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) + self.rpc.getblockcount() + # If the call to getblockcount() succeeds then the RPC connection is up + self.rpc_connected = True + self.url = self.rpc.url + self.log.debug("RPC successfully started") + return + except IOError as e: + if e.errno != errno.ECONNREFUSED: # Port not yet open? + raise # unknown IO error + except JSONRPCException as e: # Initialization phase + if e.error['code'] != -28: # RPC in warmup? + raise # unknown JSON RPC exception + except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting + if "No RPC credentials" not in str(e): + raise + time.sleep(0.25) + raise AssertionError("Unable to connect to bitcoind") + + def get_wallet_rpc(self, wallet_name): + assert self.rpc_connected + assert self.rpc + wallet_path = "wallet/%s" % wallet_name + return self.rpc / wallet_path + + def stop_node(self): + """Stop the node.""" + if not self.running: + return + self.log.debug("Stopping node") + try: + self.stop() + except http.client.CannotSendRequest: + self.log.exception("Unable to stop node.") + + def is_node_stopped(self): + """Checks whether the node has stopped. + + Returns True if the node has stopped. False otherwise. + This method is responsible for freeing resources (self.process).""" + if not self.running: + return True + return_code = self.process.poll() + if return_code is not None: + # process has stopped. Assert that it didn't return an error code. + assert_equal(return_code, 0) + self.running = False + self.process = None + self.log.debug("Node stopped") + return True + return False + + def node_encrypt_wallet(self, passphrase): + """"Encrypts the wallet. + + This causes bitcoind to shutdown, so this method takes + care of cleaning up resources.""" + self.encryptwallet(passphrase) + while not self.is_node_stopped(): + time.sleep(0.1) + self.rpc = None + self.rpc_connected = False diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index acca72aa86e1..4098fd86152a 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -204,7 +204,7 @@ def rpc_port(n): return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) def rpc_url(datadir, i, rpchost=None): - rpc_u, rpc_p = get_auth_cookie(datadir, i) + rpc_u, rpc_p = get_auth_cookie(datadir) host = '127.0.0.1' port = rpc_port(i) if rpchost: @@ -232,7 +232,7 @@ def initialize_datadir(dirname, n): def get_datadir_path(dirname, n): return os.path.join(dirname, "node" + str(n)) -def get_auth_cookie(datadir, n): +def get_auth_cookie(datadir): user = None password = None if os.path.isfile(os.path.join(datadir, "bitcoin.conf")): diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index 569cc46e6cf9..61ad00330bd7 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -94,8 +94,7 @@ def run_test (self): assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys #encrypt wallet, restart, unlock and dump - self.nodes[0].encryptwallet('test') - self.bitcoind_processes[0].wait() + self.nodes[0].node_encrypt_wallet('test') self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) self.nodes[0].walletpassphrase('test', 10) # Should be a no-op: diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index ba72918fe156..8fea4140db75 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -30,8 +30,7 @@ def run_test(self): assert_equal(len(privkey), 52) # Encrypt the wallet - self.nodes[0].encryptwallet(passphrase) - self.bitcoind_processes[0].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].node_encrypt_wallet(passphrase) self.nodes[0] = self.start_node(0, self.options.tmpdir) # Test that the wallet is encrypted From 50bd3f626d7ce35d52543b88a2e512074f9df134 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 30 Jul 2017 23:36:33 +0200 Subject: [PATCH 034/196] Avoid returning a BIP9Stats object with uninitialized values Uninitialized data potentially used in `rpc/blockchain.cpp`: ``` static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id) { ... const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id); ... if (THRESHOLD_STARTED == thresholdState) { UniValue statsUV(UniValue::VOBJ); BIP9Stats statsStruct = VersionBitsTipStatistics(consensusParams, id); statsUV.push_back(Pair("period", statsStruct.period)); statsUV.push_back(Pair("threshold", statsStruct.threshold)); statsUV.push_back(Pair("elapsed", statsStruct.elapsed)); statsUV.push_back(Pair("count", statsStruct.count)); statsUV.push_back(Pair("possible", statsStruct.possible)); rv.push_back(Pair("statistics", statsUV)); } ... return rv; } ``` Github-Pull: #10957 Rebased-From: 3eb53b867153c957529484b5338d27e69de027c1 --- src/versionbits.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/versionbits.cpp b/src/versionbits.cpp index 04a692d82644..59588023ad77 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -107,7 +107,7 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* // return the numerical statistics of blocks signalling the specified BIP9 condition in this current period BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const { - BIP9Stats stats; + BIP9Stats stats = {}; stats.period = Period(params); stats.threshold = Threshold(params); From c276c1e1d1fb18771d9efabaf5a476d29c901d5d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 18 Aug 2017 22:09:58 +0200 Subject: [PATCH 035/196] test: Increase initial RPC timeout to 60 seconds When running the tests locally with a parallelism of 4 on an otherwise busy system, RPC can take quite a wait to come up. Change the timeout to 60 seconds just to be safe. Github-Pull: #11091 Rebased-From: c1470a058f21bf98d83b9dc345c61626b87035cc --- test/functional/test_framework/test_node.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 66f89d43f4fc..4b5dc9a792a4 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -65,9 +65,9 @@ def start(self): def wait_for_rpc_connection(self): """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" - - # Wait for up to 10 seconds for the RPC server to respond - for _ in range(40): + timeout_s = 60 # Wait for up to 60 seconds for the RPC server to respond + poll_per_s = 4 # Poll at a rate of four times per second + for _ in range(timeout_s*poll_per_s): assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode try: self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) @@ -86,7 +86,7 @@ def wait_for_rpc_connection(self): except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting if "No RPC credentials" not in str(e): raise - time.sleep(0.25) + time.sleep(1.0 / poll_per_s) raise AssertionError("Unable to connect to bitcoind") def get_wallet_rpc(self, wallet_name): From 1d80d1e319b41e5187d5949b3c22c35df182ba3c Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 16 Aug 2017 15:46:48 -0400 Subject: [PATCH 036/196] [tests] fix timeout issues from TestNode Fixes a couple of bugs from the introduction of TestNode: - test scripts were no longer able to specify a custom timeout for starting a node. Therefore tests with nodes that take a long time to start up (eg pruning.py) would fail. - the test for whether a node has failed on start up was broken by changing 'assert x is None' to 'assert not x'. Since subprocess.poll() can return None (indicating the node is still running) or 0 (indicating the node exited with return code 0), this was a regression. Github-Pull: #11077 Rebased-From: 2b4ea520b717b3ca894adbac17796786667764d3 --- test/functional/dbcrash.py | 7 ++++--- test/functional/test_framework/test_node.py | 14 +++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index 8339305f5e45..a7fcc411c345 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -64,7 +64,8 @@ def __init__(self): self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args] def setup_network(self): - self.setup_nodes() + # Need a bit of extra time for the nodes to start up for this test + self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) # Leave them unconnected, we'll use submitblock directly in this test def restart_node(self, node_index, expected_tip): @@ -74,10 +75,10 @@ def restart_node(self, node_index, expected_tip): after 60 seconds. Returns the utxo hash of the given node.""" time_start = time.time() - while time.time() - time_start < 60: + while time.time() - time_start < 120: try: # Any of these RPC calls could throw due to node crash - self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index]) + self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index], timewait=90) self.nodes[node_index].waitforblock(expected_tip) utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2'] return utxo_hash diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 4b5dc9a792a4..a803df5b4986 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -34,7 +34,11 @@ def __init__(self, i, dirname, extra_args, rpchost, timewait, binary, stderr, mo self.index = i self.datadir = os.path.join(dirname, "node" + str(i)) self.rpchost = rpchost - self.rpc_timeout = timewait + if timewait: + self.rpc_timeout = timewait + else: + # Wait for up to 60 seconds for the RPC server to respond + self.rpc_timeout = 60 if binary is None: self.binary = os.getenv("BITCOIND", "bitcoind") else: @@ -65,10 +69,10 @@ def start(self): def wait_for_rpc_connection(self): """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" - timeout_s = 60 # Wait for up to 60 seconds for the RPC server to respond - poll_per_s = 4 # Poll at a rate of four times per second - for _ in range(timeout_s*poll_per_s): - assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode + # Poll at a rate of four times per second + poll_per_s = 4 + for _ in range(poll_per_s * self.rpc_timeout): + assert self.process.poll() is None, "bitcoind exited with status %i during initialization" % self.process.returncode try: self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) self.rpc.getblockcount() From 5398f205e3ba1f7542deeba420f9e198bcb635f5 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 16 Aug 2017 18:17:34 +0200 Subject: [PATCH 037/196] qa: Move wait_until to util Github-Pull: #11068 Rebased-From: 08ce33f8e95efa81b37ddc6b3350462c61bbfd51 --- test/functional/bip65-cltv-p2p.py | 4 +- test/functional/bipdersig-p2p.py | 4 +- test/functional/disconnect_ban.py | 16 ++++---- test/functional/example_test.py | 4 +- test/functional/mempool_persist.py | 5 +-- test/functional/p2p-compactblocks.py | 47 ++++++++-------------- test/functional/p2p-leaktests.py | 14 +++---- test/functional/sendheaders.py | 6 +-- test/functional/test_framework/comptool.py | 12 +++--- test/functional/test_framework/mininode.py | 33 ++++----------- test/functional/test_framework/util.py | 22 ++++++++++ 11 files changed, 78 insertions(+), 89 deletions(-) diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index 7e5e4cf6820b..65ae8de554b6 100755 --- a/test/functional/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -109,7 +109,7 @@ def run_test(self): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until(lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)') @@ -138,7 +138,7 @@ def run_test(self): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until (lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD] assert_equal(node0.last_message["reject"].data, block.sha256) diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index 38a90095441c..977597089309 100755 --- a/test/functional/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -98,7 +98,7 @@ def run_test(self): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until(lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)') @@ -128,7 +128,7 @@ def run_test(self): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until (lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: # We can receive different reject messages depending on whether # bitcoind is running with multiple script check threads. If script diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index 89b68aeb25e6..19723226d3ca 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -5,11 +5,13 @@ """Test node disconnect and ban behavior""" import time -from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_equal, - assert_raises_jsonrpc, - connect_nodes_bi) +from test_framework.util import ( + assert_equal, + assert_raises_jsonrpc, + connect_nodes_bi, + wait_until, +) class DisconnectBanTest(BitcoinTestFramework): @@ -24,7 +26,7 @@ def run_test(self): self.log.info("setban: successfully ban single IP address") assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban("127.0.0.1", "add") - assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) + wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) @@ -90,7 +92,7 @@ def run_test(self): self.log.info("disconnectnode: successfully disconnect node by address") address1 = self.nodes[0].getpeerinfo()[0]['addr'] self.nodes[0].disconnectnode(address=address1) - assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] self.log.info("disconnectnode: successfully reconnect node") @@ -101,7 +103,7 @@ def run_test(self): self.log.info("disconnectnode: successfully disconnect node by node id") id1 = self.nodes[0].getpeerinfo()[0]['id'] self.nodes[0].disconnectnode(nodeid=id1) - assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1] if __name__ == '__main__': diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 7709524f2359..a54b5278e48d 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -23,13 +23,13 @@ mininode_lock, msg_block, msg_getdata, - wait_until, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, connect_nodes, p2p_port, + wait_until, ) # NodeConnCB is a class containing callbacks to be executed when a P2P @@ -209,7 +209,7 @@ def run_test(self): # wait_until() will loop until a predicate condition is met. Use it to test properties of the # NodeConnCB objects. - assert wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5) + wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5, lock=mininode_lock) self.log.info("Check that each block was received only once") # The network thread uses a global lock on data access to the NodeConn objects when sending and receiving diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index e0889fd5e9d8..807edeb7a832 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -32,7 +32,6 @@ """ import time -from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -69,7 +68,7 @@ def run_test(self): self.nodes.append(self.start_node(1, self.options.tmpdir)) # Give bitcoind a second to reload the mempool time.sleep(1) - assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) + wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) assert_equal(len(self.nodes[1].getrawmempool()), 0) self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") @@ -84,7 +83,7 @@ def run_test(self): self.stop_nodes() self.nodes = [] self.nodes.append(self.start_node(0, self.options.tmpdir)) - assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) + wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) if __name__ == '__main__': MempoolPersistTest().main() diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py index ff76e49fba78..c5c264765a3f 100755 --- a/test/functional/p2p-compactblocks.py +++ b/test/functional/p2p-compactblocks.py @@ -70,7 +70,7 @@ def send_header_for_blocks(self, new_blocks): def request_headers_and_sync(self, locator, hashstop=0): self.clear_block_announcement() self.get_headers(locator, hashstop) - assert wait_until(self.received_block_announcement, timeout=30) + wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock) self.clear_block_announcement() # Block until a block announcement for a particular block hash is @@ -78,7 +78,7 @@ def request_headers_and_sync(self, locator, hashstop=0): def wait_for_block_announcement(self, block_hash, timeout=30): def received_hash(): return (block_hash in self.announced_blockhashes) - return wait_until(received_hash, timeout=timeout) + wait_until(received_hash, timeout=timeout, lock=mininode_lock) def send_await_disconnect(self, message, timeout=30): """Sends a message to the node and wait for disconnect. @@ -86,11 +86,7 @@ def send_await_disconnect(self, message, timeout=30): This is used when we want to send a message into the node that we expect will get us disconnected, eg an invalid block.""" self.send_message(message) - success = wait_until(lambda: not self.connected, timeout=timeout) - if not success: - logger.error("send_await_disconnect failed!") - raise AssertionError("send_await_disconnect failed!") - return success + wait_until(lambda: not self.connected, timeout=timeout, lock=mininode_lock) class CompactBlocksTest(BitcoinTestFramework): def __init__(self): @@ -150,9 +146,7 @@ def test_sendcmpct(self, node, test_node, preferred_version, old_node=None): # Make sure we get a SENDCMPCT message from our peer def received_sendcmpct(): return (len(test_node.last_sendcmpct) > 0) - got_message = wait_until(received_sendcmpct, timeout=30) - assert(received_sendcmpct()) - assert(got_message) + wait_until(received_sendcmpct, timeout=30, lock=mininode_lock) with mininode_lock: # Check that the first version received is the preferred one assert_equal(test_node.last_sendcmpct[0].version, preferred_version) @@ -167,7 +161,6 @@ def check_announcement_of_new_block(node, peer, predicate): 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), ( @@ -282,7 +275,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a # Wait until we've seen the block announcement for the resulting tip tip = int(node.getbestblockhash(), 16) - assert(test_node.wait_for_block_announcement(tip)) + test_node.wait_for_block_announcement(tip) # Make sure we will receive a fast-announce compact block self.request_cb_announcements(test_node, node, version) @@ -297,8 +290,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a block.rehash() # Wait until the block was announced (via compact blocks) - wait_until(test_node.received_block_announcement, timeout=30) - assert(test_node.received_block_announcement()) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) # Now fetch and check the compact block header_and_shortids = None @@ -314,8 +306,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a inv = CInv(4, block_hash) # 4 == "CompactBlock" test_node.send_message(msg_getdata([inv])) - wait_until(test_node.received_block_announcement, timeout=30) - assert(test_node.received_block_announcement()) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) # Now fetch and check the compact block header_and_shortids = None @@ -386,13 +377,11 @@ def test_compactblock_requests(self, node, test_node, version, segwit): if announce == "inv": test_node.send_message(msg_inv([CInv(2, block.sha256)])) - success = wait_until(lambda: "getheaders" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock) test_node.send_header_for_blocks([block]) else: test_node.send_header_for_blocks([block]) - success = wait_until(lambda: "getdata" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "getdata" in test_node.last_message, timeout=30, lock=mininode_lock) assert_equal(len(test_node.last_message["getdata"].inv), 1) assert_equal(test_node.last_message["getdata"].inv[0].type, 4) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) @@ -571,8 +560,7 @@ def test_incorrect_blocktxn_response(self, node, test_node, version): assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) # We should receive a getdata request - success = wait_until(lambda: "getdata" in test_node.last_message, timeout=10) - assert(success) + wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock) assert_equal(len(test_node.last_message["getdata"].inv), 1) assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) @@ -599,8 +587,7 @@ def test_getblocktxn_handler(self, node, test_node, version): num_to_request = random.randint(1, len(block.vtx)) msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request))) test_node.send_message(msg) - success = wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) - assert(success) + wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10, lock=mininode_lock) [tx.calc_sha256() for tx in block.vtx] with mininode_lock: @@ -639,22 +626,20 @@ def test_compactblocks_not_at_tip(self, node, test_node): 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) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) test_node.clear_block_announcement() test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))])) - success = wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock) test_node.clear_block_announcement() node.generate(1) - wait_until(test_node.received_block_announcement, timeout=30) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) test_node.clear_block_announcement() with mininode_lock: test_node.last_message.pop("block", None) test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))])) - success = wait_until(lambda: "block" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock) with mininode_lock: test_node.last_message["block"].block.calc_sha256() assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16)) @@ -705,7 +690,7 @@ def test_end_to_end_block_relay(self, node, listeners): node.submitblock(ToHex(block)) for l in listeners: - wait_until(lambda: l.received_block_announcement(), timeout=30) + wait_until(lambda: l.received_block_announcement(), timeout=30, lock=mininode_lock) with mininode_lock: for l in listeners: assert "cmpctblock" in l.last_message diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index 5611c876ae35..f0d4d9a8b86c 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -119,11 +119,11 @@ def run_test(self): NetworkThread().start() # Start up network handling in another thread - assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10) - assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10) - assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10) - assert wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10) - assert wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10) + wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock) + wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock) + wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock) + wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10, lock=mininode_lock) + wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10, lock=mininode_lock) # Mine a block and make sure that it's not sent to the connected nodes self.nodes[0].generate(1) @@ -158,8 +158,8 @@ def run_test(self): allowed_service_bit5_node.add_connection(connections[5]) allowed_service_bit7_node.add_connection(connections[6]) - assert wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10) - assert wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10) + wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10, lock=mininode_lock) + wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10, lock=mininode_lock) if __name__ == '__main__': P2PLeakTest().main() diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index e47e07fb868b..6451b097c07d 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -128,7 +128,7 @@ def check_last_announcement(self, headers=None, inv=None): expect_headers = headers if headers != None else [] expect_inv = inv if inv != None else [] test_function = lambda: self.block_announced - assert(wait_until(test_function, timeout=60)) + wait_until(test_function, timeout=60, lock=mininode_lock) with mininode_lock: self.block_announced = False @@ -155,12 +155,12 @@ def wait_for_getdata(self, hash_list, timeout=60): return test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list - assert(wait_until(test_function, timeout=timeout)) + wait_until(test_function, timeout=timeout, lock=mininode_lock) return def wait_for_block_announcement(self, block_hash, timeout=60): test_function = lambda: self.last_blockhash_announced == block_hash - assert(wait_until(test_function, timeout=timeout)) + wait_until(test_function, timeout=timeout, lock=mininode_lock) return def send_header_for_blocks(self, new_blocks): diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py index 9f062865a3e2..bfbc0c3b0340 100755 --- a/test/functional/test_framework/comptool.py +++ b/test/functional/test_framework/comptool.py @@ -19,7 +19,7 @@ from .mininode import * from .blockstore import BlockStore, TxStore -from .util import p2p_port +from .util import p2p_port, wait_until import logging @@ -189,7 +189,7 @@ def clear_all_connections(self): def wait_for_disconnections(self): def disconnected(): return all(node.closed for node in self.test_nodes) - return wait_until(disconnected, timeout=10) + wait_until(disconnected, timeout=10, lock=mininode_lock) def wait_for_verack(self): return all(node.wait_for_verack() for node in self.test_nodes) @@ -197,7 +197,7 @@ def wait_for_verack(self): def wait_for_pings(self, counter): def received_pongs(): return all(node.received_ping_response(counter) for node in self.test_nodes) - return wait_until(received_pongs) + wait_until(received_pongs, lock=mininode_lock) # sync_blocks: Wait for all connections to request the blockhash given # then send get_headers to find out the tip of each node, and synchronize @@ -210,8 +210,7 @@ def blocks_requested(): ) # --> error if not requested - if not wait_until(blocks_requested, attempts=20*num_blocks): - raise AssertionError("Not all nodes requested block") + wait_until(blocks_requested, attempts=20*num_blocks, lock=mininode_lock) # Send getheaders message [ c.cb.send_getheaders() for c in self.connections ] @@ -231,8 +230,7 @@ def transaction_requested(): ) # --> error if not requested - if not wait_until(transaction_requested, attempts=20*num_events): - raise AssertionError("Not all nodes requested transaction") + wait_until(transaction_requested, attempts=20*num_events, lock=mininode_lock) # Get the mempool [ c.cb.send_mempool() for c in self.connections ] diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index a4d85501e7e3..d0753276db2b 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -35,7 +35,7 @@ from threading import RLock, Thread from test_framework.siphash import siphash256 -from test_framework.util import hex_str_to_bytes, bytes_to_hex_str +from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, wait_until BIP0031_VERSION = 60000 MY_VERSION = 70014 # past bip-31 for ping/pong @@ -1358,23 +1358,6 @@ def __repr__(self): return "msg_reject: %s %d %s [%064x]" \ % (self.message, self.code, self.reason, self.data) -# Helper function -def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf')): - if attempts == float('inf') and timeout == float('inf'): - timeout = 60 - attempt = 0 - elapsed = 0 - - while attempt < attempts and elapsed < timeout: - with mininode_lock: - if predicate(): - return True - attempt += 1 - elapsed += 0.05 - time.sleep(0.05) - - return False - class msg_feefilter(object): command = b"feefilter" @@ -1591,21 +1574,21 @@ def add_connection(self, conn): def wait_for_disconnect(self, timeout=60): test_function = lambda: not self.connected - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) # Message receiving helper methods def wait_for_block(self, blockhash, timeout=60): test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_getdata(self, timeout=60): test_function = lambda: self.last_message.get("getdata") - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_getheaders(self, timeout=60): test_function = lambda: self.last_message.get("getheaders") - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_inv(self, expected_inv, timeout=60): """Waits for an INV message and checks that the first inv object in the message was as expected.""" @@ -1614,11 +1597,11 @@ def wait_for_inv(self, expected_inv, timeout=60): test_function = lambda: self.last_message.get("inv") and \ self.last_message["inv"].inv[0].type == expected_inv[0].type and \ self.last_message["inv"].inv[0].hash == expected_inv[0].hash - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_verack(self, timeout=60): test_function = lambda: self.message_count["verack"] - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) # Message sending helper functions @@ -1636,7 +1619,7 @@ def send_and_ping(self, message): def sync_with_ping(self, timeout=60): self.send_message(msg_ping(nonce=self.ping_counter)) test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) self.ping_counter += 1 return True diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 4098fd86152a..a14cda07d0cb 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -157,6 +157,28 @@ def str_to_b64str(string): def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) +def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None): + if attempts == float('inf') and timeout == float('inf'): + timeout = 60 + attempt = 0 + timeout += time.time() + + while attempt < attempts and time.time() < timeout: + if lock: + with lock: + if predicate(): + return + else: + if predicate(): + return + attempt += 1 + time.sleep(0.05) + + # Print the cause of the timeout + assert_greater_than(attempts, attempt) + assert_greater_than(timeout, time.time()) + raise RuntimeError('Unreachable') + # RPC/P2P connection constants and functions ############################################ From 016b9ada2111aaf41f3336c0179a1347355bc9e6 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 11 Jul 2017 13:01:44 -0400 Subject: [PATCH 038/196] [tests] add TestNodeCLI class for calling bitcoin-cli for a node Github-Pull: #10798 Rebased-From: b23549f6e677a8e22953568704eac7ea0c2c1289 --- test/functional/test_framework/test_node.py | 29 +++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 30 insertions(+) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index a803df5b4986..7c1325e69147 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -4,8 +4,10 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Class for bitcoind node under test""" +import decimal import errno import http.client +import json import logging import os import subprocess @@ -49,6 +51,8 @@ def __init__(self, i, dirname, extra_args, rpchost, timewait, binary, stderr, mo self.extra_args = extra_args self.args = [self.binary, "-datadir=" + self.datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime), "-uacomment=testnode%d" % i] + self.cli = TestNodeCLI(os.getenv("BITCOINCLI", "bitcoin-cli"), self.datadir) + self.running = False self.process = None self.rpc_connected = False @@ -136,3 +140,28 @@ def node_encrypt_wallet(self, passphrase): time.sleep(0.1) self.rpc = None self.rpc_connected = False + +class TestNodeCLI(): + """Interface to bitcoin-cli for an individual node""" + + def __init__(self, binary, datadir): + self.binary = binary + self.datadir = datadir + + def __getattr__(self, command): + def dispatcher(*args, **kwargs): + return self.send_cli(command, *args, **kwargs) + return dispatcher + + def send_cli(self, command, *args, **kwargs): + """Run bitcoin-cli command. Deserializes returned string as python object.""" + + pos_args = [str(arg) for arg in args] + named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()] + assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call" + p_args = [self.binary, "-datadir=" + self.datadir] + if named_args: + p_args += ["-named"] + p_args += [command] + pos_args + named_args + cli_output = subprocess.check_output(p_args, universal_newlines=True) + return json.loads(cli_output, parse_float=decimal.Decimal) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 93f180555d2e..01236b607e61 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -279,6 +279,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove #Set env vars if "BITCOIND" not in os.environ: os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext + os.environ["BITCOINCLI"] = build_dir + '/src/bitcoin-cli' + exeext tests_dir = src_dir + '/test/functional/' From 716066dbea0e448b78838a692c4627a9e32fcec2 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 11 Jul 2017 13:02:01 -0400 Subject: [PATCH 039/196] [tests] Add bitcoin_cli.py test script Github-Pull: #10798 Rebased-From: c6ec4358a797b7a11283238a0cf0b4531def9e92 --- test/functional/bitcoin_cli.py | 26 ++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 27 insertions(+) create mode 100755 test/functional/bitcoin_cli.py diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py new file mode 100755 index 000000000000..103320209268 --- /dev/null +++ b/test/functional/bitcoin_cli.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test bitcoin-cli""" +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +class TestBitcoinCli(BitcoinTestFramework): + + def __init__(self): + super().__init__() + self.setup_clean_chain = True + self.num_nodes = 1 + + def run_test(self): + """Main test logic""" + + self.log.info("Compare responses from getinfo RPC and `bitcoin-cli getinfo`") + cli_get_info = self.nodes[0].cli.getinfo() + rpc_get_info = self.nodes[0].getinfo() + + assert_equal(cli_get_info, rpc_get_info) + +if __name__ == '__main__': + TestBitcoinCli().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 01236b607e61..fae4f66d70cd 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -81,6 +81,7 @@ # vv Tests less than 30s vv 'keypool-topup.py', 'zmq_test.py', + 'bitcoin_cli.py', 'mempool_resurrect_test.py', 'txn_doublespend.py --mineblock', 'txn_clone.py', From b278a43646c8fb331a1b830b09a60ec2544dd6b6 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 25 Aug 2017 12:39:30 +0200 Subject: [PATCH 040/196] rpc: Write authcookie atomically Use POSIX rename atomicity at the `bitcoind` side to create a working cookie atomically: - Write `.cookie.tmp`, close file - Rename `.cookie.tmp` to `.cookie` This avoids clients reading invalid/partial cookies as in #11129. Github-Pull: #11131 Rebased-From: 82dd7195e1fb943f9cd45a48188f9678219c0206 --- src/rpc/protocol.cpp | 21 ++++++++++++++++----- src/rpc/protocol.h | 2 -- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp index db0626b5e1ca..dc6bcec382fb 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -66,9 +66,14 @@ static const std::string COOKIEAUTH_USER = "__cookie__"; /** Default name for auth cookie file */ static const std::string COOKIEAUTH_FILE = ".cookie"; -fs::path GetAuthCookieFile() +/** Get name of RPC authentication cookie file */ +static fs::path GetAuthCookieFile(bool temp=false) { - fs::path path(gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE)); + std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE); + if (temp) { + arg += ".tmp"; + } + fs::path path(arg); if (!path.is_complete()) path = GetDataDir() / path; return path; } @@ -84,14 +89,20 @@ bool GenerateAuthCookie(std::string *cookie_out) * these are set to 077 in init.cpp unless overridden with -sysperms. */ std::ofstream file; - fs::path filepath = GetAuthCookieFile(); - file.open(filepath.string().c_str()); + fs::path filepath_tmp = GetAuthCookieFile(true); + file.open(filepath_tmp.string().c_str()); if (!file.is_open()) { - LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string()); + LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string()); return false; } file << cookie; file.close(); + + fs::path filepath = GetAuthCookieFile(false); + if (!RenameOver(filepath_tmp, filepath)) { + LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string()); + return false; + } LogPrintf("Generated RPC authentication cookie %s\n", filepath.string()); if (cookie_out) diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 4bd4702d6244..5c9c64f67d1c 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -91,8 +91,6 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); UniValue JSONRPCError(int code, const std::string& message); -/** Get name of RPC authentication cookie file */ -fs::path GetAuthCookieFile(); /** Generate a new RPC authentication cookie and write it to disk */ bool GenerateAuthCookie(std::string *cookie_out); /** Read the RPC authentication cookie from disk */ From 2cb720ae6122101c83a8836da057a5a7cba5b5df Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Thu, 24 Aug 2017 14:12:21 -0400 Subject: [PATCH 041/196] Acquire cs_main lock before cs_wallet during wallet initialization CWallet::MarkConflicted may acquire the cs_main lock after CWalletDB::LoadWallet acquires the cs_wallet lock during wallet initialization. (CWalletDB::LoadWallet calls ReadKeyValue which calls CWallet::LoadToWallet which calls CWallet::MarkConflicted). This is the opposite order that cs_main and cs_wallet locks are acquired in the rest of the code, and so leads to POTENTIAL DEADLOCK DETECTED errors if bitcoin is built with -DDEBUG_LOCKORDER. This commit changes CWallet::LoadWallet (which calls CWalletDB::LoadWallet) to acquire both locks in the standard order. It also fixes some tests that were acquiring wallet and main locks out of order and failed with the new locking in CWallet::LoadWallet. Error was reported by Luke Dashjr in https://botbot.me/freenode/bitcoin-core-dev/msg/90244330/ Github-Pull: #11126 Rebased-From: de9a1db2ed14e0c75ffd82dc031f7ad30c56d195 --- src/wallet/test/wallet_tests.cpp | 17 ++++++++++------- src/wallet/wallet.cpp | 3 ++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 4a2cc9a13993..5ebacd57d3ab 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -364,6 +364,12 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset) empty_wallet(); } +static void AddKey(CWallet& wallet, const CKey& key) +{ + LOCK(wallet.cs_wallet); + wallet.AddKeyPubKey(key, key.GetPubKey()); +} + BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) { LOCK(cs_main); @@ -379,8 +385,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) // and new block files. { CWallet wallet; - LOCK(wallet.cs_wallet); - wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); + AddKey(wallet, coinbaseKey); BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip)); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); } @@ -393,8 +398,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) // file. { CWallet wallet; - LOCK(wallet.cs_wallet); - wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); + AddKey(wallet, coinbaseKey); BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip)); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); } @@ -599,8 +603,7 @@ class ListCoinsTestingSetup : public TestChain100Setup wallet.reset(new CWallet(std::unique_ptr(new CWalletDBWrapper(&bitdb, "wallet_test.dat")))); bool firstRun; wallet->LoadWallet(firstRun); - LOCK(wallet->cs_wallet); - wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); + AddKey(*wallet, coinbaseKey); wallet->ScanForWalletTransactions(chainActive.Genesis()); } @@ -635,7 +638,7 @@ class ListCoinsTestingSetup : public TestChain100Setup BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) { std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString(); - LOCK(wallet->cs_wallet); + LOCK2(cs_main, wallet->cs_wallet); // Confirm ListCoins initially returns 1 coin grouped under coinbaseKey // address. diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 318c159cfb23..bf8981e4e871 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3101,13 +3101,14 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_c DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { + LOCK2(cs_main, cs_wallet); + fFirstRunRet = false; DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { - LOCK(cs_wallet); setInternalKeyPool.clear(); setExternalKeyPool.clear(); m_pool_key_to_index.clear(); From 2a5d099e47c896a7a3bd0015ca179587257b7792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 18 Jul 2017 02:19:21 +0200 Subject: [PATCH 042/196] RPC: gettxout: Slightly improve doc and tests Github-Pull: #10859 Rebased-From: 6d2d2eb49389d70a5db327e133c9c90748f82d5f --- src/rpc/blockchain.cpp | 7 ++++--- test/functional/wallet.py | 12 ++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 34bcdf9cccb4..720eb068bf65 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -944,9 +944,10 @@ UniValue gettxout(const JSONRPCRequest& request) "gettxout \"txid\" n ( include_mempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" - "2. n (numeric, required) vout number\n" - "3. include_mempool (boolean, optional) Whether to include the mempool\n" + "1. \"txid\" (string, required) The transaction id\n" + "2. \"n\" (numeric, required) vout number\n" + "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true." + " Note that an unspent output that is spent in the mempool won't appear.\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 3e3e8fcddb38..a37c457bc813 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -56,6 +56,15 @@ def run_test(self): assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) + self.log.info("test gettxout") + confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] + # First, outputs that are unspent both in the chain and in the + # mempool should appear with or without include_mempool + txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) + assert_equal(txout['value'], 50) + txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) + assert_equal(txout['value'], 50) + # Send 21 BTC from 0 to 2 using sendtoaddress call. # Locked memory should use at least 32 bytes to sign each transaction self.log.info("test getmemoryinfo") @@ -65,10 +74,9 @@ def run_test(self): memory_after = self.nodes[0].getmemoryinfo() assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used']) - self.log.info("test gettxout") + self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool - confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) From 847c75ec6447f58b6c4f3732a10551f1faddbb0b Mon Sep 17 00:00:00 2001 From: Cristian Mircea Messel Date: Sat, 26 Aug 2017 01:20:33 +0300 Subject: [PATCH 043/196] Add getmininginfo functional test Github-Pull: #11150 Rebased-From: 4f2905b76b502a9de235dbe739e5fe504ef5bc22 --- test/functional/mining.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/functional/mining.py b/test/functional/mining.py index dbd4e29ecae8..f3d1f3e90afb 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -4,16 +4,18 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test mining RPCs +- getmininginfo - getblocktemplate proposal mode - submitblock""" -from binascii import b2a_hex import copy +from binascii import b2a_hex +from decimal import Decimal from test_framework.blocktools import create_coinbase -from test_framework.test_framework import BitcoinTestFramework from test_framework.mininode import CBlock -from test_framework.util import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_raises_jsonrpc def b2x(b): return b2a_hex(b).decode('ascii') @@ -33,6 +35,18 @@ def __init__(self): def run_test(self): node = self.nodes[0] + + self.log.info('getmininginfo') + mining_info = node.getmininginfo() + assert_equal(mining_info['blocks'], 200) + assert_equal(mining_info['chain'], 'regtest') + assert_equal(mining_info['currentblocksize'], 0) + assert_equal(mining_info['currentblocktx'], 0) + assert_equal(mining_info['currentblockweight'], 0) + assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10')) + assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334')) + assert_equal(mining_info['pooledtx'], 0) + # Mine a block to leave initial block download node.generate(1) tmpl = node.getblocktemplate() From 11a5992c90d4cc9a3823ea08dab2c078bcbf15d2 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 23 Aug 2017 15:49:01 -0400 Subject: [PATCH 044/196] [tests] fix - use rpc_timeout as rpc timeout Github-Pull: #11121 Rebased-From: be2a2ab6a67beef97e3c3cf42bd5eeea6c4e55cf --- test/functional/test_framework/test_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 7c1325e69147..553c7c9d2022 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -78,7 +78,7 @@ def wait_for_rpc_connection(self): for _ in range(poll_per_s * self.rpc_timeout): assert self.process.poll() is None, "bitcoind exited with status %i during initialization" % self.process.returncode try: - self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) + self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir) self.rpc.getblockcount() # If the call to getblockcount() succeeds then the RPC connection is up self.rpc_connected = True From 4d3ba18386c7a09086d06c8b640c19343ff34188 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 9 Jun 2017 16:35:17 -0400 Subject: [PATCH 045/196] [tests] TestNode: separate add_node from start_node Separates the act of creating a TestNode object from starting the node. The test_framework now keeps track of its list of TestNodes, and test writers can call start_node() and stop_node() without having to update the self.nodes list. Github-Pull: #11121 Rebased-From: 36b626867087e9fae6d85f926248997ebff327b7 --- test/functional/abandonconflict.py | 6 +- test/functional/assumevalid.py | 9 +- test/functional/bip9-softforks.py | 1 + test/functional/blockchain.py | 2 +- test/functional/bumpfee.py | 11 +-- test/functional/create_cache.py | 1 - test/functional/dbcrash.py | 5 +- test/functional/disconnect_ban.py | 2 +- test/functional/forknotify.py | 13 +-- test/functional/fundrawtransaction.py | 4 +- test/functional/import-rescan.py | 3 +- test/functional/importmulti.py | 2 +- test/functional/keypool-topup.py | 4 +- test/functional/keypool.py | 2 +- test/functional/listtransactions.py | 4 - test/functional/maxuploadtarget.py | 2 +- test/functional/mempool_persist.py | 11 +-- test/functional/multiwallet.py | 8 +- test/functional/p2p-segwit.py | 2 +- test/functional/p2p-versionbits-warning.py | 4 +- test/functional/proxy_test.py | 3 +- test/functional/pruning.py | 24 +++-- test/functional/receivedby.py | 4 - test/functional/reindex.py | 2 +- test/functional/resendwallettransactions.py | 2 +- test/functional/rpcbind_test.py | 13 +-- test/functional/smartfees.py | 89 ++++++++++--------- .../test_framework/test_framework.py | 65 +++++++------- test/functional/test_framework/test_node.py | 8 +- test/functional/wallet-dump.py | 5 +- test/functional/wallet-encryption.py | 2 +- test/functional/wallet-hd.py | 8 +- test/functional/wallet.py | 61 +++++++------ test/functional/walletbackup.py | 6 +- test/functional/zapwallettxes.py | 6 +- test/functional/zmq_test.py | 5 +- 36 files changed, 202 insertions(+), 197 deletions(-) diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py index c87c02492d7c..1db04337a96f 100755 --- a/test/functional/abandonconflict.py +++ b/test/functional/abandonconflict.py @@ -74,7 +74,7 @@ def run_test(self): # Restart the node with a higher min relay fee so the parent tx is no longer in mempool # TODO: redo with eviction self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) + self.start_node(0, extra_args=["-minrelaytxfee=0.0001"]) # Verify txs no longer in either node's mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) @@ -101,7 +101,7 @@ def run_test(self): # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"]) + self.start_node(0, extra_args=["-minrelaytxfee=0.00001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) @@ -121,7 +121,7 @@ def run_test(self): # Remove using high relay fee again self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) + self.start_node(0, extra_args=["-minrelaytxfee=0.0001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("24.9996")) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index 9d17faac51ba..63e6a384a45d 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -60,10 +60,11 @@ def __init__(self): self.num_nodes = 3 def setup_network(self): + self.add_nodes(3, self.options.tmpdir) # Start node0. We don't start the other nodes yet since # we need to pre-mine a block with an invalid transaction # signature so we can pass in the block hash as assumevalid. - self.nodes = [self.start_node(0, self.options.tmpdir)] + self.start_node(0) def send_blocks_until_disconnected(self, node): """Keep sending blocks to the node until we're disconnected.""" @@ -162,15 +163,13 @@ def run_test(self): height += 1 # Start node1 and node2 with assumevalid so they accept a block with a bad signature. - self.nodes.append(self.start_node(1, self.options.tmpdir, - ["-assumevalid=" + hex(block102.sha256)])) + self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)]) node1 = BaseNode() # connects to node1 connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1)) node1.add_connection(connections[1]) node1.wait_for_verack() - self.nodes.append(self.start_node(2, self.options.tmpdir, - ["-assumevalid=" + hex(block102.sha256)])) + self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)]) node2 = BaseNode() # connects to node2 connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2)) node2.add_connection(connections[2]) diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py index f00232c9ffe0..ad16482550ce 100755 --- a/test/functional/bip9-softforks.py +++ b/test/functional/bip9-softforks.py @@ -241,6 +241,7 @@ def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignatu # Restart all self.test.clear_all_connections() self.stop_nodes() + self.nodes = [] shutil.rmtree(self.options.tmpdir + "/node0") self.setup_chain() self.setup_network() diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 0812e1b0df90..a3a6cf2fb868 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -146,7 +146,7 @@ def _test_stopatheight(self): pass # The node already shut down before response self.log.debug('Node should stop at this height...') self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index 3c488f609a3e..59c65f18e89d 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -34,21 +34,18 @@ def __init__(self): super().__init__() self.num_nodes = 2 self.setup_clean_chain = True + self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] + for i in range(self.num_nodes)] - def setup_network(self, split=False): - extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] - for i in range(self.num_nodes)] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) - + def run_test(self): # Encrypt wallet for test_locked_wallet_fails test self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE) - self.nodes[1] = self.start_node(1, self.options.tmpdir, extra_args[1]) + self.start_node(1) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() - def run_test(self): peer_node, rbf_node = self.nodes rbf_node_address = rbf_node.getnewaddress() diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 39c4c0f47edc..1a5754b3f739 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -18,7 +18,6 @@ def __init__(self): # Test network and test nodes are not required: self.num_nodes = 0 - self.nodes = [] def setup_network(self): pass diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index a7fcc411c345..d39369105bf6 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -65,7 +65,8 @@ def __init__(self): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) + self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test def restart_node(self, node_index, expected_tip): @@ -78,7 +79,7 @@ def restart_node(self, node_index, expected_tip): while time.time() - time_start < 120: try: # Any of these RPC calls could throw due to node crash - self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index], timewait=90) + self.start_node(node_index) self.nodes[node_index].waitforblock(expected_tip) utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2'] return utxo_hash diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index 19723226d3ca..cc8901c40ca5 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -68,8 +68,8 @@ def run_test(self): assert_equal(len(self.nodes[1].listbanned()), 3) self.stop_node(1) + self.start_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir) listAfterShutdown = self.nodes[1].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py index 3bcf0a679511..3a2a927098e0 100755 --- a/test/functional/forknotify.py +++ b/test/functional/forknotify.py @@ -7,7 +7,6 @@ import time from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * class ForkNotifyTest(BitcoinTestFramework): @@ -17,18 +16,12 @@ def __init__(self): self.setup_clean_chain = False def setup_network(self): - self.nodes = [] self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") with open(self.alert_filename, 'w', encoding='utf8'): pass # Just open then close to create zero-length file - self.nodes.append(self.start_node(0, self.options.tmpdir, - ["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])) - # Node1 mines block.version=211 blocks - self.nodes.append(self.start_node(1, self.options.tmpdir, - ["-blockversion=211"])) - connect_nodes(self.nodes[1], 0) - - self.sync_all() + self.extra_args = [["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""], + ["-blockversion=211"]] + super().setup_network() def run_test(self): # Mine 51 up-version blocks diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index f2f4efcf28f1..242b6eed108c 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -449,11 +449,11 @@ def run_test(self): ############################################################ # locked wallet test self.stop_node(0) + self.nodes[1].node_encrypt_wallet("test") self.stop_node(2) self.stop_node(3) - self.nodes[1].node_encrypt_wallet("test") - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) + self.start_nodes() # This test is not meant to test fee estimation and we'd like # to be sure all txs are sent at a consistent desired feerate for node in self.nodes: diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index 4fc507821760..be52d5c8472d 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -121,7 +121,8 @@ def setup_network(self): if import_node.prune: extra_args[i] += ["-prune=1"] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.start_nodes() for i in range(1, self.num_nodes): connect_nodes(self.nodes[i], 0) diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index e83e85de138e..6aae95549de9 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -429,7 +429,7 @@ def run_test (self): # restart nodes to check for proper serialization/deserialization of watch only address self.stop_nodes() - self.nodes = self.start_nodes(2, self.options.tmpdir) + self.start_nodes() address_assert = self.nodes[1].validateaddress(watchonly_address) assert_equal(address_assert['iswatchonly'], True) assert_equal(address_assert['ismine'], False) diff --git a/test/functional/keypool-topup.py b/test/functional/keypool-topup.py index 0e0c0ea74bb2..f14a449b5919 100755 --- a/test/functional/keypool-topup.py +++ b/test/functional/keypool-topup.py @@ -35,7 +35,7 @@ def run_test(self): self.stop_node(1) shutil.copyfile(self.tmpdir + "/node1/regtest/wallet.dat", self.tmpdir + "/wallet.bak") - self.nodes[1] = self.start_node(1, self.tmpdir, self.extra_args[1]) + self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.log.info("Generate keys for wallet") @@ -61,7 +61,7 @@ def run_test(self): self.log.info("Verify keypool is restored and balance is correct") - self.nodes[1] = self.start_node(1, self.tmpdir, self.extra_args[1]) + self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() diff --git a/test/functional/keypool.py b/test/functional/keypool.py index 3e7bb0ee0720..0f84b5c05501 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -19,7 +19,7 @@ def run_test(self): # Encrypt wallet and wait to terminate nodes[0].node_encrypt_wallet('test') # Restart node 0 - nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) # Keep creating keys addr = nodes[0].getnewaddress() addr_data = nodes[0].validateaddress(addr) diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py index f75a8e29cc7a..9b970284171d 100755 --- a/test/functional/listtransactions.py +++ b/test/functional/listtransactions.py @@ -20,11 +20,7 @@ def __init__(self): super().__init__() self.num_nodes = 4 self.setup_clean_chain = False - - def setup_nodes(self): - #This test requires mocktime self.enable_mocktime() - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) def run_test(self): # Simple send, 0 to 1: diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py index 66e5bd29e6d2..6bd6a9e34f45 100755 --- a/test/functional/maxuploadtarget.py +++ b/test/functional/maxuploadtarget.py @@ -147,7 +147,7 @@ def run_test(self): #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1 self.log.info("Restarting nodes with -whitelist=127.0.0.1") self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) + self.start_node(0, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) #recreate/reconnect a test node test_nodes = [TestNode()] diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 807edeb7a832..dc5a3263ffa4 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -63,9 +63,8 @@ def run_test(self): self.log.debug("Stop-start node0 and node1. Verify that node0 has the transactions in its mempool and node1 does not.") self.stop_nodes() - self.nodes = [] - self.nodes.append(self.start_node(0, self.options.tmpdir)) - self.nodes.append(self.start_node(1, self.options.tmpdir)) + self.start_node(0) + self.start_node(1) # Give bitcoind a second to reload the mempool time.sleep(1) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) @@ -73,16 +72,14 @@ def run_test(self): self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") self.stop_nodes() - self.nodes = [] - self.nodes.append(self.start_node(0, self.options.tmpdir, ["-persistmempool=0"])) + self.start_node(0, extra_args=["-persistmempool=0"]) # Give bitcoind a second to reload the mempool time.sleep(1) assert_equal(len(self.nodes[0].getrawmempool()), 0) self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.") self.stop_nodes() - self.nodes = [] - self.nodes.append(self.start_node(0, self.options.tmpdir)) + self.start_node(0) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) if __name__ == '__main__': diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index fc6e8e325f60..7381a9fd54d8 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -23,17 +23,17 @@ def run_test(self): self.stop_node(0) # should not initialize if there are duplicate wallets - self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') + self.assert_start_raises_init_error(0, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') # should not initialize if wallet file is a directory os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11')) - self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') + self.assert_start_raises_init_error(0, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') # should not initialize if wallet file is a symlink os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12')) - self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') + self.assert_start_raises_init_error(0, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') - self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) + self.start_node(0, self.extra_args[0]) w1 = self.nodes[0].get_wallet_rpc("w1") w2 = self.nodes[0].get_wallet_rpc("w2") diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 63dfbb8ae6e5..9189f5ef23f8 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -1496,7 +1496,7 @@ def test_upgrade_after_activation(self, node_id): # Restart with the new binary self.stop_node(node_id) - self.nodes[node_id] = self.start_node(node_id, self.options.tmpdir) + self.start_node(node_id, extra_args=[]) connect_nodes(self.nodes[0], node_id) sync_blocks(self.nodes) diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index df7e8ce5c163..a7aacf908d1e 100755 --- a/test/functional/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -112,7 +112,7 @@ def run_test(self): # Empty out the alert file with open(self.alert_filename, 'w', encoding='utf8') as _: pass - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.start_nodes() # Connecting one block should be enough to generate an error. self.nodes[0].generate(1) @@ -123,7 +123,7 @@ def run_test(self): self.test_versionbits_in_alert_file() # Test framework expects the node to still be running... - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.start_nodes() if __name__ == '__main__': VersionBitsWarningTest().main() diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index ae6f843ddce7..7f5a3810f4d4 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -89,7 +89,8 @@ def setup_nodes(self): ] if self.have_ipv6: args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) + self.start_nodes() def node_test(self, node, proxies, auth, test_onion=True): rv = [] diff --git a/test/functional/pruning.py b/test/functional/pruning.py index 0af91e065890..fe406e89adc2 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -56,6 +56,10 @@ def setup_network(self): connect_nodes(self.nodes[0], 4) sync_blocks(self.nodes[0:5]) + def setup_nodes(self): + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=900) + self.start_nodes() + def create_big_chain(self): # Start by creating some coinbases we can spend later self.nodes[1].generate(200) @@ -98,7 +102,7 @@ def create_chain_with_staleblocks(self): # Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects # Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine self.stop_node(0) - self.nodes[0]=self.start_node(0, self.options.tmpdir, self.full_node_default_args, timewait=900) + self.start_node(0, extra_args=self.full_node_default_args) # Mine 24 blocks in node 1 for i in range(24): if j == 0: @@ -126,7 +130,7 @@ def reorg_test(self): # Reboot node 1 to clear its mempool (hopefully make the invalidate faster) # Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks) self.stop_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"]) height = self.nodes[1].getblockcount() self.log.info("Current block height: %d" % height) @@ -149,7 +153,7 @@ def reorg_test(self): # Reboot node1 to clear those giant tx's from mempool self.stop_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"]) self.log.info("Generating new longer chain of 300 more blocks") self.nodes[1].generate(300) @@ -227,13 +231,15 @@ def reorg_back(self): def manual_test(self, node_number, use_timestamp): # at this point, node has 995 blocks and has not yet run in prune mode - node = self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, timewait=900) + self.start_node(node_number) + node = self.nodes[node_number] assert_equal(node.getblockcount(), 995) assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500) - self.stop_node(node_number) # now re-start in manual pruning mode - node = self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900) + self.stop_node(node_number) + self.start_node(node_number, extra_args=["-prune=1"]) + node = self.nodes[node_number] assert_equal(node.getblockcount(), 995) def height(index): @@ -307,7 +313,7 @@ def has_block(index): # stop node, start back up with auto-prune at 550MB, make sure still runs self.stop_node(node_number) - self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900) + self.start_node(node_number, extra_args=["-prune=550"]) self.log.info("Success") @@ -315,7 +321,7 @@ def wallet_test(self): # check that the pruning node's wallet is still in good shape self.log.info("Stop and start pruning node to trigger wallet rescan") self.stop_node(2) - self.nodes[2] = self.start_node(2, self.options.tmpdir, ["-prune=550"]) + self.start_node(2, extra_args=["-prune=550"]) self.log.info("Success") # check that wallet loads successfully when restarting a pruned node after IBD. @@ -325,7 +331,7 @@ def wallet_test(self): nds = [self.nodes[0], self.nodes[5]] sync_blocks(nds, wait=5, timeout=300) self.stop_node(5) #stop and start to trigger rescan - self.nodes[5] = self.start_node(5, self.options.tmpdir, ["-prune=550"]) + self.start_node(5, extra_args=["-prune=550"]) self.log.info("Success") def run_test(self): diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py index 19d99c9c9e97..b16583416998 100755 --- a/test/functional/receivedby.py +++ b/test/functional/receivedby.py @@ -28,11 +28,7 @@ def __init__(self): super().__init__() self.num_nodes = 4 self.setup_clean_chain = False - - def setup_nodes(self): - #This test requires mocktime self.enable_mocktime() - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) def run_test(self): ''' diff --git a/test/functional/reindex.py b/test/functional/reindex.py index b446baa04dee..0d2a10659206 100755 --- a/test/functional/reindex.py +++ b/test/functional/reindex.py @@ -25,7 +25,7 @@ def reindex(self, justchainstate=False): blockcount = self.nodes[0].getblockcount() self.stop_nodes() extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.start_nodes(extra_args) while self.nodes[0].getblockcount() < blockcount: time.sleep(0.1) assert_equal(self.nodes[0].getblockcount(), blockcount) diff --git a/test/functional/resendwallettransactions.py b/test/functional/resendwallettransactions.py index 5059aa106e1e..db6f6eec4589 100755 --- a/test/functional/resendwallettransactions.py +++ b/test/functional/resendwallettransactions.py @@ -20,7 +20,7 @@ def run_test(self): # Should return an empty array if there aren't unconfirmed wallet transactions. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0, extra_args=[]) assert_equal(self.nodes[0].resendwallettransactions(), []) # Should return an array with the unconfirmed wallet transaction. diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index 20808207b2bc..e9d64af204cd 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -20,10 +20,7 @@ def __init__(self): self.num_nodes = 1 def setup_network(self): - pass - - def setup_nodes(self): - pass + self.add_nodes(self.num_nodes, self.options.tmpdir, None) def run_bind_test(self, allow_ips, connect_to, addresses, expected): ''' @@ -31,12 +28,14 @@ def run_bind_test(self, allow_ips, connect_to, addresses, expected): then try to connect, and check if the set of bound addresses matches the expected set. ''' + self.log.info("Bind test for %s" % str(addresses)) expected = [(addr_to_hex(addr), port) for (addr, port) in expected] base_args = ['-disablewallet', '-nolisten'] if allow_ips: base_args += ['-rpcallowip=' + x for x in allow_ips] binds = ['-rpcbind='+addr for addr in addresses] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to) + self.nodes[0].rpchost = connect_to + self.start_node(0, base_args + binds) pid = self.nodes[0].process.pid assert_equal(set(get_bind_addrs(pid)), set(expected)) self.stop_nodes() @@ -46,8 +45,10 @@ def run_allowip_test(self, allow_ips, rpchost, rpcport): Start a node with rpcallow IP, and request getnetworkinfo at a non-localhost IP. ''' + self.log.info("Allow IP test for %s:%d" % (rpchost, rpcport)) base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) + self.nodes[0].rpchost = None + self.start_nodes([base_args]) # connect to node through non-loopback interface node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) node.getnetworkinfo() diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index bc42a319df79..6eb665846644 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -153,57 +153,16 @@ def setup_network(self): But first we need to use one node to create a lot of outputs which we will use to generate our transactions. """ - self.nodes = [] + self.add_nodes(3, self.options.tmpdir, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"], + ["-blockmaxsize=17000", "-maxorphantx=1000"], + ["-blockmaxsize=8000", "-maxorphantx=1000"]]) # Use node0 to mine blocks for input splitting - self.nodes.append(self.start_node(0, self.options.tmpdir, ["-maxorphantx=1000", - "-whitelist=127.0.0.1"])) - - self.log.info("This test is time consuming, please be patient") - self.log.info("Splitting inputs so we can generate tx's") - self.txouts = [] - self.txouts2 = [] - # Split a coinbase into two transaction puzzle outputs - split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True) - - # Mine - while (len(self.nodes[0].getrawmempool()) > 0): - self.nodes[0].generate(1) - - # Repeatedly split those 2 outputs, doubling twice for each rep - # Use txouts to monitor the available utxo, since these won't be tracked in wallet - reps = 0 - while (reps < 5): - #Double txouts to txouts2 - while (len(self.txouts)>0): - split_inputs(self.nodes[0], self.txouts, self.txouts2) - while (len(self.nodes[0].getrawmempool()) > 0): - self.nodes[0].generate(1) - #Double txouts2 to txouts - while (len(self.txouts2)>0): - split_inputs(self.nodes[0], self.txouts2, self.txouts) - while (len(self.nodes[0].getrawmempool()) > 0): - self.nodes[0].generate(1) - reps += 1 - self.log.info("Finished splitting") - - # Now we can connect the other nodes, didn't want to connect them earlier - # so the estimates would not be affected by the splitting transactions # Node1 mines small blocks but that are bigger than the expected transaction rate. # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # (17k is room enough for 110 or so transactions) - self.nodes.append(self.start_node(1, self.options.tmpdir, - ["-blockmaxsize=17000", "-maxorphantx=1000"])) - connect_nodes(self.nodes[1], 0) - # Node2 is a stingy miner, that # produces too small blocks (room for only 55 or so transactions) - node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"] - self.nodes.append(self.start_node(2, self.options.tmpdir, node2args)) - connect_nodes(self.nodes[0], 2) - connect_nodes(self.nodes[2], 1) - - self.sync_all() def transact_and_mine(self, numblocks, mining_node): min_fee = Decimal("0.00001") @@ -232,9 +191,51 @@ def transact_and_mine(self, numblocks, mining_node): self.memutxo = newmem def run_test(self): + self.log.info("This test is time consuming, please be patient") + self.log.info("Splitting inputs so we can generate tx's") + # Make log handler available to helper functions global log log = self.log + + # Start node0 + self.start_node(0) + self.txouts = [] + self.txouts2 = [] + # Split a coinbase into two transaction puzzle outputs + split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True) + + # Mine + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + + # Repeatedly split those 2 outputs, doubling twice for each rep + # Use txouts to monitor the available utxo, since these won't be tracked in wallet + reps = 0 + while (reps < 5): + #Double txouts to txouts2 + while (len(self.txouts)>0): + split_inputs(self.nodes[0], self.txouts, self.txouts2) + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + #Double txouts2 to txouts + while (len(self.txouts2)>0): + split_inputs(self.nodes[0], self.txouts2, self.txouts) + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + reps += 1 + self.log.info("Finished splitting") + + # Now we can connect the other nodes, didn't want to connect them earlier + # so the estimates would not be affected by the splitting transactions + self.start_node(1) + self.start_node(2) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[2], 1) + + self.sync_all() + self.fees_per_kb = [] self.memutxo = [] self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 7903bb00451b..a14ff9c292e0 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -91,7 +91,8 @@ def setup_nodes(self): extra_args = None if hasattr(self, "extra_args"): extra_args = self.extra_args - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.start_nodes() def run_test(self): raise NotImplementedError @@ -204,37 +205,39 @@ def main(self): # Public helper methods. These can be accessed by the subclass test scripts. - def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): - """Start a bitcoind and return RPC connection to it""" + def add_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + """Instantiate TestNode objects""" if extra_args is None: - extra_args = [] + extra_args = [[]] * num_nodes if binary is None: - binary = os.getenv("BITCOIND", "bitcoind") - node = TestNode(i, dirname, extra_args, rpchost, timewait, binary, stderr, self.mocktime, coverage_dir=self.options.coveragedir) - node.start() + binary = [None] * num_nodes + assert_equal(len(extra_args), num_nodes) + assert_equal(len(binary), num_nodes) + for i in range(num_nodes): + self.nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) + + def start_node(self, i, extra_args=None, stderr=None): + """Start a bitcoind""" + + node = self.nodes[i] + + node.start(extra_args, stderr) node.wait_for_rpc_connection() if self.options.coveragedir is not None: coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) - return node - - def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): - """Start multiple bitcoinds, return RPC connections to them""" + def start_nodes(self, extra_args=None): + """Start multiple bitcoinds""" if extra_args is None: - extra_args = [[]] * num_nodes - if binary is None: - binary = [None] * num_nodes - assert_equal(len(extra_args), num_nodes) - assert_equal(len(binary), num_nodes) - nodes = [] + extra_args = [None] * self.num_nodes + assert_equal(len(extra_args), self.num_nodes) try: - for i in range(num_nodes): - nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) - nodes[i].start() - for node in nodes: + for i, node in enumerate(self.nodes): + node.start(extra_args[i]) + for node in self.nodes: node.wait_for_rpc_connection() except: # If one node failed to start, stop the others @@ -242,11 +245,9 @@ def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewai raise if self.options.coveragedir is not None: - for node in nodes: + for node in self.nodes: coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) - return nodes - def stop_node(self, i): """Stop a bitcoind test node""" self.nodes[i].stop_node() @@ -264,10 +265,10 @@ def stop_nodes(self): while not node.is_node_stopped(): time.sleep(0.1) - def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_msg=None): + def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: try: - self.start_node(i, dirname, extra_args, stderr=log_stderr) + self.start_node(i, extra_args, stderr=log_stderr) self.stop_node(i) except Exception as e: assert 'bitcoind exited' in str(e) # node must have shutdown @@ -385,7 +386,7 @@ def _initialize_chain(self, test_dir, num_nodes, cachedir): args.append("-connect=127.0.0.1:" + str(p2p_port(0))) self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) self.nodes[i].args = args - self.nodes[i].start() + self.start_node(i) # Wait for RPC connections to be ready for node in self.nodes: @@ -455,13 +456,13 @@ def add_options(self, parser): help="bitcoind binary to use for reference nodes (if any)") def setup_network(self): - extra_args = [['-whitelist=127.0.0.1']]*self.num_nodes + extra_args = [['-whitelist=127.0.0.1']] * self.num_nodes if hasattr(self, "extra_args"): extra_args = self.extra_args - self.nodes = self.start_nodes( - self.num_nodes, self.options.tmpdir, extra_args, - binary=[self.options.testbinary] + - [self.options.refbinary] * (self.num_nodes - 1)) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args, + binary=[self.options.testbinary] + + [self.options.refbinary] * (self.num_nodes - 1)) + self.start_nodes() class SkipTest(Exception): """This exception is raised to skip a test""" diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 553c7c9d2022..efb3ac9d1659 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -65,9 +65,13 @@ def __getattr__(self, *args, **kwargs): assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection" return self.rpc.__getattr__(*args, **kwargs) - def start(self): + def start(self, extra_args=None, stderr=None): """Start the node.""" - self.process = subprocess.Popen(self.args + self.extra_args, stderr=self.stderr) + if extra_args is None: + extra_args = self.extra_args + if stderr is None: + stderr = self.stderr + self.process = subprocess.Popen(self.args + extra_args, stderr=stderr) self.running = True self.log.debug("bitcoind started, waiting for RPC to come up") diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index 61ad00330bd7..a588e2386ffe 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -68,7 +68,8 @@ def setup_network(self, split=False): # 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 = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) + self.start_nodes() def run_test (self): tmpdir = self.options.tmpdir @@ -95,7 +96,7 @@ def run_test (self): #encrypt wallet, restart, unlock and dump self.nodes[0].node_encrypt_wallet('test') - self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) + self.start_node(0) self.nodes[0].walletpassphrase('test', 10) # Should be a no-op: self.nodes[0].keypoolrefill() diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index 8fea4140db75..2f38e6fee846 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -31,7 +31,7 @@ def run_test(self): # Encrypt the wallet self.nodes[0].node_encrypt_wallet(passphrase) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) # Test that the wallet is encrypted assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py index 821575ed1997..13b9dd9a906f 100755 --- a/test/functional/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -25,8 +25,8 @@ def run_test (self): # Make sure can't switch off usehd after wallet creation self.stop_node(1) - self.assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet') - self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1]) + self.assert_start_raises_init_error(1, ['-usehd=0'], 'already existing HD wallet') + self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) # Make sure we use hd, keep masterkeyid @@ -76,7 +76,7 @@ def run_test (self): shutil.rmtree(tmpdir + "/node1/regtest/blocks") shutil.rmtree(tmpdir + "/node1/regtest/chainstate") shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat") - self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1]) + self.start_node(1) # Assert that derivation is deterministic hd_add_2 = None @@ -91,7 +91,7 @@ def run_test (self): # Needs rescan self.stop_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan']) + self.start_node(1, extra_args=self.extra_args[1] + ['-rescan']) assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) # send a tx and make sure its using the internal chain for the changeoutput diff --git a/test/functional/wallet.py b/test/functional/wallet.py index a37c457bc813..17896101498c 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -21,11 +21,14 @@ def __init__(self): self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): - self.nodes = self.start_nodes(3, self.options.tmpdir, self.extra_args[:3]) + self.add_nodes(4, self.options.tmpdir, self.extra_args) + self.start_node(0) + self.start_node(1) + self.start_node(2) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - self.sync_all() + self.sync_all([self.nodes[0:3]]) def run_test(self): @@ -42,9 +45,9 @@ def run_test(self): assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) - self.sync_all() + self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) - self.sync_all() + self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) @@ -96,7 +99,7 @@ def run_test(self): # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] @@ -109,7 +112,7 @@ def run_test(self): # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) - self.sync_all() + self.sync_all([self.nodes[0:3]]) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 @@ -138,7 +141,7 @@ def run_test(self): # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) @@ -150,14 +153,14 @@ def run_test(self): self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) @@ -165,7 +168,7 @@ def run_test(self): # Sendmany 10 BTC txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", []) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), node_0_bal) @@ -173,7 +176,7 @@ def run_test(self): # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) @@ -184,9 +187,9 @@ def run_test(self): # EXPECT: nodes[3] should have those transactions in its mempool. txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) - sync_mempools(self.nodes) + sync_mempools(self.nodes[0:2]) - self.nodes.append(self.start_node(3, self.options.tmpdir, self.extra_args[3])) + self.start_node(3) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) @@ -230,22 +233,24 @@ def run_test(self): #do some -walletbroadcast tests self.stop_nodes() - self.nodes = self.start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]]) + self.start_node(0, ["-walletbroadcast=0"]) + self.start_node(1, ["-walletbroadcast=0"]) + self.start_node(2, ["-walletbroadcast=0"]) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - self.sync_all() + self.sync_all([self.nodes[0:3]]) txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.nodes[1].generate(1) #mine a block, tx should not be in there - self.sync_all() + self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[2].getbalance(), node_2_bal) #should not be changed because tx was not broadcasted #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) self.nodes[1].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal += 2 txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), node_2_bal) @@ -255,14 +260,16 @@ def run_test(self): #restart the nodes with -walletbroadcast=1 self.stop_nodes() - self.nodes = self.start_nodes(3, self.options.tmpdir) + self.start_node(0) + self.start_node(1) + self.start_node(2) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - sync_blocks(self.nodes) + sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) - sync_blocks(self.nodes) + sync_blocks(self.nodes[0:3]) node_2_bal += 2 #tx should be added to balance because after restarting the nodes tx should be broadcastet @@ -293,7 +300,7 @@ def run_test(self): address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) @@ -319,15 +326,15 @@ def run_test(self): cbAddr = self.nodes[1].getnewaddress() blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0] cbTxId = self.nodes[0].getblock(blkHash)['tx'][0] - self.sync_all() + self.sync_all([self.nodes[0:3]]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(cbTxId) # check if wallet or blockchain maintenance changes the balance - self.sync_all() + self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) - self.sync_all() + self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() @@ -358,7 +365,9 @@ def run_test(self): self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later - self.nodes = self.start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3) + self.start_node(0, [m, "-limitancestorcount="+str(chainlimit)]) + self.start_node(1, [m, "-limitancestorcount="+str(chainlimit)]) + self.start_node(2, [m, "-limitancestorcount="+str(chainlimit)]) 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) @@ -406,7 +415,7 @@ def run_test(self): # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)]) + self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)]) # wait for loadmempool timeout = 10 diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index ff51cba4b3f6..688cd6d0c866 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -78,9 +78,9 @@ def do_one_round(self): # As above, this mirrors the original bash test. def start_three(self): - self.nodes[0] = self.start_node(0, self.options.tmpdir) - self.nodes[1] = self.start_node(1, self.options.tmpdir) - self.nodes[2] = self.start_node(2, self.options.tmpdir) + self.start_node(0) + self.start_node(1) + self.start_node(2) connect_nodes(self.nodes[0], 3) connect_nodes(self.nodes[1], 3) connect_nodes(self.nodes[2], 3) diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index af867d7a52c7..1005a4b95fc0 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -48,7 +48,7 @@ def run_test(self): # Stop-start node0. Both confirmed and unconfirmed transactions remain in the wallet. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) @@ -56,7 +56,7 @@ def run_test(self): # Stop node0 and restart with zapwallettxes and persistmempool. The unconfirmed # transaction is zapped from the wallet, but is re-added when the mempool is reloaded. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-persistmempool=1", "-zapwallettxes=2"]) + self.start_node(0, ["-persistmempool=1", "-zapwallettxes=2"]) assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) @@ -64,7 +64,7 @@ def run_test(self): # Stop node0 and restart with zapwallettxes, but not persistmempool. # The unconfirmed transaction is zapped and is no longer in the wallet. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-zapwallettxes=2"]) + self.start_node(0, ["-zapwallettxes=2"]) # tx1 is still be available because it was confirmed assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index 26c946d215eb..603b7a1b9484 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -41,8 +41,9 @@ def setup_nodes(self): self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") ip_address = "tcp://127.0.0.1:28332" self.zmqSubSocket.connect(ip_address) - extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.start_nodes() def run_test(self): try: From bb5e7cb308b58a1c16db1275dfca1a31e2bba71f Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 24 Aug 2017 11:37:25 -0400 Subject: [PATCH 046/196] [tests] Avoid passing around member variables in test_framework Github-Pull: #11121 Rebased-From: 6cf094a0229d051ab8a15189c8a0bc6011919e72 --- test/functional/assumevalid.py | 2 +- test/functional/dbcrash.py | 2 +- test/functional/import-rescan.py | 2 +- test/functional/proxy_test.py | 2 +- test/functional/pruning.py | 2 +- test/functional/rpcbind_test.py | 2 +- test/functional/smartfees.py | 6 +-- .../test_framework/test_framework.py | 50 +++++++++---------- test/functional/wallet-dump.py | 2 +- test/functional/wallet.py | 2 +- test/functional/zmq_test.py | 2 +- 11 files changed, 37 insertions(+), 37 deletions(-) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index 63e6a384a45d..ec485281d4d9 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -60,7 +60,7 @@ def __init__(self): self.num_nodes = 3 def setup_network(self): - self.add_nodes(3, self.options.tmpdir) + self.add_nodes(3) # Start node0. We don't start the other nodes yet since # we need to pre-mine a block with an invalid transaction # signature so we can pass in the block hash as assumevalid. diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index d39369105bf6..b0c6d39c494d 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -65,7 +65,7 @@ def __init__(self): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) + self.add_nodes(self.num_nodes, timewait=90) self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index be52d5c8472d..e85086fbc16c 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -121,7 +121,7 @@ def setup_network(self): if import_node.prune: extra_args[i] += ["-prune=1"] - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, extra_args) self.start_nodes() for i in range(1, self.num_nodes): connect_nodes(self.nodes[i], 0) diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index 7f5a3810f4d4..adbbda278dac 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -89,7 +89,7 @@ def setup_nodes(self): ] if self.have_ipv6: args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) + self.add_nodes(self.num_nodes, extra_args=args) self.start_nodes() def node_test(self, node, proxies, auth, test_onion=True): diff --git a/test/functional/pruning.py b/test/functional/pruning.py index fe406e89adc2..9690428769f8 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -57,7 +57,7 @@ def setup_network(self): sync_blocks(self.nodes[0:5]) def setup_nodes(self): - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=900) + self.add_nodes(self.num_nodes, self.extra_args, timewait=900) self.start_nodes() def create_big_chain(self): diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index e9d64af204cd..a7661421ff9a 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -20,7 +20,7 @@ def __init__(self): self.num_nodes = 1 def setup_network(self): - self.add_nodes(self.num_nodes, self.options.tmpdir, None) + self.add_nodes(self.num_nodes, None) def run_bind_test(self, allow_ips, connect_to, addresses, expected): ''' diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index 6eb665846644..caf35926522c 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -153,9 +153,9 @@ def setup_network(self): But first we need to use one node to create a lot of outputs which we will use to generate our transactions. """ - self.add_nodes(3, self.options.tmpdir, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"], - ["-blockmaxsize=17000", "-maxorphantx=1000"], - ["-blockmaxsize=8000", "-maxorphantx=1000"]]) + self.add_nodes(3, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"], + ["-blockmaxsize=17000", "-maxorphantx=1000"], + ["-blockmaxsize=8000", "-maxorphantx=1000"]]) # Use node0 to mine blocks for input splitting # Node1 mines small blocks but that are bigger than the expected transaction rate. # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index a14ff9c292e0..5e3644a9142b 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -73,9 +73,9 @@ def add_options(self, parser): def setup_chain(self): self.log.info("Initializing test directory " + self.options.tmpdir) if self.setup_clean_chain: - self._initialize_chain_clean(self.options.tmpdir, self.num_nodes) + self._initialize_chain_clean() else: - self._initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) + self._initialize_chain() def setup_network(self): self.setup_nodes() @@ -91,7 +91,7 @@ def setup_nodes(self): extra_args = None if hasattr(self, "extra_args"): extra_args = self.extra_args - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, extra_args) self.start_nodes() def run_test(self): @@ -205,7 +205,7 @@ def main(self): # Public helper methods. These can be accessed by the subclass test scripts. - def add_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + def add_nodes(self, num_nodes, extra_args=None, rpchost=None, timewait=None, binary=None): """Instantiate TestNode objects""" if extra_args is None: @@ -215,7 +215,7 @@ def add_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait= assert_equal(len(extra_args), num_nodes) assert_equal(len(binary), num_nodes) for i in range(num_nodes): - self.nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) + self.nodes.append(TestNode(i, self.options.tmpdir, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) def start_node(self, i, extra_args=None, stderr=None): """Start a bitcoind""" @@ -357,16 +357,16 @@ def _start_logging(self): rpc_handler.setLevel(logging.DEBUG) rpc_logger.addHandler(rpc_handler) - def _initialize_chain(self, test_dir, num_nodes, cachedir): + def _initialize_chain(self): """Initialize a pre-mined blockchain for use by the test. Create a cache of a 200-block-long chain (with wallet) for MAX_NODES Afterward, create num_nodes copies from the cache.""" - assert num_nodes <= MAX_NODES + assert self.num_nodes <= MAX_NODES create_cache = False for i in range(MAX_NODES): - if not os.path.isdir(os.path.join(cachedir, 'node' + str(i))): + if not os.path.isdir(os.path.join(self.options.cachedir, 'node' + str(i))): create_cache = True break @@ -375,16 +375,16 @@ def _initialize_chain(self, test_dir, num_nodes, cachedir): # find and delete old cache directories if any exist for i in range(MAX_NODES): - if os.path.isdir(os.path.join(cachedir, "node" + str(i))): - shutil.rmtree(os.path.join(cachedir, "node" + str(i))) + if os.path.isdir(os.path.join(self.options.cachedir, "node" + str(i))): + shutil.rmtree(os.path.join(self.options.cachedir, "node" + str(i))) # Create cache directories, run bitcoinds: for i in range(MAX_NODES): - datadir = initialize_datadir(cachedir, i) + datadir = initialize_datadir(self.options.cachedir, i) args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"] if i > 0: args.append("-connect=127.0.0.1:" + str(p2p_port(0))) - self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) + self.nodes.append(TestNode(i, self.options.cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) self.nodes[i].args = args self.start_node(i) @@ -415,24 +415,24 @@ def _initialize_chain(self, test_dir, num_nodes, cachedir): self.nodes = [] self.disable_mocktime() for i in range(MAX_NODES): - os.remove(log_filename(cachedir, i, "debug.log")) - os.remove(log_filename(cachedir, i, "db.log")) - os.remove(log_filename(cachedir, i, "peers.dat")) - os.remove(log_filename(cachedir, i, "fee_estimates.dat")) - - for i in range(num_nodes): - from_dir = os.path.join(cachedir, "node" + str(i)) - to_dir = os.path.join(test_dir, "node" + str(i)) + os.remove(log_filename(self.options.cachedir, i, "debug.log")) + os.remove(log_filename(self.options.cachedir, i, "db.log")) + os.remove(log_filename(self.options.cachedir, i, "peers.dat")) + os.remove(log_filename(self.options.cachedir, i, "fee_estimates.dat")) + + for i in range(self.num_nodes): + from_dir = os.path.join(self.options.cachedir, "node" + str(i)) + to_dir = os.path.join(self.options.tmpdir, "node" + str(i)) shutil.copytree(from_dir, to_dir) - initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf + initialize_datadir(self.options.tmpdir, i) # Overwrite port/rpcport in bitcoin.conf - def _initialize_chain_clean(self, test_dir, num_nodes): + def _initialize_chain_clean(self): """Initialize empty blockchain for use by the test. Create an empty blockchain and num_nodes wallets. Useful if a test case wants complete control over initialization.""" - for i in range(num_nodes): - initialize_datadir(test_dir, i) + for i in range(self.num_nodes): + initialize_datadir(self.options.tmpdir, i) class ComparisonTestFramework(BitcoinTestFramework): """Test framework for doing p2p comparison testing @@ -459,7 +459,7 @@ def setup_network(self): extra_args = [['-whitelist=127.0.0.1']] * self.num_nodes if hasattr(self, "extra_args"): extra_args = self.extra_args - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args, + self.add_nodes(self.num_nodes, extra_args, binary=[self.options.testbinary] + [self.options.refbinary] * (self.num_nodes - 1)) self.start_nodes() diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index a588e2386ffe..e0381b9809f9 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -68,7 +68,7 @@ def setup_network(self, split=False): # 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.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) + self.add_nodes(self.num_nodes, self.extra_args, timewait=60) self.start_nodes() def run_test (self): diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 17896101498c..7190de94b670 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -21,7 +21,7 @@ def __init__(self): self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): - self.add_nodes(4, self.options.tmpdir, self.extra_args) + self.add_nodes(4, self.extra_args) self.start_node(0) self.start_node(1) self.start_node(2) diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index 603b7a1b9484..b5a22ea07fc8 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -42,7 +42,7 @@ def setup_nodes(self): ip_address = "tcp://127.0.0.1:28332" self.zmqSubSocket.connect(ip_address) self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.add_nodes(self.num_nodes, self.extra_args) self.start_nodes() def run_test(self): From 801d2ae9247be5870344c8b4ed5c372ab8930408 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 9 Jun 2017 18:21:21 -0400 Subject: [PATCH 047/196] [tests] don't override __init__() in individual tests Almost all test scripts currently need to override the __init__() method. When they do that they need to call into super().__init__() as the base class does some generic initialization. This commit makes the base class __init__() call into set_test_params() method. Individual test cases can override set_test_params() to setup their test parameters. Github-Pull: #11121 Rebased-From: 5448a1471d6fc638a2220ea5a2f3782172efe14c --- test/functional/README.md | 6 +- test/functional/abandonconflict.py | 4 +- test/functional/assumevalid.py | 3 +- test/functional/bip65-cltv-p2p.py | 4 +- test/functional/bip68-112-113-p2p.py | 4 +- test/functional/bip68-sequence.py | 4 +- test/functional/bip9-softforks.py | 5 +- test/functional/bipdersig-p2p.py | 4 +- test/functional/blockchain.py | 6 +- test/functional/bumpfee.py | 3 +- test/functional/create_cache.py | 6 +- test/functional/dbcrash.py | 3 +- test/functional/decodescript.py | 4 +- test/functional/disablewallet.py | 5 +- test/functional/disconnect_ban.py | 5 +- test/functional/example_test.py | 10 +-- test/functional/forknotify.py | 5 +- test/functional/fundrawtransaction.py | 6 +- test/functional/getblocktemplate_longpoll.py | 5 -- test/functional/getchaintips.py | 6 -- test/functional/httpbasics.py | 4 +- test/functional/import-rescan.py | 3 +- test/functional/importmulti.py | 3 +- test/functional/importprunedfunds.py | 5 +- test/functional/invalidateblock.py | 4 +- test/functional/invalidblockrequest.py | 4 +- test/functional/invalidtxrequest.py | 4 +- test/functional/keypool-topup.py | 3 +- test/functional/keypool.py | 7 +- test/functional/listsinceblock.py | 5 +- test/functional/listtransactions.py | 5 +- test/functional/maxuploadtarget.py | 3 +- test/functional/mempool_limit.py | 4 +- test/functional/mempool_packages.py | 4 +- test/functional/mempool_persist.py | 6 +- test/functional/mempool_reorg.py | 4 +- test/functional/mempool_resurrect_test.py | 6 +- test/functional/mempool_spendcoinbase.py | 5 +- test/functional/merkle_blocks.py | 5 +- test/functional/mining.py | 4 +- test/functional/multi_rpc.py | 5 +- test/functional/multiwallet.py | 4 +- test/functional/net.py | 4 +- test/functional/nulldummy.py | 3 +- test/functional/p2p-acceptblock.py | 3 +- test/functional/p2p-compactblocks.py | 3 +- test/functional/p2p-feefilter.py | 5 +- test/functional/p2p-fullblocktest.py | 5 +- test/functional/p2p-leaktests.py | 3 +- test/functional/p2p-mempool.py | 4 +- test/functional/p2p-segwit.py | 7 +- test/functional/p2p-timeouts.py | 3 +- test/functional/p2p-versionbits-warning.py | 3 +- test/functional/preciousblock.py | 3 +- test/functional/prioritise_transaction.py | 4 +- test/functional/proxy_test.py | 6 -- test/functional/pruning.py | 4 +- test/functional/rawtransactions.py | 4 +- test/functional/receivedby.py | 6 +- test/functional/reindex.py | 3 +- test/functional/replace-by-fee.py | 4 +- test/functional/resendwallettransactions.py | 6 +- test/functional/rest.py | 3 +- test/functional/rpcbind_test.py | 5 +- test/functional/rpcnamedargs.py | 9 +- test/functional/segwit.py | 4 +- test/functional/sendheaders.py | 3 +- test/functional/signmessages.py | 4 +- test/functional/signrawtransactions.py | 3 +- test/functional/smartfees.py | 5 +- .../test_framework/test_framework.py | 89 +++++++++++-------- test/functional/txn_clone.py | 6 -- test/functional/txn_doublespend.py | 5 -- test/functional/uptime.py | 4 +- test/functional/wallet-accounts.py | 4 +- test/functional/wallet-dump.py | 5 +- test/functional/wallet-encryption.py | 4 +- test/functional/wallet-hd.py | 5 +- test/functional/wallet.py | 18 ++-- test/functional/walletbackup.py | 5 +- test/functional/zapwallettxes.py | 4 +- test/functional/zmq_test.py | 4 +- 82 files changed, 145 insertions(+), 322 deletions(-) diff --git a/test/functional/README.md b/test/functional/README.md index 44efda33d3c4..2558bd017d6a 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -24,8 +24,8 @@ don't have test cases for. - Use a module-level docstring to describe what the test is testing, and how it is testing it. - When subclassing the BitcoinTestFramwork, place overrides for the - `__init__()`, and `setup_xxxx()` methods at the top of the subclass, then - locally-defined helper methods, then the `run_test()` method. + `set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of + the subclass, then locally-defined helper methods, then the `run_test()` method. #### General test-writing advice @@ -36,7 +36,7 @@ don't have test cases for. - Avoid stop-starting the nodes multiple times during the test if possible. A stop-start takes several seconds, so doing it several times blows up the runtime of the test. -- Set the `self.setup_clean_chain` variable in `__init__()` to control whether +- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether or not to use the cached data directories. The cached data directories contain a 200-block pre-mined blockchain and wallets for four nodes. Each node has 25 mature blocks (25x50=1250 BTC) in its wallet. diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py index 1db04337a96f..e8dbc864698a 100755 --- a/test/functional/abandonconflict.py +++ b/test/functional/abandonconflict.py @@ -14,10 +14,8 @@ from test_framework.util import * class AbandonConflictTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [["-minrelaytxfee=0.00001"], []] def run_test(self): diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index ec485281d4d9..beaf8c705586 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -54,8 +54,7 @@ def send_header_for_blocks(self, new_blocks): self.send_message(headers_message) class AssumeValidTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index 65ae8de554b6..2cd6df6e37a8 100755 --- a/test/functional/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -60,9 +60,7 @@ def create_transaction(node, coinbase, to_address, amount): return tx class BIP65Test(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']] self.setup_clean_chain = True diff --git a/test/functional/bip68-112-113-p2p.py b/test/functional/bip68-112-113-p2p.py index 5a322e8c0e43..7e6a4f440866 100755 --- a/test/functional/bip68-112-113-p2p.py +++ b/test/functional/bip68-112-113-p2p.py @@ -92,9 +92,9 @@ def all_rlt_txs(txarray): return txs class BIP68_112_113Test(ComparisonTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4']] def run_test(self): diff --git a/test/functional/bip68-sequence.py b/test/functional/bip68-sequence.py index 87a50692f6c8..39012adf9533 100755 --- a/test/functional/bip68-sequence.py +++ b/test/functional/bip68-sequence.py @@ -17,10 +17,8 @@ NOT_FINAL_ERROR = "64: non-BIP68-final" class BIP68Test(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [[], ["-acceptnonstdtxn=0"]] def run_test(self): diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py index ad16482550ce..904789301a10 100755 --- a/test/functional/bip9-softforks.py +++ b/test/functional/bip9-softforks.py @@ -28,11 +28,10 @@ from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP class BIP9SoftForksTest(ComparisonTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-whitelist=127.0.0.1']] + self.setup_clean_chain = True def run_test(self): self.test = TestManager(self, self.options.tmpdir) diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index 977597089309..c620d3e155d1 100755 --- a/test/functional/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -48,9 +48,7 @@ def create_transaction(node, coinbase, to_address, amount): return tx class BIP66Test(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']] self.setup_clean_chain = True diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index a3a6cf2fb868..5d04de9940c4 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -30,12 +30,8 @@ assert_is_hash_string, ) - class BlockchainTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-stopatheight=207']] diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index 59c65f18e89d..ede0df29d8d7 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -30,8 +30,7 @@ class BumpFeeTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 1a5754b3f739..7d4d1a529b76 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -12,11 +12,9 @@ from test_framework.test_framework import BitcoinTestFramework class CreateCache(BitcoinTestFramework): + # Test network and test nodes are not required: - def __init__(self): - super().__init__() - - # Test network and test nodes are not required: + def set_test_params(self): self.num_nodes = 0 def setup_network(self): diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index b0c6d39c494d..71424f641b55 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -43,8 +43,7 @@ pass class ChainstateWriteCrashTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = False diff --git a/test/functional/decodescript.py b/test/functional/decodescript.py index 21a9f1223fd3..6611da883147 100755 --- a/test/functional/decodescript.py +++ b/test/functional/decodescript.py @@ -10,9 +10,7 @@ from io import BytesIO class DecodeScriptTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/disablewallet.py b/test/functional/disablewallet.py index d34451341426..c1d37963bc60 100755 --- a/test/functional/disablewallet.py +++ b/test/functional/disablewallet.py @@ -11,11 +11,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * - class DisableWalletTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-disablewallet"]] diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index cc8901c40ca5..a6445b9b35e4 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -14,11 +14,8 @@ ) class DisconnectBanTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False def run_test(self): self.log.info("Test setban and listbanned RPCs") diff --git a/test/functional/example_test.py b/test/functional/example_test.py index a54b5278e48d..de8934f74b76 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -73,15 +73,11 @@ def custom_function(): class ExampleTest(BitcoinTestFramework): # Each functional test is a subclass of the BitcoinTestFramework class. - # Override the __init__(), add_options(), setup_chain(), setup_network() + # Override the set_test_params(), add_options(), setup_chain(), setup_network() # and setup_nodes() methods to customize the test setup as required. - def __init__(self): - """Initialize the test - - Call super().__init__() first, and then override any test parameters - for your individual test.""" - super().__init__() + def set_test_params(self): + """Override any test parameters for your individual test.""" self.setup_clean_chain = True self.num_nodes = 3 # Use self.extra_args to change command-line arguments for the nodes diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py index 3a2a927098e0..afcad1f9cc3f 100755 --- a/test/functional/forknotify.py +++ b/test/functional/forknotify.py @@ -9,11 +9,8 @@ from test_framework.test_framework import BitcoinTestFramework class ForkNotifyTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False def setup_network(self): self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 242b6eed108c..dec3d41bfc5f 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -14,13 +14,9 @@ def get_unspent(listunspent, amount): return utx raise AssertionError('Could not find unspent with amount={}'.format(amount)) - class RawTransactionsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 def setup_network(self, split=False): self.setup_nodes() diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index cca30e2688e4..85d2560244e5 100755 --- a/test/functional/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -23,11 +23,6 @@ def run(self): self.node.getblocktemplate({'longpollid':self.longpollid}) class GetBlockTemplateLPTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def run_test(self): self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.") self.nodes[0].generate(10) diff --git a/test/functional/getchaintips.py b/test/functional/getchaintips.py index 15f96c565fe6..00fc23c6b0d3 100755 --- a/test/functional/getchaintips.py +++ b/test/functional/getchaintips.py @@ -14,13 +14,7 @@ from test_framework.util import assert_equal class GetChainTipsTest (BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def run_test (self): - tips = self.nodes[0].getchaintips () assert_equal (len (tips), 1) assert_equal (tips[0]['branchlen'], 0) diff --git a/test/functional/httpbasics.py b/test/functional/httpbasics.py index 4b32e8d9ca33..c7682cb49df4 100755 --- a/test/functional/httpbasics.py +++ b/test/functional/httpbasics.py @@ -11,10 +11,8 @@ import urllib.parse class HTTPBasicsTest (BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 3 - self.setup_clean_chain = False def setup_network(self): self.setup_nodes() diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index e85086fbc16c..02d7428120be 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -111,8 +111,7 @@ def check(self, txid=None, amount=None, confirmations=None): class ImportRescanTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 + len(IMPORT_NODES) def setup_network(self): diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index 6aae95549de9..4c519f40d54e 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -7,8 +7,7 @@ from test_framework.util import * class ImportMultiTest (BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True diff --git a/test/functional/importprunedfunds.py b/test/functional/importprunedfunds.py index 94753fe43114..df90e9ec177b 100755 --- a/test/functional/importprunedfunds.py +++ b/test/functional/importprunedfunds.py @@ -6,11 +6,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * - class ImportPrunedFundsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/invalidateblock.py b/test/functional/invalidateblock.py index c499d57b9037..dd3daf1e07bd 100755 --- a/test/functional/invalidateblock.py +++ b/test/functional/invalidateblock.py @@ -8,9 +8,7 @@ from test_framework.util import * class InvalidateTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/invalidblockrequest.py b/test/functional/invalidblockrequest.py index eabc0db8df58..9f44b44927c0 100755 --- a/test/functional/invalidblockrequest.py +++ b/test/functional/invalidblockrequest.py @@ -23,9 +23,9 @@ class InvalidBlockRequestTest(ComparisonTestFramework): ''' Can either run this test as 1 node with expected answers, or two and compare them. Change the "outcome" variable from each TestInstance object to only do the comparison. ''' - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True def run_test(self): test = TestManager(self, self.options.tmpdir) diff --git a/test/functional/invalidtxrequest.py b/test/functional/invalidtxrequest.py index a9ac231f096a..a22bd8f8cdc3 100755 --- a/test/functional/invalidtxrequest.py +++ b/test/functional/invalidtxrequest.py @@ -19,9 +19,9 @@ class InvalidTxRequestTest(ComparisonTestFramework): ''' Can either run this test as 1 node with expected answers, or two and compare them. Change the "outcome" variable from each TestInstance object to only do the comparison. ''' - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True def run_test(self): test = TestManager(self, self.options.tmpdir) diff --git a/test/functional/keypool-topup.py b/test/functional/keypool-topup.py index f14a449b5919..8302e3ef6065 100755 --- a/test/functional/keypool-topup.py +++ b/test/functional/keypool-topup.py @@ -20,8 +20,7 @@ ) class KeypoolRestoreTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=100', '-keypoolmin=20']] diff --git a/test/functional/keypool.py b/test/functional/keypool.py index 0f84b5c05501..b823ca63bb80 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -8,6 +8,8 @@ from test_framework.util import * class KeyPoolTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 def run_test(self): nodes = self.nodes @@ -78,10 +80,5 @@ def run_test(self): assert_equal(wi['keypoolsize_hd_internal'], 100) assert_equal(wi['keypoolsize'], 100) - def __init__(self): - super().__init__() - self.setup_clean_chain = False - self.num_nodes = 1 - if __name__ == '__main__': KeyPoolTest().main() diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py index ce2d556ef022..ed1315e805b1 100755 --- a/test/functional/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -8,11 +8,8 @@ from test_framework.util import assert_equal class ListSinceBlockTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 def run_test(self): self.nodes[2].generate(101) diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py index 9b970284171d..5ee85a0dac66 100755 --- a/test/functional/listtransactions.py +++ b/test/functional/listtransactions.py @@ -16,10 +16,7 @@ def txFromHex(hexstring): return tx class ListTransactionsTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False + def set_test_params(self): self.enable_mocktime() def run_test(self): diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py index 6bd6a9e34f45..1f402798e7e0 100755 --- a/test/functional/maxuploadtarget.py +++ b/test/functional/maxuploadtarget.py @@ -31,8 +31,7 @@ def on_block(self, conn, message): class MaxUploadTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-maxuploadtarget=800", "-blockmaxsize=999000"]] diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 2777291dd0ef..e24dc5a464b3 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -8,9 +8,7 @@ from test_framework.util import * class MempoolLimitTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]] diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index e225493816e0..2dedadf8ce4a 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -12,10 +12,8 @@ MAX_DESCENDANTS = 25 class MempoolPackagesTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]] # Build a transaction that spends parent_txid:vout diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index dc5a3263ffa4..01f65b137363 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -36,12 +36,8 @@ from test_framework.util import * class MempoolPersistTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - # We need 3 nodes for this test. Node1 does not have a persistent mempool. + def set_test_params(self): self.num_nodes = 3 - self.setup_clean_chain = False self.extra_args = [[], ["-persistmempool=0"], []] def run_test(self): diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 937bf4bab578..7dfddd3230df 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -13,10 +13,8 @@ # Create one-input, one-output, no-fee transaction: class MempoolCoinbaseTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [["-checkmempool"]] * 2 alert_filename = None # Set by setup_network diff --git a/test/functional/mempool_resurrect_test.py b/test/functional/mempool_resurrect_test.py index a2f6228df91c..1263c9306b63 100755 --- a/test/functional/mempool_resurrect_test.py +++ b/test/functional/mempool_resurrect_test.py @@ -9,12 +9,8 @@ # Create one-input, one-output, no-fee transaction: class MempoolCoinbaseTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = False - # Just need one node for this test self.extra_args = [["-checkmempool"]] def run_test(self): diff --git a/test/functional/mempool_spendcoinbase.py b/test/functional/mempool_spendcoinbase.py index 277ea45ad5be..58ccd3e3734f 100755 --- a/test/functional/mempool_spendcoinbase.py +++ b/test/functional/mempool_spendcoinbase.py @@ -17,11 +17,8 @@ # Create one-input, one-output, no-fee transaction: class MempoolSpendCoinbaseTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = False self.extra_args = [["-checkmempool"]] def run_test(self): diff --git a/test/functional/merkle_blocks.py b/test/functional/merkle_blocks.py index bcc65c8408ee..2125c6e17bc2 100755 --- a/test/functional/merkle_blocks.py +++ b/test/functional/merkle_blocks.py @@ -8,11 +8,8 @@ from test_framework.util import * class MerkleBlockTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 # Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing self.extra_args = [[], [], [], ["-txindex"]] diff --git a/test/functional/mining.py b/test/functional/mining.py index f3d1f3e90afb..93f98388960f 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -27,9 +27,7 @@ def assert_template(node, block, expect, rehash=True): assert_equal(rsp, expect) class MiningTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = False diff --git a/test/functional/multi_rpc.py b/test/functional/multi_rpc.py index a30e15ace9e4..a2b346f27429 100755 --- a/test/functional/multi_rpc.py +++ b/test/functional/multi_rpc.py @@ -12,10 +12,7 @@ import urllib.parse class HTTPBasicsTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 2 def setup_chain(self): diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index 7381a9fd54d8..e5453e9aaddc 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -12,9 +12,7 @@ from test_framework.util import assert_equal, assert_raises_jsonrpc class MultiWalletTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']] diff --git a/test/functional/net.py b/test/functional/net.py index 3ba3764cf9e8..37ea6824d570 100755 --- a/test/functional/net.py +++ b/test/functional/net.py @@ -17,10 +17,8 @@ p2p_port, ) - class NetTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py index 9717add272e9..60d0d876df70 100755 --- a/test/functional/nulldummy.py +++ b/test/functional/nulldummy.py @@ -37,8 +37,7 @@ def trueDummy(tx): class NULLDUMMYTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness']] diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 322cb767db31..293bc055393e 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -60,8 +60,7 @@ def add_options(self, parser): default=os.getenv("BITCOIND", "bitcoind"), help="bitcoind binary to test") - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [[], ["-whitelist=127.0.0.1"]] diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py index c5c264765a3f..9c91c0045307 100755 --- a/test/functional/p2p-compactblocks.py +++ b/test/functional/p2p-compactblocks.py @@ -89,8 +89,7 @@ def send_await_disconnect(self, message, timeout=30): wait_until(lambda: not self.connected, timeout=timeout, lock=mininode_lock) class CompactBlocksTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True # Node0 = pre-segwit, node1 = segwit-aware self.num_nodes = 2 diff --git a/test/functional/p2p-feefilter.py b/test/functional/p2p-feefilter.py index dbccb633a5b8..8c92365ceda6 100755 --- a/test/functional/p2p-feefilter.py +++ b/test/functional/p2p-feefilter.py @@ -37,11 +37,8 @@ def clear_invs(self): self.txinvs = [] class FeeFilterTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False def run_test(self): node1 = self.nodes[1] diff --git a/test/functional/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py index e7fe7372c806..cb7bbaf7e563 100755 --- a/test/functional/p2p-fullblocktest.py +++ b/test/functional/p2p-fullblocktest.py @@ -49,12 +49,11 @@ def normal_serialize(self): return r class FullBlockTest(ComparisonTestFramework): - # Can either run this test as 1 node with expected answers, or two and compare them. # Change the "outcome" variable from each TestInstance object to only do the comparison. - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True self.block_heights = {} self.coinbase_key = CECKey() self.coinbase_key.set_secretbytes(b"horsebattery") diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index f0d4d9a8b86c..f27086c97eb2 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -92,8 +92,7 @@ def on_version(self, conn, message): conn.send_message(msg_getaddr()) class P2PLeakTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-banscore='+str(banscore)]] diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py index 34ef249eeaa0..40fcde260571 100755 --- a/test/functional/p2p-mempool.py +++ b/test/functional/p2p-mempool.py @@ -13,9 +13,7 @@ from test_framework.util import * class P2PMempoolTests(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-peerbloomfilters=0"]] diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 9189f5ef23f8..8c2d2f0272c3 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -33,8 +33,7 @@ def get_virtual_size(witness_block): return vsize class TestNode(NodeConnCB): - def __init__(self): - super().__init__() + def set_test_params(self): self.getdataset = set() def on_getdata(self, conn, message): @@ -109,9 +108,7 @@ def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key): class SegWitTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [["-whitelist=127.0.0.1"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]] diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py index c3b29c215b7d..51d4769efc3f 100755 --- a/test/functional/p2p-timeouts.py +++ b/test/functional/p2p-timeouts.py @@ -33,8 +33,7 @@ def on_version(self, conn, message): pass class TimeoutsTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index a7aacf908d1e..5dfac6dd10e0 100755 --- a/test/functional/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -28,8 +28,7 @@ def on_inv(self, conn, message): pass class VersionBitsWarningTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/preciousblock.py b/test/functional/preciousblock.py index 04b41e76baef..40d7bb14edce 100755 --- a/test/functional/preciousblock.py +++ b/test/functional/preciousblock.py @@ -35,8 +35,7 @@ def node_sync_via_rpc(nodes): unidirectional_node_sync_via_rpc(node_src, node_dest) class PreciousTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/prioritise_transaction.py b/test/functional/prioritise_transaction.py index 4fc03d254746..7ad368acd4b8 100755 --- a/test/functional/prioritise_transaction.py +++ b/test/functional/prioritise_transaction.py @@ -9,9 +9,7 @@ from test_framework.mininode import COIN, MAX_BLOCK_BASE_SIZE class PrioritiseTransactionTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [["-printpriority=1"], ["-printpriority=1"]] diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index adbbda278dac..26cb645da431 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -41,13 +41,7 @@ RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports - class ProxyTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def setup_nodes(self): self.have_ipv6 = test_ipv6_local() # Create two proxies on different ports diff --git a/test/functional/pruning.py b/test/functional/pruning.py index 9690428769f8..a4afbd46d73f 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -26,9 +26,7 @@ def calc_usage(blockdir): return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.) class PruneTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 6 diff --git a/test/functional/rawtransactions.py b/test/functional/rawtransactions.py index 6272fc69b783..51dda09ac415 100755 --- a/test/functional/rawtransactions.py +++ b/test/functional/rawtransactions.py @@ -17,9 +17,7 @@ # Create one-input, one-output, no-fee transaction: class RawTransactionsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py index b16583416998..48eb1c51b51c 100755 --- a/test/functional/receivedby.py +++ b/test/functional/receivedby.py @@ -23,11 +23,7 @@ def get_sub_array_from_array(object_array, to_match): return [] class ReceivedByTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False + def set_test_params(self): self.enable_mocktime() def run_test(self): diff --git a/test/functional/reindex.py b/test/functional/reindex.py index 0d2a10659206..1f684a1afe3b 100755 --- a/test/functional/reindex.py +++ b/test/functional/reindex.py @@ -15,8 +15,7 @@ class ReindexTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index bc6765498750..220e88968663 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -61,10 +61,8 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): class ReplaceByFeeTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = False self.extra_args= [["-maxorphantx=1000", "-whitelist=127.0.0.1", "-limitancestorcount=50", diff --git a/test/functional/resendwallettransactions.py b/test/functional/resendwallettransactions.py index db6f6eec4589..d6ba5913912d 100755 --- a/test/functional/resendwallettransactions.py +++ b/test/functional/resendwallettransactions.py @@ -8,11 +8,9 @@ from test_framework.util import assert_equal, assert_raises_jsonrpc class ResendWalletTransactionsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.extra_args = [['--walletbroadcast=false']] + def set_test_params(self): self.num_nodes = 1 + self.extra_args = [['--walletbroadcast=false']] def run_test(self): # Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled. diff --git a/test/functional/rest.py b/test/functional/rest.py index a69dbb501333..437111a4d7fd 100755 --- a/test/functional/rest.py +++ b/test/functional/rest.py @@ -43,8 +43,7 @@ def http_post_call(host, port, path, requestdata = '', response_object = 0): class RESTTest (BitcoinTestFramework): FORMAT_SEPARATOR = "." - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index a7661421ff9a..0cf64beebd40 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -11,11 +11,8 @@ from test_framework.util import * from test_framework.netutil import * - class RPCBindTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py index 3b286000a167..da61cc66e685 100755 --- a/test/functional/rpcnamedargs.py +++ b/test/functional/rpcnamedargs.py @@ -10,15 +10,8 @@ assert_raises_jsonrpc, ) - class NamedArgumentTest(BitcoinTestFramework): - """ - Test named arguments on RPC calls. - """ - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 1 def run_test(self): diff --git a/test/functional/segwit.py b/test/functional/segwit.py index 51eaa34a54d4..c08fbd3e7751 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -75,9 +75,7 @@ def find_unspent(node, min_value): return utxo class SegWitTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0"], diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index 6451b097c07d..fe577dc20a2d 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -174,8 +174,7 @@ def send_getblocks(self, locator): self.send_message(getblocks_message) class SendHeadersTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/signmessages.py b/test/functional/signmessages.py index 42f6a9daaf1f..5fdfeceb76a0 100755 --- a/test/functional/signmessages.py +++ b/test/functional/signmessages.py @@ -7,9 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework class SignMessagesTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py index 415727268a30..b47ef939558a 100755 --- a/test/functional/signrawtransactions.py +++ b/test/functional/signrawtransactions.py @@ -9,8 +9,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index caf35926522c..76632fc57848 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -141,11 +141,8 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): class EstimateFeeTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 3 - self.setup_clean_chain = False def setup_network(self): """ diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 5e3644a9142b..d860bc5594c6 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -48,58 +48,30 @@ class TestStatus(Enum): class BitcoinTestFramework(object): """Base class for a bitcoin test script. - Individual bitcoin test scripts should subclass this class and override the following methods: + Individual bitcoin test scripts should subclass this class and override the run_test() method. - - __init__() + Individual tests can also override the following methods to customize the test setup: + + - set_test_params() - add_options() - setup_chain() - setup_network() - - run_test() + - setup_nodes() - The main() method should not be overridden. + The __init__() and main() methods should not be overridden. This class also contains various public and private helper methods.""" - # Methods to override in subclass test scripts. def __init__(self): + """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" self.num_nodes = 4 self.setup_clean_chain = False self.nodes = [] self.mocktime = 0 - - def add_options(self, parser): - pass - - def setup_chain(self): - self.log.info("Initializing test directory " + self.options.tmpdir) - if self.setup_clean_chain: - self._initialize_chain_clean() - else: - self._initialize_chain() - - def setup_network(self): - self.setup_nodes() - - # Connect the nodes as a "chain". This allows us - # to split the network between nodes 1 and 2 to get - # two halves that can work on competing chains. - for i in range(self.num_nodes - 1): - connect_nodes_bi(self.nodes, i, i + 1) - self.sync_all() - - def setup_nodes(self): - extra_args = None - if hasattr(self, "extra_args"): - extra_args = self.extra_args - self.add_nodes(self.num_nodes, extra_args) - self.start_nodes() - - def run_test(self): - raise NotImplementedError - - # Main function. This should not be overridden by the subclass test scripts. + self.set_test_params() def main(self): + """Main function. This should not be overridden by the subclass test scripts.""" parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", @@ -203,6 +175,46 @@ def main(self): logging.shutdown() sys.exit(TEST_EXIT_FAILED) + # Methods to override in subclass test scripts. + def set_test_params(self): + """Override this method to change default values for number of nodes, topology, etc""" + pass + + def add_options(self, parser): + """Override this method to add command-line options to the test""" + pass + + def setup_chain(self): + """Override this method to customize blockchain setup""" + self.log.info("Initializing test directory " + self.options.tmpdir) + if self.setup_clean_chain: + self._initialize_chain_clean() + else: + self._initialize_chain() + + def setup_network(self): + """Override this method to customize test network topology""" + self.setup_nodes() + + # Connect the nodes as a "chain". This allows us + # to split the network between nodes 1 and 2 to get + # two halves that can work on competing chains. + for i in range(self.num_nodes - 1): + connect_nodes_bi(self.nodes, i, i + 1) + self.sync_all() + + def setup_nodes(self): + """Override this method to customize test node setup""" + extra_args = None + if hasattr(self, "extra_args"): + extra_args = self.extra_args + self.add_nodes(self.num_nodes, extra_args) + self.start_nodes() + + def run_test(self): + """Override this method to define test logic""" + raise NotImplementedError + # Public helper methods. These can be accessed by the subclass test scripts. def add_nodes(self, num_nodes, extra_args=None, rpchost=None, timewait=None, binary=None): @@ -442,8 +454,7 @@ class ComparisonTestFramework(BitcoinTestFramework): - 2 binaries: 1 test binary, 1 ref binary - n>2 binaries: 1 test binary, n-1 ref binaries""" - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True diff --git a/test/functional/txn_clone.py b/test/functional/txn_clone.py index 9b81af96cf0b..fc133050b0d7 100755 --- a/test/functional/txn_clone.py +++ b/test/functional/txn_clone.py @@ -8,12 +8,6 @@ from test_framework.util import * class TxnMallTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/txn_doublespend.py b/test/functional/txn_doublespend.py index 1bd3b3271c51..ff24fac254ea 100755 --- a/test/functional/txn_doublespend.py +++ b/test/functional/txn_doublespend.py @@ -9,11 +9,6 @@ class TxnMallTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/uptime.py b/test/functional/uptime.py index b20d6f5cb62b..78236b239374 100755 --- a/test/functional/uptime.py +++ b/test/functional/uptime.py @@ -13,9 +13,7 @@ class UptimeTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py index 158aa9ae896c..40726d2a7609 100755 --- a/test/functional/wallet-accounts.py +++ b/test/functional/wallet-accounts.py @@ -17,9 +17,7 @@ from test_framework.util import assert_equal class WalletAccountsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [[]] diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index e0381b9809f9..39b7164d6e6e 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -56,10 +56,7 @@ def read_dump(file_name, addrs, hd_master_addr_old): class WalletDumpTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 1 self.extra_args = [["-keypool=90"]] diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index 2f38e6fee846..f63bb2ea5e1c 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -13,9 +13,7 @@ ) class WalletEncryptionTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py index 13b9dd9a906f..68b5e5b8d48a 100755 --- a/test/functional/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -11,11 +11,8 @@ ) import shutil - class WalletHDTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=0']] diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 7190de94b670..79727f9be62d 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -7,17 +7,8 @@ from test_framework.util import * class WalletTest(BitcoinTestFramework): - - def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): - """Return curr_balance after asserting the fee was in range""" - fee = balance_with_fee - curr_balance - assert_fee_amount(fee, tx_size, fee_per_byte * 1000) - return curr_balance - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): @@ -30,8 +21,13 @@ def setup_network(self): connect_nodes_bi(self.nodes,0,2) self.sync_all([self.nodes[0:3]]) - def run_test(self): + def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): + """Return curr_balance after asserting the fee was in range""" + fee = balance_with_fee - curr_balance + assert_fee_amount(fee, tx_size, fee_per_byte * 1000) + return curr_balance + def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index 688cd6d0c866..36714164a832 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -37,11 +37,8 @@ from test_framework.util import * class WalletBackupTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 # nodes 1, 2,3 are spenders, let's give them a keypool=100 self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index 1005a4b95fc0..c001517a6d4f 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -20,9 +20,7 @@ ) class ZapWalletTXesTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index b5a22ea07fc8..3f2668ee8724 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -13,9 +13,7 @@ ) class ZMQTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 def setup_nodes(self): From 82bf6fc6d48a232cc0ceb54b136d86914f49013c Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 24 Aug 2017 11:11:56 -0400 Subject: [PATCH 048/196] [tests] Functional tests must explicitly set num_nodes Github-Pull: #11121 Rebased-From: 7148b74dc39110f53c665b94fa9d994c6ad6dc1c --- test/functional/example_test.py | 4 +++- test/functional/fundrawtransaction.py | 1 + test/functional/getblocktemplate_longpoll.py | 3 +++ test/functional/getchaintips.py | 3 +++ test/functional/listsinceblock.py | 1 + test/functional/listtransactions.py | 1 + test/functional/merkle_blocks.py | 1 + test/functional/p2p-segwit.py | 1 + test/functional/proxy_test.py | 3 +++ test/functional/receivedby.py | 1 + test/functional/test_framework/test_framework.py | 12 ++++++------ test/functional/txn_clone.py | 3 +++ test/functional/txn_doublespend.py | 2 ++ test/functional/wallet.py | 1 + test/functional/walletbackup.py | 1 + 15 files changed, 31 insertions(+), 7 deletions(-) diff --git a/test/functional/example_test.py b/test/functional/example_test.py index de8934f74b76..936aceb89aa7 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -77,7 +77,9 @@ class ExampleTest(BitcoinTestFramework): # and setup_nodes() methods to customize the test setup as required. def set_test_params(self): - """Override any test parameters for your individual test.""" + """Override test parameters for your individual test. + + This method must be overridden and num_nodes must be exlicitly set.""" self.setup_clean_chain = True self.num_nodes = 3 # Use self.extra_args to change command-line arguments for the nodes diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index dec3d41bfc5f..3326b58c4571 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -16,6 +16,7 @@ def get_unspent(listunspent, amount): class RawTransactionsTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True def setup_network(self, split=False): diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index 85d2560244e5..89768bd2fb53 100755 --- a/test/functional/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -23,6 +23,9 @@ def run(self): self.node.getblocktemplate({'longpollid':self.longpollid}) class GetBlockTemplateLPTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 2 + def run_test(self): self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.") self.nodes[0].generate(10) diff --git a/test/functional/getchaintips.py b/test/functional/getchaintips.py index 00fc23c6b0d3..21b67bfc64f9 100755 --- a/test/functional/getchaintips.py +++ b/test/functional/getchaintips.py @@ -14,6 +14,9 @@ from test_framework.util import assert_equal class GetChainTipsTest (BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 + def run_test (self): tips = self.nodes[0].getchaintips () assert_equal (len (tips), 1) diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py index ed1315e805b1..6f428388ecbb 100755 --- a/test/functional/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -9,6 +9,7 @@ class ListSinceBlockTest (BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True def run_test(self): diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py index 5ee85a0dac66..e4522cc3b5c7 100755 --- a/test/functional/listtransactions.py +++ b/test/functional/listtransactions.py @@ -17,6 +17,7 @@ def txFromHex(hexstring): class ListTransactionsTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 2 self.enable_mocktime() def run_test(self): diff --git a/test/functional/merkle_blocks.py b/test/functional/merkle_blocks.py index 2125c6e17bc2..a58334b2a540 100755 --- a/test/functional/merkle_blocks.py +++ b/test/functional/merkle_blocks.py @@ -9,6 +9,7 @@ class MerkleBlockTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True # Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing self.extra_args = [[], [], [], ["-txindex"]] diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 8c2d2f0272c3..9bb72c819945 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -34,6 +34,7 @@ def get_virtual_size(witness_block): class TestNode(NodeConnCB): def set_test_params(self): + self.num_nodes = 3 self.getdataset = set() def on_getdata(self, conn, message): diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index 26cb645da431..81b99d1bf448 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -42,6 +42,9 @@ RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports class ProxyTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 + def setup_nodes(self): self.have_ipv6 = test_ipv6_local() # Create two proxies on different ports diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py index 48eb1c51b51c..db6fc86b82fe 100755 --- a/test/functional/receivedby.py +++ b/test/functional/receivedby.py @@ -24,6 +24,7 @@ def get_sub_array_from_array(object_array, to_match): class ReceivedByTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 2 self.enable_mocktime() def run_test(self): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index d860bc5594c6..103651f1752b 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -48,11 +48,10 @@ class TestStatus(Enum): class BitcoinTestFramework(object): """Base class for a bitcoin test script. - Individual bitcoin test scripts should subclass this class and override the run_test() method. + Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods. Individual tests can also override the following methods to customize the test setup: - - set_test_params() - add_options() - setup_chain() - setup_network() @@ -64,12 +63,13 @@ class BitcoinTestFramework(object): def __init__(self): """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" - self.num_nodes = 4 self.setup_clean_chain = False self.nodes = [] self.mocktime = 0 self.set_test_params() + assert hasattr(self, "num_nodes"), "Test must set self.num_nodes in set_test_params()" + def main(self): """Main function. This should not be overridden by the subclass test scripts.""" @@ -177,8 +177,8 @@ def main(self): # Methods to override in subclass test scripts. def set_test_params(self): - """Override this method to change default values for number of nodes, topology, etc""" - pass + """Tests must this method to change default values for number of nodes, topology, etc""" + raise NotImplementedError def add_options(self, parser): """Override this method to add command-line options to the test""" @@ -212,7 +212,7 @@ def setup_nodes(self): self.start_nodes() def run_test(self): - """Override this method to define test logic""" + """Tests must override this method to define test logic""" raise NotImplementedError # Public helper methods. These can be accessed by the subclass test scripts. diff --git a/test/functional/txn_clone.py b/test/functional/txn_clone.py index fc133050b0d7..740bb2d4c5c0 100755 --- a/test/functional/txn_clone.py +++ b/test/functional/txn_clone.py @@ -8,6 +8,9 @@ from test_framework.util import * class TxnMallTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 + def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/txn_doublespend.py b/test/functional/txn_doublespend.py index ff24fac254ea..69629ef95196 100755 --- a/test/functional/txn_doublespend.py +++ b/test/functional/txn_doublespend.py @@ -8,6 +8,8 @@ from test_framework.util import * class TxnMallTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 79727f9be62d..de3aa8a87554 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -8,6 +8,7 @@ class WalletTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index 36714164a832..15ea26afa160 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -38,6 +38,7 @@ class WalletBackupTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True # nodes 1, 2,3 are spenders, let's give them a keypool=100 self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] From cef03198dcdca63d88bf8f50edcc79fa6b268261 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 1 Sep 2017 14:24:30 -0400 Subject: [PATCH 049/196] [tests] fixups from set_test_params() Github-Pull: #11215 Rebased-From: 3918d93f3cd2305dc12cb964aebba0fc1f8720b4 --- test/functional/bitcoin_cli.py | 3 +-- test/functional/example_test.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py index 103320209268..7acfede3f7a5 100755 --- a/test/functional/bitcoin_cli.py +++ b/test/functional/bitcoin_cli.py @@ -8,8 +8,7 @@ class TestBitcoinCli(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 936aceb89aa7..228e1505983c 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -85,7 +85,7 @@ def set_test_params(self): # Use self.extra_args to change command-line arguments for the nodes self.extra_args = [[], ["-logips"], []] - # self.log.info("I've finished __init__") # Oops! Can't run self.log before run_test() + # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() # Use add_options() to add specific command-line options for your test. # In practice this is not used very much, since the tests are mostly written From 7310f1f2eb5900a9d07e2c6427a71d161762000a Mon Sep 17 00:00:00 2001 From: Daniel Edgecumbe Date: Wed, 30 Aug 2017 19:14:07 +0100 Subject: [PATCH 050/196] [Qt] Fix display of package name on 'open config file' tooltip Github-Pull: #11198 Rebased-From: 14ccd4d8d1847d64903224562ad3c7eb795b3781 --- src/qt/optionsdialog.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index b80b6541dddd..550884ed8e4f 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -80,6 +80,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME))); ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME))); + ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(tr(PACKAGE_NAME))); + ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME))); ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); for (const QString &langStr : translations.entryList()) From 44241765e3c8caa9248949cbe0fbc1c3072319c0 Mon Sep 17 00:00:00 2001 From: Cristian Mircea Messel Date: Tue, 5 Sep 2017 19:55:37 +0300 Subject: [PATCH 051/196] Improve signmessages functional test This patch improves branch coverage of the test, making sure a message can not be verified with the wrong address or signature. Github-Pull: #11241 Rebased-From: b3d6fc654770e3b4d2f82e8d77e531df9e522982 --- test/functional/signmessages.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/functional/signmessages.py b/test/functional/signmessages.py index 5fdfeceb76a0..52ba6a5ad761 100755 --- a/test/functional/signmessages.py +++ b/test/functional/signmessages.py @@ -5,6 +5,7 @@ """Test RPC commands for signing and verifying messages.""" from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal class SignMessagesTest(BitcoinTestFramework): def set_test_params(self): @@ -14,20 +15,24 @@ def set_test_params(self): def run_test(self): message = 'This is just a test message' - # Test the signing with a privkey - privKey = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N' + self.log.info('test signing with priv_key') + priv_key = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N' address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB' - signature = self.nodes[0].signmessagewithprivkey(privKey, message) - - # Verify the message + expected_signature = 'INbVnW4e6PeRmsv2Qgu8NuopvrVjkcxob+sX8OcZG0SALhWybUjzMLPdAsXI46YZGb0KQTRii+wWIQzRpG/U+S0=' + signature = self.nodes[0].signmessagewithprivkey(priv_key, message) + assert_equal(expected_signature, signature) assert(self.nodes[0].verifymessage(address, signature, message)) - # Test the signing with an address with wallet + self.log.info('test signing with an address with wallet') address = self.nodes[0].getnewaddress() signature = self.nodes[0].signmessage(address, message) - - # Verify the message assert(self.nodes[0].verifymessage(address, signature, message)) + self.log.info('test verifying with another address should not work') + other_address = self.nodes[0].getnewaddress() + other_signature = self.nodes[0].signmessage(other_address, message) + assert(not self.nodes[0].verifymessage(other_address, signature, message)) + assert(not self.nodes[0].verifymessage(address, other_signature, message)) + if __name__ == '__main__': SignMessagesTest().main() From f0b67954f06e71eb2f4df0125b7075d8b36e0c6f Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Tue, 5 Sep 2017 15:02:17 +1200 Subject: [PATCH 052/196] Remove redundant testutil files Github-Pull: #11234 Rebased-From: d1138e36208dac87a27f415f39c70377636e93f1 --- src/Makefile.qttest.include | 6 ++---- src/Makefile.test.include | 2 -- src/qt/test/rpcnestedtests.cpp | 1 - src/test/test_bitcoin.cpp | 4 +--- src/test/testutil.cpp | 15 --------------- src/test/testutil.h | 15 --------------- 6 files changed, 3 insertions(+), 40 deletions(-) delete mode 100644 src/test/testutil.cpp delete mode 100644 src/test/testutil.h diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 02f30bc9527b..ea2ed17472ee 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -25,12 +25,10 @@ TEST_QT_H = \ qt/test/wallettests.h TEST_BITCOIN_CPP = \ - test/test_bitcoin.cpp \ - test/testutil.cpp + test/test_bitcoin.cpp TEST_BITCOIN_H = \ - test/test_bitcoin.h \ - test/testutil.h + test/test_bitcoin.h qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6415b3d2e339..01ab0134fee5 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -74,8 +74,6 @@ BITCOIN_TESTS =\ test/test_bitcoin.cpp \ test/test_bitcoin.h \ test/test_bitcoin_main.cpp \ - test/testutil.cpp \ - test/testutil.h \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index e2abfb3742e2..c1f71a6b4eab 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -11,7 +11,6 @@ #include "rpc/register.h" #include "rpc/server.h" #include "rpcconsole.h" -#include "test/testutil.h" #include "test/test_bitcoin.h" #include "univalue.h" #include "util.h" diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 94ec7c03f595..194f62ca1183 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -22,8 +22,6 @@ #include "rpc/register.h" #include "script/sigcache.h" -#include "test/testutil.h" - #include uint256 insecure_rand_seed = GetRandHash(); @@ -61,7 +59,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha RegisterAllCoreRPCCommands(tableRPC); ClearDatadirCache(); - pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000))); + pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000))); fs::create_directories(pathTemp); gArgs.ForceSetArg("-datadir", pathTemp.string()); diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp deleted file mode 100644 index 591d0bf30271..000000000000 --- a/src/test/testutil.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2009-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. - -#include "testutil.h" - -#ifdef WIN32 -#include -#endif - -#include "fs.h" - -fs::path GetTempPath() { - return fs::temp_directory_path(); -} diff --git a/src/test/testutil.h b/src/test/testutil.h deleted file mode 100644 index cbe784d6400b..000000000000 --- a/src/test/testutil.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2009-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. - -/** - * Utility functions shared by unit tests - */ -#ifndef BITCOIN_TEST_TESTUTIL_H -#define BITCOIN_TEST_TESTUTIL_H - -#include "fs.h" - -fs::path GetTempPath(); - -#endif // BITCOIN_TEST_TESTUTIL_H From 47c02a8ae8b406a1a7d7004b2a0337a1f32420e9 Mon Sep 17 00:00:00 2001 From: Chris Moore Date: Wed, 30 Aug 2017 00:32:54 -0700 Subject: [PATCH 053/196] qt: Use IsMine to validate custom change address (cherry picked from commit c41224dfd51c896341bbf2fa23e160bf5ffe27c3) Github-Pull: #11247 Rebased-From: a1ea1cfbd8d4fc976f0ab2423d395e03ded6eedd --- src/qt/sendcoinsdialog.cpp | 10 ++++------ src/qt/walletmodel.cpp | 4 ++-- src/qt/walletmodel.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 38a475227e55..7732c7398818 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -789,10 +789,8 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) } else // Valid address { - CKeyID keyid; - addr.GetKeyID(keyid); - if (!model->havePrivKey(keyid)) // Unknown change address - { + const CTxDestination dest = addr.Get(); + if (!model->IsSpendable(dest)) { ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); // confirmation dialog @@ -800,7 +798,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); if(btnRetVal == QMessageBox::Yes) - CoinControlDialog::coinControl->destChange = addr.Get(); + CoinControlDialog::coinControl->destChange = dest; else { ui->lineEditCoinControlChange->setText(""); @@ -819,7 +817,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) else ui->labelCoinControlChangeLabel->setText(tr("(no label)")); - CoinControlDialog::coinControl->destChange = addr.Get(); + CoinControlDialog::coinControl->destChange = dest; } } } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 3ca726d0f906..aedbf22e4d1d 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -561,9 +561,9 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const return wallet->GetPubKey(address, vchPubKeyOut); } -bool WalletModel::havePrivKey(const CKeyID &address) const +bool WalletModel::IsSpendable(const CTxDestination& dest) const { - return wallet->HaveKey(address); + return IsMine(*wallet, dest) & ISMINE_SPENDABLE; } bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 6be36a57e256..05733f82727a 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -190,7 +190,7 @@ class WalletModel : public QObject UnlockContext requestUnlock(); bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; - bool havePrivKey(const CKeyID &address) const; + bool IsSpendable(const CTxDestination& dest) const; bool getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const; void getOutputs(const std::vector& vOutpoints, std::vector& vOutputs); bool isSpent(const COutPoint& outpoint) const; From f3f78917769b9bc65c133a160dba7df18a33b27d Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Thu, 31 Aug 2017 11:15:48 +1200 Subject: [PATCH 054/196] Stop test_bitcoin-qt touching ~/.bitcoin Github-Pull: #11210 Rebased-From: dea086f498097d19a2c9acbfc753c9c2d68dbb03 --- src/qt/test/rpcnestedtests.cpp | 7 ------- src/qt/test/test_main.cpp | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index c1f71a6b4eab..98a6605190f4 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -36,11 +36,6 @@ void RPCNestedTests::rpcNestedTests() // do some test setup // could be moved to a more generic place when we add more tests on QT level tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); - ClearDatadirCache(); - std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); - QDir dir(QString::fromStdString(path)); - dir.mkpath("."); - gArgs.ForceSetArg("-datadir", path); //mempool.setSanityCheck(1.0); TestingSetup test; @@ -135,6 +130,4 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , #endif - - fs::remove_all(fs::path(path)); } diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 1b28a285f1e6..b5790e4e2be8 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -53,6 +53,10 @@ int main(int argc, char *argv[]) SetupNetworking(); SelectParams(CBaseChainParams::MAIN); noui_connect(); + ClearDatadirCache(); + fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000)); + fs::create_directories(pathTemp); + gArgs.ForceSetArg("-datadir", pathTemp.string()); bool fInvalid = false; @@ -97,5 +101,7 @@ int main(int argc, char *argv[]) } #endif + fs::remove_all(pathTemp); + return fInvalid; } From eeb24a3a0157c41a0aae1d5561cf490abe378585 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 16 Aug 2017 08:52:24 -0700 Subject: [PATCH 055/196] [qa] TestNode: Add wait_until_stopped helper method Github-Pull: #11067 Rebased-From: faa8d9581affde35a8242c63fca8a52004d4f943 --- test/functional/blockchain.py | 4 +-- test/functional/fundrawtransaction.py | 2 +- .../test_framework/test_framework.py | 8 ++--- test/functional/test_framework/test_node.py | 30 +++++++++++-------- test/functional/wallet-encryption.py | 2 +- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 5d04de9940c4..50be9262e4f9 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -21,7 +21,7 @@ import http.client import subprocess -from test_framework.test_framework import (BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT) +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises, @@ -141,7 +141,7 @@ def _test_stopatheight(self): except (ConnectionError, http.client.BadStatusLine): pass # The node already shut down before response self.log.debug('Node should stop at this height...') - self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].wait_until_stopped() self.start_node(0) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 3326b58c4571..42d95dd5204e 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the fundrawtransaction RPC.""" -from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 103651f1752b..a53eb517998d 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -43,8 +43,6 @@ class TestStatus(Enum): TEST_EXIT_FAILED = 1 TEST_EXIT_SKIPPED = 77 -BITCOIND_PROC_WAIT_TIMEOUT = 60 - class BitcoinTestFramework(object): """Base class for a bitcoin test script. @@ -263,8 +261,7 @@ def start_nodes(self, extra_args=None): def stop_node(self, i): """Stop a bitcoind test node""" self.nodes[i].stop_node() - while not self.nodes[i].is_node_stopped(): - time.sleep(0.1) + self.nodes[i].wait_until_stopped() def stop_nodes(self): """Stop multiple bitcoind test nodes""" @@ -274,8 +271,7 @@ def stop_nodes(self): for node in self.nodes: # Wait for nodes to stop - while not node.is_node_stopped(): - time.sleep(0.1) + node.wait_until_stopped() def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index efb3ac9d1659..f58a372a144a 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -17,9 +17,12 @@ assert_equal, get_rpc_proxy, rpc_url, + wait_until, ) from .authproxy import JSONRPCException +BITCOIND_PROC_WAIT_TIMEOUT = 60 + class TestNode(): """A class for representing a bitcoind node under test. @@ -125,14 +128,20 @@ def is_node_stopped(self): if not self.running: return True return_code = self.process.poll() - if return_code is not None: - # process has stopped. Assert that it didn't return an error code. - assert_equal(return_code, 0) - self.running = False - self.process = None - self.log.debug("Node stopped") - return True - return False + if return_code is None: + return False + + # process has stopped. Assert that it didn't return an error code. + assert_equal(return_code, 0) + self.running = False + self.process = None + self.rpc_connected = False + self.rpc = None + self.log.debug("Node stopped") + return True + + def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): + wait_until(self.is_node_stopped, timeout=timeout) def node_encrypt_wallet(self, passphrase): """"Encrypts the wallet. @@ -140,10 +149,7 @@ def node_encrypt_wallet(self, passphrase): This causes bitcoind to shutdown, so this method takes care of cleaning up resources.""" self.encryptwallet(passphrase) - while not self.is_node_stopped(): - time.sleep(0.1) - self.rpc = None - self.rpc_connected = False + self.wait_until_stopped() class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index f63bb2ea5e1c..ce1e7744e903 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -6,7 +6,7 @@ import time -from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_jsonrpc, From 812c87004311732da2fc8840a483be80c7a443ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 16:52:25 +0100 Subject: [PATCH 056/196] [test] Improve assert_raises_jsonrpc docstring Github-Pull: #11125 Rebased-From: e1274947d4574bb83a020d0e178f0e5db7fc6282 --- test/functional/test_framework/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index a14cda07d0cb..a5bc495dfaf8 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -62,13 +62,13 @@ def assert_raises_jsonrpc(code, message, fun, *args, **kwds): Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException and verifies that the error code and message are as expected. Throws AssertionError if - no JSONRPCException was returned or if the error code/message are not as expected. + no JSONRPCException was raised or if the error code/message are not as expected. Args: code (int), optional: the error code returned by the RPC call (defined in src/rpc/protocol.h). Set to None if checking the error code is not required. message (string), optional: [a substring of] the error string returned by the - RPC call. Set to None if checking the error string is not required + RPC call. Set to None if checking the error string is not required. fun (function): the function to call. This should be the name of an RPC. args*: positional arguments for the function. kwds**: named arguments for the function. From e0bfd28de28efb1ffa84e89d76c144824dae987f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 17:07:21 +0100 Subject: [PATCH 057/196] [test] Add support for custom arguments to TestNodeCLI Github-Pull: #11125 Rebased-From: 5c18a84b9a49e3f9dacf0502dbf7d5d755f38da6 --- test/functional/test_framework/test_node.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index f58a372a144a..363025740a53 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -155,8 +155,16 @@ class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" def __init__(self, binary, datadir): + self.args = [] self.binary = binary self.datadir = datadir + self.input = None + + def __call__(self, *args, input=None): + # TestNodeCLI is callable with bitcoin-cli command-line args + self.args = [str(arg) for arg in args] + self.input = input + return self def __getattr__(self, command): def dispatcher(*args, **kwargs): @@ -169,9 +177,9 @@ def send_cli(self, command, *args, **kwargs): pos_args = [str(arg) for arg in args] named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()] assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call" - p_args = [self.binary, "-datadir=" + self.datadir] + p_args = [self.binary, "-datadir=" + self.datadir] + self.args if named_args: p_args += ["-named"] p_args += [command] + pos_args + named_args - cli_output = subprocess.check_output(p_args, universal_newlines=True) + cli_output = subprocess.check_output(p_args, input=self.input, universal_newlines=True) return json.loads(cli_output, parse_float=decimal.Decimal) From e38211f5e8900ee9027c671d7c655958e4dbe8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 16:35:57 +0100 Subject: [PATCH 058/196] [test] Add assert_raises_process_error to assert process errors Github-Pull: #11125 Rebased-From: 232e3e8471edb346c09f906c996b2f350cabc72a --- test/functional/test_framework/util.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index a5bc495dfaf8..b2d8199d12b8 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -12,6 +12,7 @@ import os import random import re +from subprocess import CalledProcessError import time from . import coverage @@ -57,6 +58,30 @@ def assert_raises_message(exc, message, fun, *args, **kwds): else: raise AssertionError("No exception raised") +def assert_raises_process_error(returncode, output, fun, *args, **kwds): + """Execute a process and asserts the process return code and output. + + Calls function `fun` with arguments `args` and `kwds`. Catches a CalledProcessError + and verifies that the return code and output are as expected. Throws AssertionError if + no CalledProcessError was raised or if the return code and output are not as expected. + + Args: + returncode (int): the process return code. + output (string): [a substring of] the process output. + fun (function): the function to call. This should execute a process. + args*: positional arguments for the function. + kwds**: named arguments for the function. + """ + try: + fun(*args, **kwds) + except CalledProcessError as e: + if returncode != e.returncode: + raise AssertionError("Unexpected returncode %i" % e.returncode) + if output not in e.output: + raise AssertionError("Expected substring not found:" + e.output) + else: + raise AssertionError("No exception raised") + def assert_raises_jsonrpc(code, message, fun, *args, **kwds): """Run an RPC and verify that a specific JSONRPC exception code and message is raised. From 2b97b36e5d37c6935dce112f90213f4f49cd88ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 16:36:13 +0100 Subject: [PATCH 059/196] [test] Replace check_output with low level version Github-Pull: #11125 Rebased-From: ce379b47b92d6c04250c21719bb1abfb41c586ad --- test/functional/test_framework/test_node.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 363025740a53..12dab57a022d 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -181,5 +181,10 @@ def send_cli(self, command, *args, **kwargs): if named_args: p_args += ["-named"] p_args += [command] + pos_args + named_args - cli_output = subprocess.check_output(p_args, input=self.input, universal_newlines=True) - return json.loads(cli_output, parse_float=decimal.Decimal) + process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + cli_stdout, cli_stderr = process.communicate(input=self.input) + returncode = process.poll() + if returncode: + # Ignore cli_stdout, raise with cli_stderr + raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr) + return json.loads(cli_stdout, parse_float=decimal.Decimal) From 2e31b1d48d4da31bf32e1e4123c7e5d662490826 Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Wed, 6 Sep 2017 10:49:36 +1200 Subject: [PATCH 060/196] Fix division by zero in time remaining Github-Pull: #11237 Rebased-From: 3b69a08c53c2ef738f32c270fdacf1e4ed5a4c97 --- src/qt/modaloverlay.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index a83f285034fd..4f357e297d79 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -99,15 +99,18 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri progressDelta = progressStart-sample.second; timeDelta = blockProcessTime[0].first - sample.first; progressPerHour = progressDelta/(double)timeDelta*1000*3600; - remainingMSecs = remainingProgress / progressDelta * timeDelta; + remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1; break; } } // show progress increase per hour ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%"); - // show expected remaining time - ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs/1000.0)); + if(remainingMSecs >= 0) { + ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0)); + } else { + ui->expectedTimeLeft->setText(QObject::tr("unknown")); + } static const int MAX_SAMPLES = 5000; if (blockProcessTime.count() > MAX_SAMPLES) @@ -169,4 +172,4 @@ void ModalOverlay::closeClicked() { showHide(true); userClosed = true; -} +} \ No newline at end of file From 921542e0bde120cc5e36e6c400b9fcd486c73cdf Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 7 Sep 2017 18:16:34 +0200 Subject: [PATCH 061/196] rpc: update cli for estimatefee argument rename The first argument of estimatesmartfee was renamed from nblocks to conf_target in 06bcdb8da64502a64df03f3c89fbc6ccb72cd349. Update the client-side table as well. Github-Pull: #11267 Rebased-From: 24697c40ee6739b812259140042d426c81179977 --- src/rpc/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 417945378242..7c1c4c55a750 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -116,7 +116,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawmempool", 0, "verbose" }, { "estimatefee", 0, "nblocks" }, { "estimatesmartfee", 0, "nblocks" }, - { "estimaterawfee", 0, "nblocks" }, + { "estimaterawfee", 0, "conf_target" }, { "estimaterawfee", 1, "threshold" }, { "prioritisetransaction", 1, "dummy" }, { "prioritisetransaction", 2, "fee_delta" }, From b1a6c946838fb070fe3079084b800836c7d5ddfa Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 7 Sep 2017 19:15:45 +0200 Subject: [PATCH 062/196] rpc: make estimatesmartfee argument naming consistent with documentation Github-Pull: #11267 Rebased-From: 5acd82de9ad6df8cab922da66d49b8ff2bd35439 --- src/rpc/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 7c1c4c55a750..406ad2f6ec60 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -115,7 +115,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "keypoolrefill", 0, "newsize" }, { "getrawmempool", 0, "verbose" }, { "estimatefee", 0, "nblocks" }, - { "estimatesmartfee", 0, "nblocks" }, + { "estimatesmartfee", 0, "conf_target" }, { "estimaterawfee", 0, "conf_target" }, { "estimaterawfee", 1, "threshold" }, { "prioritisetransaction", 1, "dummy" }, From 19d63e8a939abb89385fc5758771351cbe650ffe Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 15 Sep 2017 00:07:45 -0400 Subject: [PATCH 063/196] Remove custom fee radio group Removes the extraneous custom fee radio group and its single radio button. The radio button is replaced with a label that has the radio button's text. Github-Pull: #11334 Rebased-From: e53fa4a1ca58ef46416c4a96542722601fb75c5a --- src/qt/forms/sendcoinsdialog.ui | 9 +-------- src/qt/sendcoinsdialog.cpp | 14 ++------------ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 1e2f2302b91f..a0e48334c1b5 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -846,19 +846,13 @@ - + 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. per kilobyte - - true - - - groupCustomFee - @@ -1285,6 +1279,5 @@ - diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 7732c7398818..96adae73daf6 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -114,10 +114,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p settings.setValue("nFeeRadio", 1); // custom if (!settings.contains("nFeeRadio")) settings.setValue("nFeeRadio", 0); // recommended - if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility - settings.setValue("nCustomFeeRadio", 1); // total at least - if (!settings.contains("nCustomFeeRadio")) - settings.setValue("nCustomFeeRadio", 0); // per kilobyte if (!settings.contains("nSmartFeeSliderPosition")) settings.setValue("nSmartFeeSliderPosition", 0); if (!settings.contains("nTransactionFee")) @@ -127,8 +123,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p ui->groupFee->setId(ui->radioSmartFee, 0); ui->groupFee->setId(ui->radioCustomFee, 1); ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true); - ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0); - ui->groupCustomFee->button(0)->setChecked(true); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); @@ -178,7 +172,6 @@ void SendCoinsDialog::setModel(WalletModel *_model) connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls())); connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); @@ -214,7 +207,6 @@ SendCoinsDialog::~SendCoinsDialog() QSettings settings; settings.setValue("fFeeSectionMinimized", fFeeMinimized); settings.setValue("nFeeRadio", ui->groupFee->checkedId()); - settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId()); settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex())); settings.setValue("nTransactionFee", (qint64)ui->customFee->value()); settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked()); @@ -609,7 +601,6 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked() void SendCoinsDialog::setMinimumFee() { - ui->radioCustomPerKilobyte->setChecked(true); ui->customFee->setValue(CWallet::GetRequiredFee(1000)); } @@ -622,7 +613,7 @@ void SendCoinsDialog::updateFeeSectionControls() ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked()); ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked()); ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked()); - ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); + ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); } @@ -634,8 +625,7 @@ void SendCoinsDialog::updateFeeMinimizedLabel() if (ui->radioSmartFee->isChecked()) ui->labelFeeMinimized->setText(ui->labelSmartFee->text()); else { - ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + - ((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : "")); + ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kB"); } } From 6642558078deaae2bdf1d85ed2156eb23ba004b0 Mon Sep 17 00:00:00 2001 From: Lucas Betschart Date: Sun, 6 Aug 2017 22:55:14 +0200 Subject: [PATCH 064/196] [Qt] Add delay before filtering transactions Fixes 3141 Github-Pull: #11015 Rebased-From: 7b137acedd5e2ff3fe5395a927c546a528b0cac6 --- src/qt/transactionview.cpp | 27 ++++++++++++++++++++------- src/qt/transactionview.h | 4 ++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 53c38da9db3d..39dfdb587c2a 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,17 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this)); hlayout->addWidget(amountWidget); + // Delay before filtering transactions in ms + static const int input_filter_delay = 200; + + QTimer* amount_typing_delay = new QTimer(this); + amount_typing_delay->setSingleShot(true); + amount_typing_delay->setInterval(input_filter_delay); + + QTimer* prefix_typing_delay = new QTimer(this); + prefix_typing_delay->setSingleShot(true); + prefix_typing_delay->setInterval(input_filter_delay); + QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setContentsMargins(0,0,0,0); vlayout->setSpacing(0); @@ -173,8 +185,10 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int))); connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int))); connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int))); - connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString))); - connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString))); + connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start())); + connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount())); + connect(addressWidget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start())); + connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedPrefix())); connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex))); connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); @@ -312,20 +326,19 @@ void TransactionView::chooseWatchonly(int idx) (TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt()); } -void TransactionView::changedPrefix(const QString &prefix) +void TransactionView::changedPrefix() { if(!transactionProxyModel) return; - transactionProxyModel->setAddressPrefix(prefix); + transactionProxyModel->setAddressPrefix(addressWidget->text()); } -void TransactionView::changedAmount(const QString &amount) +void TransactionView::changedAmount() { if(!transactionProxyModel) return; CAmount amount_parsed = 0; - if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed)) - { + if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) { transactionProxyModel->setMinAmount(amount_parsed); } else diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 52e57cae4cf9..5b4cfd4a88d3 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -112,8 +112,8 @@ public Q_SLOTS: void chooseDate(int idx); void chooseType(int idx); void chooseWatchonly(int idx); - void changedPrefix(const QString &prefix); - void changedAmount(const QString &amount); + void changedAmount(); + void changedPrefix(); void exportClicked(); void focusTransaction(const QModelIndex&); From 8d13b4298c1ca83db0a65c8c8a93bd3be9135754 Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Fri, 15 Sep 2017 16:38:42 +1200 Subject: [PATCH 065/196] Replace save|restoreWindowGeometry with Qt functions Github-Pull: #11335 Rebased-From: 13baf7217bf8394ae02efc376208ae86eac4d0f6 --- src/qt/bitcoingui.cpp | 9 +++++++-- src/qt/guiutil.cpp | 26 -------------------------- src/qt/guiutil.h | 5 ----- src/qt/rpcconsole.cpp | 11 ++++++++--- 4 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index e3970298e61d..56373563b81b 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -123,7 +123,11 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * spinnerFrame(0), platformStyle(_platformStyle) { - GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this); + QSettings settings; + if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) { + // Restore failed (perhaps missing setting), center the window + move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); + } QString windowTitle = tr(PACKAGE_NAME) + " - "; #ifdef ENABLE_WALLET @@ -261,7 +265,8 @@ BitcoinGUI::~BitcoinGUI() // Unsubscribe from notifications from core unsubscribeFromCoreSignals(); - GUIUtil::saveWindowGeometry("nWindow", this); + QSettings settings; + settings.setValue("MainWindowGeometry", saveGeometry()); if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) trayIcon->hide(); #ifdef Q_OS_MAC diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index f3c5daebec9a..69c3e0686963 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -842,32 +842,6 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; } #endif -void saveWindowGeometry(const QString& strSetting, QWidget *parent) -{ - QSettings settings; - settings.setValue(strSetting + "Pos", parent->pos()); - settings.setValue(strSetting + "Size", parent->size()); -} - -void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent) -{ - QSettings settings; - QPoint pos = settings.value(strSetting + "Pos").toPoint(); - QSize size = settings.value(strSetting + "Size", defaultSize).toSize(); - - parent->resize(size); - parent->move(pos); - - if ((!pos.x() && !pos.y()) || (QApplication::desktop()->screenNumber(parent) == -1)) - { - QRect screen = QApplication::desktop()->screenGeometry(); - QPoint defaultPos((screen.width() - defaultSize.width()) / 2, - (screen.height() - defaultSize.height()) / 2); - parent->resize(defaultSize); - parent->move(defaultPos); - } -} - void setClipboard(const QString& str) { QApplication::clipboard()->setText(str, QClipboard::Clipboard); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index d6aa8c4ea656..d10818d0c88e 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -179,11 +179,6 @@ namespace GUIUtil bool GetStartOnSystemStartup(); bool SetStartOnSystemStartup(bool fAutoStart); - /** Save window size and position */ - void saveWindowGeometry(const QString& strSetting, QWidget *parent); - /** Restore window size and position */ - void restoreWindowGeometry(const QString& strSetting, const QSize &defaultSizeIn, QWidget *parent); - /* Convert QString to OS specific boost path through UTF-8 */ fs::path qstringToBoostPath(const QString &path); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 3590a98efac1..d895fc16630c 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -28,6 +28,7 @@ #include #endif +#include #include #include #include @@ -428,7 +429,11 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) : consoleFontSize(0) { ui->setupUi(this); - GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this); + QSettings settings; + if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) { + // Restore failed (perhaps missing setting), center the window + move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); + } ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME))); @@ -466,14 +471,14 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) : ui->detailWidget->hide(); ui->peerHeading->setText(tr("Select a peer to view detailed information.")); - QSettings settings; consoleFontSize = settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize()).toInt(); clear(); } RPCConsole::~RPCConsole() { - GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); + QSettings settings; + settings.setValue("RPCConsoleWindowGeometry", saveGeometry()); RPCUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete ui; From 75997c3b35db39031a222e2d63da83e67cc9397c Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 20 Sep 2017 20:19:14 -0400 Subject: [PATCH 066/196] Disallow uncompressed pubkeys in bitcoin-tx [multisig] output adds Github-Pull: #11377 Rebased-From: 28d4542a0ac77a30a242d0568e580a5b437f53fa --- Makefile.am | 1 + src/bitcoin-tx.cpp | 8 ++++++++ test/util/data/bitcoin-util-test.json | 18 ++++++++++++++++++ test/util/data/txcreatemultisig5.json | 26 ++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 test/util/data/txcreatemultisig5.json diff --git a/Makefile.am b/Makefile.am index 8216b7d60811..3b62a106031c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -249,6 +249,7 @@ EXTRA_DIST += \ test/util/data/txcreatemultisig3.json \ test/util/data/txcreatemultisig4.hex \ test/util/data/txcreatemultisig4.json \ + test/util/data/txcreatemultisig5.json \ test/util/data/txcreateoutpubkey1.hex \ test/util/data/txcreateoutpubkey1.json \ test/util/data/txcreateoutpubkey2.hex \ diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index cff90d13affc..0f2c19bd5df7 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -310,6 +310,9 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str } if (bSegWit) { + if (!pubkey.IsCompressed()) { + throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); + } // Call GetScriptForWitness() to build a P2WSH scriptPubKey scriptPubKey = GetScriptForWitness(scriptPubKey); } @@ -377,6 +380,11 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s CScript scriptPubKey = GetScriptForMultisig(required, pubkeys); if (bSegWit) { + for (CPubKey& pubkey : pubkeys) { + if (!pubkey.IsCompressed()) { + throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); + } + } // Call GetScriptForWitness() to build a P2WSH scriptPubKey scriptPubKey = GetScriptForWitness(scriptPubKey); } diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index b61a4f7f8f94..89b28bba6ced 100644 --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -261,6 +261,13 @@ "output_cmp": "txcreateoutpubkey3.json", "description": "Creates a new transaction with a single pay-to-pub-key output, wrapped in P2SH (output as json)" }, + { "exec": "./bitcoin-tx", + "args": + ["-json", "-create", "outpubkey=0:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:WS", "nversion=1"], + "return_code": 1, + "error_txt": "error: Uncompressed pubkeys are not useable for SegWit outputs", + "description": "Creates a new transaction with a single pay-to-pub-key output, wrapped in P2SH (output as json)" + }, { "exec": "./bitcoin-tx", "args": ["-create", @@ -388,5 +395,16 @@ "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:WS", "nversion=1"], "output_cmp": "txcreatemultisig4.json", "description": "Creates a new transaction with a single 2-of-3 multisig in a P2WSH output, wrapped in P2SH (output in json)" + }, + { "exec": "./bitcoin-tx", + "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:S"], + "output_cmp": "txcreatemultisig5.json", + "description": "Uncompressed pubkeys should work just fine for non-witness outputs" + }, + { "exec": "./bitcoin-tx", + "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:WS"], + "return_code": 1, + "error_txt": "error: Uncompressed pubkeys are not useable for SegWit outputs", + "description": "Ensure adding witness outputs with uncompressed pubkeys fails" } ] diff --git a/test/util/data/txcreatemultisig5.json b/test/util/data/txcreatemultisig5.json new file mode 100644 index 000000000000..20e9bb077bbf --- /dev/null +++ b/test/util/data/txcreatemultisig5.json @@ -0,0 +1,26 @@ +{ + "txid": "813cf75e1f08debd242ef7c8192b7d478fb651355209369499a0de779ba7eb2f", + "hash": "813cf75e1f08debd242ef7c8192b7d478fb651355209369499a0de779ba7eb2f", + "version": 2, + "size": 42, + "vsize": 42, + "locktime": 0, + "vin": [ + ], + "vout": [ + { + "value": 1.00000000, + "n": 0, + "scriptPubKey": { + "asm": "OP_HASH160 a4051c02398868af83f28f083208fae99a769263 OP_EQUAL", + "hex": "a914a4051c02398868af83f28f083208fae99a76926387", + "reqSigs": 1, + "type": "scripthash", + "addresses": [ + "3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos" + ] + } + } + ], + "hex": "02000000000100e1f5050000000017a914a4051c02398868af83f28f083208fae99a7692638700000000" +} From 8b61aee69026b03dfd5ebdb29c8d27a2b87462d1 Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Wed, 13 Sep 2017 07:24:42 +0000 Subject: [PATCH 067/196] Put back inadvertently removed copyright notices In an abundance of caution this restores "Bitcoin Developers" to the COPYING file in case there were contributors before that point in time that would object to the current label. It's harmless and more pedantically correct. [Change extracted from the Bitcoin-abc repository, commit message by gmaxwell] Signed-off-by: Gregory Maxwell Github-Pull: #11318 Rebased-From: d552ed678c2632bafeab695c639f5fe185dc9853 --- COPYING | 1 + 1 file changed, 1 insertion(+) diff --git a/COPYING b/COPYING index c6203c0f76d2..45d51c3c7851 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,7 @@ The MIT License (MIT) Copyright (c) 2009-2017 The Bitcoin Core developers +Copyright (c) 2009-2017 Bitcoin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 62d18cdb893fea92680a6f382bb8b3e8ca157bcf Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 3 Oct 2017 18:09:04 +0200 Subject: [PATCH 068/196] doc: Prepare release notes for 0.15.1 --- doc/release-notes.md | 28 +- doc/release-notes/release-notes-0.15.0.1.md | 87 ++ doc/release-notes/release-notes-0.15.0.md | 878 ++++++++++++++++++++ 3 files changed, 975 insertions(+), 18 deletions(-) create mode 100644 doc/release-notes/release-notes-0.15.0.1.md create mode 100644 doc/release-notes/release-notes-0.15.0.md diff --git a/doc/release-notes.md b/doc/release-notes.md index 32bf667734fd..ef8de316a505 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,8 +1,12 @@ -Bitcoin Core version *0.15.0.1* is now available from: +(note: this is a temporary file, to be added-to by anybody, and moved to +release-notes at release time) - +Bitcoin Core version *0.15.1* is now available from: -This is a minor bug fix for 0.15.0. + + +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: @@ -56,28 +60,16 @@ frequently tested on them. Notable changes =============== -GUI startup crash issue -------------------------- - -After upgrade to 0.15.0, some clients would crash at startup because a custom -fee setting was configured that no longer exists in the GUI. This is a minimal -patch to avoid this issue from occuring. - -0.15.0.1 Change log -==================== -- #11332 `46c8d23` Fix possible crash with invalid nCustomFeeRadio in QSettings (achow101, TheBlueMatt) -Also the manpages were updated, as this was forgotten for 0.15.0. +0.15.1 Change log +================= Credits ======= Thanks to everyone who directly contributed to this release: -- Andrew Chow -- Matt Corallo -- Jonas Schnelli -- Wladimir J. van der Laan +(fill this in) 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.15.0.1.md b/doc/release-notes/release-notes-0.15.0.1.md new file mode 100644 index 000000000000..53ab02cbb024 --- /dev/null +++ b/doc/release-notes/release-notes-0.15.0.1.md @@ -0,0 +1,87 @@ +Bitcoin Core version *0.15.0.1* is now available from: + + + +and + + + +This is a minor bug fix for 0.15.0. + +Please report bugs using the issue tracker at GitHub: + + + +To receive security and update notifications, please subscribe to: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0 or higher, your chainstate database will +be converted to a new format, which will take anywhere from a few minutes to +half an hour, depending on the speed of your machine. + +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee +estimates to be discarded. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notable changes +=============== + +GUI startup crash issue +------------------------- + +After upgrade to 0.15.0, some clients would crash at startup because a custom +fee setting was configured that no longer exists in the GUI. This is a minimal +patch to avoid this issue from occuring. + +0.15.0.1 Change log +==================== + +- #11332 `46c8d23` Fix possible crash with invalid nCustomFeeRadio in QSettings (achow101, TheBlueMatt) + +Also the manpages were updated, as this was forgotten for 0.15.0. + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Andrew Chow +- Matt Corallo +- Jonas Schnelli +- Wladimir J. van der Laan + +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.15.0.md b/doc/release-notes/release-notes-0.15.0.md new file mode 100644 index 000000000000..29816cacf730 --- /dev/null +++ b/doc/release-notes/release-notes-0.15.0.md @@ -0,0 +1,878 @@ +Bitcoin Core version *0.15.0* is now available from: + + + +This is a new major version release, including new features, 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: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0, your chainstate database will be converted to a +new format, which will take anywhere from a few minutes to half an hour, +depending on the speed of your machine. + +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee +estimates to be discarded. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notes for 0.15.0 +================ + +Current SegWit support +---------------------- + +Version 0.15.0 supports adding a segregated witness address via the `addwitnessaddress` RPC, but +please note that this is a testing/expert RPC, which does not guarantee recovery from backup. Only use +this RPC if you know what you are doing. More complete wallet support for segregated witness is coming +in a next version. + +Rescanning with encrypted wallets +--------------------------------- + +As in previous versions, when using an encrypted HD wallet, the keypool cannot be topped up without unlocking +the wallet. This means that currently, in order to recover from a backup of an encrypted HD wallet, the user +must unlock the wallet with a really long timeout and manually trigger a rescan, otherwise they risk missing +some keys when auto-topup cannot run. Unfortunately there is no `rescan` RPC in this version, that will be +included in a future version, so for now a rescan can be triggered using one of the `import*` commands, using +a dummy address generated by another (trusted) wallet. + +Notable changes +=============== + +Performance Improvements +------------------------ + +Version 0.15 contains a number of significant performance improvements, which make +Initial Block Download, startup, transaction and block validation much faster: + +- The chainstate database (which is used for tracking UTXOs) has been changed + from a per-transaction model to a per-output model (See [PR 10195](https://github.com/bitcoin/bitcoin/pull/10195)). Advantages of this model + are that it: + - avoids the CPU overhead of deserializing and serializing the unused outputs; + - has more predictable memory usage; + - uses simpler code; + - is adaptable to various future cache flushing strategies. + + As a result, validating the blockchain during Initial Block Download (IBD) and reindex + is ~30-40% faster, uses 10-20% less memory, and flushes to disk far less frequently. + The only downside is that the on-disk database is 15% larger. During the conversion from the previous format + a few extra gigabytes may be used. +- Earlier versions experienced a spike in memory usage while flushing UTXO updates to disk. + As a result, only half of the available memory was actually used as cache, and the other half was + reserved to accommodate flushing. This is no longer the case (See [PR 10148](https://github.com/bitcoin/bitcoin/pull/10148)), and the entirety of + the available cache (see `-dbcache`) is now actually used as cache. This reduces the flushing + frequency by a factor 2 or more. +- In previous versions, signature validation for transactions has been cached when the + transaction is accepted to the mempool. Version 0.15 extends this to cache the entire script + validity (See [PR 10192](https://github.com/bitcoin/bitcoin/pull/10192)). This means that if a transaction in a block has already been accepted to the + mempool, the scriptSig does not need to be re-evaluated. Empirical tests show that + this results in new block validation being 40-50% faster. +- LevelDB has been upgraded to version 1.20 (See [PR 10544](https://github.com/bitcoin/bitcoin/pull/10544)). This version contains hardware acceleration for CRC + on architectures supporting SSE 4.2. As a result, synchronization and block validation are now faster. +- SHA256 hashing has been optimized for architectures supporting SSE 4 (See [PR 10821](https://github.com/bitcoin/bitcoin/pull/10821)). SHA256 is around + 50% faster on supported hardware, which results in around 5% faster IBD and block + validation. In version 0.15, SHA256 hardware optimization is disabled in release builds by + default, but can be enabled by using `--enable-experimental-asm` when building. +- Refill of the keypool no longer flushes the wallet between each key which resulted in a ~20x speedup in creating a new wallet. Part of this speedup was used to increase the default keypool to 1000 keys to make recovery more robust. (See [PR 10831](https://github.com/bitcoin/bitcoin/pull/10831)). + +Fee Estimation Improvements +--------------------------- + +Fee estimation has been significantly improved in version 0.15, with more accurate fee estimates used by the wallet and a wider range of options for advanced users of the `estimatesmartfee` and `estimaterawfee` RPCs (See [PR 10199](https://github.com/bitcoin/bitcoin/pull/10199)). + +### Changes to internal logic and wallet behavior + +- Internally, estimates are now tracked on 3 different time horizons. This allows for longer targets and means estimates adjust more quickly to changes in conditions. +- Estimates can now be *conservative* or *economical*. *Conservative* estimates use longer time horizons to produce an estimate which is less susceptible to rapid changes in fee conditions. *Economical* estimates use shorter time horizons and will be more affected by short-term changes in fee conditions. Economical estimates may be considerably lower during periods of low transaction activity (for example over weekends), but may result in transactions being unconfirmed if prevailing fees increase rapidly. +- By default, the wallet will use conservative fee estimates to increase the reliability of transactions being confirmed within the desired target. For transactions that are marked as replaceable, the wallet will use an economical estimate by default, since the fee can be 'bumped' if the fee conditions change rapidly (See [PR 10589](https://github.com/bitcoin/bitcoin/pull/10589)). +- Estimates can now be made for confirmation targets up to 1008 blocks (one week). +- More data on historical fee rates is stored, leading to more precise fee estimates. +- Transactions which leave the mempool due to eviction or other non-confirmed reasons are now taken into account by the fee estimation logic, leading to more accurate fee estimates. +- The fee estimation logic will make sure enough data has been gathered to return a meaningful estimate. If there is insufficient data, a fallback default fee is used. + +### Changes to fee estimate RPCs + +- The `estimatefee` RPC is now deprecated in favor of using only `estimatesmartfee` (which is the implementation used by the GUI) +- The `estimatesmartfee` RPC interface has been changed (See [PR 10707](https://github.com/bitcoin/bitcoin/pull/10707)): + - The `nblocks` argument has been renamed to `conf_target` (to be consistent with other RPC methods). + - An `estimate_mode` argument has been added. This argument takes one of the following strings: `CONSERVATIVE`, `ECONOMICAL` or `UNSET` (which defaults to `CONSERVATIVE`). + - The RPC return object now contains an `errors` member, which returns errors encountered during processing. + - If Bitcoin Core has not been running for long enough and has not seen enough blocks or transactions to produce an accurate fee estimation, an error will be returned (previously a value of -1 was used to indicate an error, which could be confused for a feerate). +- A new `estimaterawfee` RPC is added to provide raw fee data. External clients can query and use this data in their own fee estimation logic. + +Multi-wallet support +-------------------- + +Bitcoin Core now supports loading multiple, separate wallets (See [PR 8694](https://github.com/bitcoin/bitcoin/pull/8694), [PR 10849](https://github.com/bitcoin/bitcoin/pull/10849)). The wallets are completely separated, with individual balances, keys and received transactions. + +Multi-wallet is enabled by using more than one `-wallet` argument when starting Bitcoin, either on the command line or in the Bitcoin config file. + +**In Bitcoin-Qt, only the first wallet will be displayed and accessible for creating and signing transactions.** GUI selectable multiple wallets will be supported in a future version. However, even in 0.15 other loaded wallets will remain synchronized to the node's current tip in the background. This can be useful if running a pruned node, since loading a wallet where the most recent sync is beyond the pruned height results in having to download and revalidate the whole blockchain. Continuing to synchronize all wallets in the background avoids this problem. + +Bitcoin Core 0.15.0 contains the following changes to the RPC interface and `bitcoin-cli` for multi-wallet: + +* When running Bitcoin Core with a single wallet, there are **no** changes to the RPC interface or `bitcoin-cli`. All RPC calls and `bitcoin-cli` commands continue to work as before. +* When running Bitcoin Core with multi-wallet, all *node-level* RPC methods continue to work as before. HTTP RPC requests should be send to the normal `:/` endpoint, and `bitcoin-cli` commands should be run as before. A *node-level* RPC method is any method which does not require access to the wallet. +* When running Bitcoin Core with multi-wallet, *wallet-level* RPC methods must specify the wallet for which they're intended in every request. HTTP RPC requests should be send to the `:/wallet//` endpoint, for example `127.0.0.1:8332/wallet/wallet1.dat/`. `bitcoin-cli` commands should be run with a `-rpcwallet` option, for example `bitcoin-cli -rpcwallet=wallet1.dat getbalance`. +* A new *node-level* `listwallets` RPC method is added to display which wallets are currently loaded. The names returned by this method are the same as those used in the HTTP endpoint and for the `rpcwallet` argument. + +Note that while multi-wallet is now fully supported, the RPC multi-wallet interface should be considered unstable for version 0.15.0, and there may backwards-incompatible changes in future versions. + +Replace-by-fee control in the GUI +--------------------------------- + +Bitcoin Core has supported creating opt-in replace-by-fee (RBF) transactions +since version 0.12.0, and since version 0.14.0 has included a `bumpfee` RPC method to +replace unconfirmed opt-in RBF transactions with a new transaction that pays +a higher fee. + +In version 0.15, creating an opt-in RBF transaction and replacing the unconfirmed +transaction with a higher-fee transaction are both supported in the GUI (See [PR 9592](https://github.com/bitcoin/bitcoin/pull/9592)). + +Removal of Coin Age Priority +---------------------------- + +In previous versions of Bitcoin Core, a portion of each block could be reserved for transactions based on the age and value of UTXOs they spent. This concept (Coin Age Priority) is a policy choice by miners, and there are no consensus rules around the inclusion of Coin Age Priority transactions in blocks. In practice, only a few miners continue to use Coin Age Priority for transaction selection in blocks. Bitcoin Core 0.15 removes all remaining support for Coin Age Priority (See [PR 9602](https://github.com/bitcoin/bitcoin/pull/9602)). This has the following implications: + +- The concept of *free transactions* has been removed. High Coin Age Priority transactions would previously be allowed to be relayed even if they didn't attach a miner fee. This is no longer possible since there is no concept of Coin Age Priority. The `-limitfreerelay` and `-relaypriority` options which controlled relay of free transactions have therefore been removed. +- The `-sendfreetransactions` option has been removed, since almost all miners do not include transactions which do not attach a transaction fee. +- The `-blockprioritysize` option has been removed. +- The `estimatepriority` and `estimatesmartpriority` RPCs have been removed. +- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. +- The `prioritisetransaction` RPC no longer takes a `priority_delta` argument, which is replaced by a `dummy` argument for backwards compatibility with clients using positional arguments. The RPC is still used to change the apparent fee-rate of the transaction by using the `fee_delta` argument. +- `-minrelaytxfee` can now be set to 0. If `minrelaytxfee` is set, then fees smaller than `minrelaytxfee` (per kB) are rejected from relaying, mining and transaction creation. This defaults to 1000 satoshi/kB. +- The `-printpriority` option has been updated to only output the fee rate and hash of transactions included in a block by the mining code. + +Mempool Persistence Across Restarts +----------------------------------- + +Version 0.14 introduced mempool persistence across restarts (the mempool is saved to a `mempool.dat` file in the data directory prior to shutdown and restores the mempool when the node is restarted). Version 0.15 allows this feature to be switched on or off using the `-persistmempool` command-line option (See [PR 9966](https://github.com/bitcoin/bitcoin/pull/9966)). By default, the option is set to true, and the mempool is saved on shutdown and reloaded on startup. If set to false, the `mempool.dat` file will not be loaded on startup or saved on shutdown. + +New RPC methods +--------------- + +Version 0.15 introduces several new RPC methods: + +- `abortrescan` stops current wallet rescan, e.g. when triggered by an `importprivkey` call (See [PR 10208](https://github.com/bitcoin/bitcoin/pull/10208)). +- `combinerawtransaction` accepts a JSON array of raw transactions and combines them into a single raw transaction (See [PR 10571](https://github.com/bitcoin/bitcoin/pull/10571)). +- `estimaterawfee` returns raw fee data so that customized logic can be implemented to analyze the data and calculate estimates. See [Fee Estimation Improvements](#fee-estimation-improvements) for full details on changes to the fee estimation logic and interface. +- `getchaintxstats` returns statistics about the total number and rate of transactions + in the chain (See [PR 9733](https://github.com/bitcoin/bitcoin/pull/9733)). +- `listwallets` lists wallets which are currently loaded. See the *Multi-wallet* section + of these release notes for full details (See [Multi-wallet support](#multi-wallet-support)). +- `uptime` returns the total runtime of the `bitcoind` server since its last start (See [PR 10400](https://github.com/bitcoin/bitcoin/pull/10400)). + +Low-level RPC changes +--------------------- + +- When using Bitcoin Core in multi-wallet mode, RPC requests for wallet methods must specify + the wallet that they're intended for. See [Multi-wallet support](#multi-wallet-support) for full details. + +- The new database model no longer stores information about transaction + versions of unspent outputs (See [Performance improvements](#performance-improvements)). This means that: + - The `gettxout` RPC no longer has a `version` field in the response. + - The `gettxoutsetinfo` RPC reports `hash_serialized_2` instead of `hash_serialized`, + which does not commit to the transaction versions of unspent outputs, but does + commit to the height and coinbase information. + - The `getutxos` REST path no longer reports the `txvers` field in JSON format, + and always reports 0 for transaction versions in the binary format + +- The `estimatefee` RPC is deprecated. Clients should switch to using the `estimatesmartfee` RPC, which returns better fee estimates. See [Fee Estimation Improvements](#fee-estimation-improvements) for full details on changes to the fee estimation logic and interface. + +- The `gettxoutsetinfo` response now contains `disk_size` and `bogosize` instead of + `bytes_serialized`. The first is a more accurate estimate of actual disk usage, but + is not deterministic. The second is unrelated to disk usage, but is a + database-independent metric of UTXO set size: it counts every UTXO entry as 50 + the + length of its scriptPubKey (See [PR 10426](https://github.com/bitcoin/bitcoin/pull/10426)). + +- `signrawtransaction` can no longer be used to combine multiple transactions into a single transaction. Instead, use the new `combinerawtransaction` RPC (See [PR 10571](https://github.com/bitcoin/bitcoin/pull/10571)). + +- `fundrawtransaction` no longer accepts a `reserveChangeKey` option. This option used to allow RPC users to fund a raw transaction using an key from the keypool for the change address without removing it from the available keys in the keypool. The key could then be re-used for a `getnewaddress` call, which could potentially result in confusing or dangerous behaviour (See [PR 10784](https://github.com/bitcoin/bitcoin/pull/10784)). + +- `estimatepriority` and `estimatesmartpriority` have been removed. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). + +- The `listunspent` RPC now takes a `query_options` argument (see [PR 8952](https://github.com/bitcoin/bitcoin/pull/8952)), which is a JSON object + containing one or more of the following members: + - `minimumAmount` - a number specifying the minimum value of each UTXO + - `maximumAmount` - a number specifying the maximum value of each UTXO + - `maximumCount` - a number specifying the minimum number of UTXOs + - `minimumSumAmount` - a number specifying the minimum sum value of all UTXOs + +- The `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry` and `getrawmempool` RPCs no longer return `startingpriority` and `currentpriority`. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). + +- The `dumpwallet` RPC now returns the full absolute path to the dumped wallet. It + used to return no value, even if successful (See [PR 9740](https://github.com/bitcoin/bitcoin/pull/9740)). + +- In the `getpeerinfo` RPC, the return object for each peer now returns an `addrbind` member, which contains the ip address and port of the connection to the peer. This is in addition to the `addrlocal` member which contains the ip address and port of the local node as reported by the peer (See [PR 10478](https://github.com/bitcoin/bitcoin/pull/10478)). + +- The `disconnectnode` RPC can now disconnect a node specified by node ID (as well as by IP address/port). To disconnect a node based on node ID, call the RPC with the new `nodeid` argument (See [PR 10143](https://github.com/bitcoin/bitcoin/pull/10143)). + +- The second argument in `prioritisetransaction` has been renamed from `priority_delta` to `dummy` since Bitcoin Core no longer has a concept of coin age priority. The `dummy` argument has no functional effect, but is retained for positional argument compatibility. See [Removal of Coin Age Priority](#removal-of-coin-age-priority). + +- The `resendwallettransactions` RPC throws an error if the `-walletbroadcast` option is set to false (See [PR 10995](https://github.com/bitcoin/bitcoin/pull/10995)). + +- The second argument in the `submitblock` RPC argument has been renamed from `parameters` to `dummy`. This argument never had any effect, and the renaming is simply to communicate this fact to the user (See [PR 10191](https://github.com/bitcoin/bitcoin/pull/10191)) + (Clients should, however, use positional arguments for `submitblock` in order to be compatible with BIP 22.) + +- The `verbose` argument of `getblock` has been renamed to `verbosity` and now takes an integer from 0 to 2. Verbose level 0 is equivalent to `verbose=false`. Verbose level 1 is equivalent to `verbose=true`. Verbose level 2 will give the full transaction details of each transaction in the output as given by `getrawtransaction`. The old behavior of using the `verbose` named argument and a boolean value is still maintained for compatibility. + +- Error codes have been updated to be more accurate for the following error cases (See [PR 9853](https://github.com/bitcoin/bitcoin/pull/9853)): + - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for + example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND. + - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned + because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address + or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban + a node that has not previously been banned. Previously returned RPC_MISC_ERROR. + - `removeprunedfunds` now returns RPC_WALLET_ERROR if `bitcoind` is unable to remove + the transaction. Previously returned RPC_INTERNAL_ERROR. + - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not + exist in the wallet. Previously returned RPC_INTERNAL_ERROR. + - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change + address is provided. Previously returned RPC_INVALID_PARAMETER. + - `fundrawtransaction` now returns RPC_WALLET_ERROR if `bitcoind` is unable to create + the transaction. The error message provides further details. Previously returned + RPC_INTERNAL_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the wallet. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the mempool. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has + has been mined or conflicts with a mined transaction. Previously returned + RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not + BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already + been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains + inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change + outputs. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change + output. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the + fee. Previously returned RPC_MISC_ERROR. + +0.15.0 Change log +================= + +### RPC and other APIs +- #9485 `61a640e` ZMQ example using python3 and asyncio (mcelrath) +- #9894 `0496e15` remove 'label' filter for rpc command help (instagibbs) +- #9853 `02bd6e9` Fix error codes from various RPCs (jnewbery) +- #9842 `598ef9c` Fix RPC failure testing (continuation of #9707) (jnewbery) +- #10038 `d34995a` Add mallocinfo mode to `getmemoryinfo` RPC (laanwj) +- #9500 `3568b30` [Qt][RPC] Autocomplete commands for 'help' command in debug console (achow101) +- #10056 `e6156a0` [zmq] Call va_end() on va_start()ed args (kallewoof) +- #10086 `7438cea` Trivial: move rpcserialversion into RPC option group (jlopp) +- #10150 `350b224` [rpc] Add logging rpc (jnewbery) +- #10208 `393160c` [wallet] Rescan abortability (kallewoof) +- #10143 `a987def` [net] Allow disconnectnode RPC to be called with node id (jnewbery) +- #10281 `0e8499c` doc: Add RPC interface guidelines (laanwj) +- #9733 `d4732f3` Add getchaintxstats RPC (sipa) +- #10310 `f4b15e2` [doc] Add hint about getmempoolentry to getrawmempool help (kallewoof) +- #8704 `96c850c` [RPC] Transaction details in getblock (achow101) +- #8952 `9390845` Add query options to listunspent RPC call (pedrobranco) +- #10413 `08ac35a` Fix docs (there's no rpc command setpaytxfee) (RHavar) +- #8384 `e317c0d` Add witness data output to TxInError messages (instagibbs) +- #9571 `4677151` RPC: getblockchaininfo returns BIP signaling statistics (pinheadmz) +- #10450 `ef2d062` Fix bumpfee rpc "errors" return value (ryanofsky) +- #10475 `39039b1` [RPC] getmempoolinfo mempoolminfee is a BTC/KB feerate (instagibbs) +- #10478 `296928e` rpc: Add listen address to incoming connections in `getpeerinfo` (laanwj) +- #10403 `08d0390` Fix importmulti failure to return rescan errors (ryanofsky) +- #9740 `9fec4da` Add friendly output to dumpwallet (aideca) +- #10426 `16f6c98` Replace bytes_serialized with bogosize (sipa) +- #10252 `980deaf` RPC/Mining: Restore API compatibility for prioritisetransaction (luke-jr) +- #9672 `46311e7` Opt-into-RBF for RPC & bitcoin-tx (luke-jr) +- #10481 `9c248e3` Decodehextx scripts sanity check (achow101) +- #10488 `fa1f106` Note that the prioritizetransaction dummy value is deprecated, and has no meaning (TheBlueMatt) +- #9738 `c94b89e` gettxoutproof() should return consistent result (jnewbery) +- #10191 `00350bd` [trivial] Rename unused RPC arguments 'dummy' (jnewbery) +- #10627 `b62b4c8` fixed listunspent rpc convert parameter (tnakagawa) +- #10412 `bef02fb` Improve wallet rescan API (ryanofsky) +- #10400 `1680ee0` [RPC] Add an uptime command that displays the amount of time (in seconds) bitcoind has been running (rvelhote) +- #10683 `d81bec7` rpc: Move the `generate` RPC call to rpcwallet (laanwj) +- #10710 `30bc0f6` REST/RPC example update (Mirobit) +- #10747 `9edda0c` [rpc] fix verbose argument for getblock in bitcoin-cli (jnewbery) +- #10589 `104f5f2` More economical fee estimates for RBF and RPC options to control (morcos) +- #10543 `b27b004` Change API to estimaterawfee (morcos) +- #10807 `afd2fca` getbalance example covers at least 6 confirms (instagibbs) +- #10707 `75b5643` Better API for estimatesmartfee RPC (morcos) +- #10784 `9e8d6a3` Do not allow users to get keys from keypool without reserving them (TheBlueMatt) +- #10857 `d445a2c` [RPC] Add a deprecation warning to getinfo's output (achow101) +- #10571 `adf170d` [RPC]Move transaction combining from signrawtransaction to new RPC (achow101) +- #10783 `041dad9` [RPC] Various rpc argument fixes (instagibbs) +- #9622 `6ef3c7e` [rpc] listsinceblock should include lost transactions when parameter is a reorg'd block (kallewoof) +- #10799 `8537187` Prevent user from specifying conflicting parameters to fundrawtx (TheBlueMatt) +- #10931 `0b11a07` Fix misleading "Method not found" multiwallet errors (ryanofsky) +- #10788 `f66c596` [RPC] Fix addwitnessaddress by replacing ismine with producesignature (achow101) +- #10999 `627c3c0` Fix amounts formatting in `decoderawtransaction` (laanwj) +- #11002 `4268426` [wallet] return correct error code from resendwallettransaction (jnewbery) +- #11029 `96a63a3` [RPC] trivial: gettxout no longer shows version of tx (FelixWeis) +- #11083 `6c2b008` Fix combinerawtransaction RPC help result section (jonasnick) +- #11027 `07164bb` [RPC] Only return hex field once in getrawtransaction (achow101) +- #10698 `5af6572` Be consistent in calling transactions "replaceable" for Opt-In RBF (TheBlueMatt) + +### Block and transaction handling +- #9801 `a8c5751` Removed redundant parameter from mempool.PrioritiseTransaction (gubatron) +- #9819 `1efc99c` Remove harmless read of unusued priority estimates (morcos) +- #9822 `b7547fa` Remove block file location upgrade code (benma) +- #9602 `30ff3a2` Remove coin age priority and free transactions - implementation (morcos) +- #9548 `47510ad` Remove min reasonable fee (morcos) +- #10249 `c73af54` Switch CCoinsMap from boost to std unordered_map (sipa) +- #9966 `2a183de` Control mempool persistence using a command line parameter (jnewbery) +- #10199 `318ea50` Better fee estimates (morcos) +- #10196 `bee3529` Bugfix: PrioritiseTransaction updates the mempool tx counter (sdaftuar) +- #10195 `1088b02` Switch chainstate db and cache to per-txout model (sipa) +- #10284 `c2ab38b` Always log debug information for fee calculation in CreateTransaction (morcos) +- #10503 `efbcf2b` Use REJECT_DUPLICATE for already known and conflicted txn (sipa) +- #10537 `b3eb0d6` Few Minor per-utxo assert-semantics re-adds and tweak (TheBlueMatt) +- #10626 `8c841a3` doc: Remove outdated minrelaytxfee comment (MarcoFalke) +- #10559 `234ffc6` Change semantics of HaveCoinInCache to match HaveCoin (morcos) +- #10581 `7878353` Simplify return values of GetCoin/HaveCoin(InCache) (sipa) +- #10684 `a381f6a` Remove no longer used mempool.exists(outpoint) (morcos) +- #10148 `d4e551a` Use non-atomic flushing with block replay (sipa) +- #10685 `30c2130` Clarify CCoinsViewMemPool documentation (TheBlueMatt) +- #10558 `90a002e` Address nits from per-utxo change (morcos) +- #10706 `6859ad2` Improve wallet fee logic and fix GUI bugs (morcos) +- #10526 `754aa02` Force on-the-fly compaction during pertxout upgrade (sipa) +- #10985 `d896d5c` Add undocumented -forcecompactdb to force LevelDB compactions (sipa) +- #10292 `e4bbd3d` Improved efficiency in COutPoint constructors (mm-s) +- #10290 `8d6d43e` Add -stopatheight for benchmarking (sipa) + +### P2P protocol and network code +- #9726 `7639d38` netbase: Do not print an error on connection timeouts through proxy (laanwj) +- #9805 `5b583ef` Add seed.btc.petertodd.org to mainnet DNS seeds (petertodd) +- #9861 `22f609f` Trivial: Debug log ambiguity fix for peer addrs (keystrike) +- #9774 `90cb2a2` Enable host lookups for -proxy and -onion parameters (jmcorgan) +- #9558 `7b585cf` Clarify assumptions made about when BlockCheck is called (TheBlueMatt) +- #10135 `e19586a` [p2p] Send the correct error code in reject messages (jnewbery) +- #9665 `eab00d9` Use cached [compact] blocks to respond to getdata messages (TheBlueMatt) +- #10215 `a077a90` Check interruptNet during dnsseed lookups (TheBlueMatt) +- #10234 `faf2dea` [net] listbanned RPC and QT should show correct banned subnets (jnewbery) +- #10134 `314ebdf` [qa] Fixes segwit block relay test after inv-direct-fetch was disabled (sdaftuar) +- #10351 `3f57c55` removed unused code in INV message (Greg-Griffith) +- #10061 `ae78609` [net] Added SetSocketNoDelay() utility function (tjps) +- #10408 `28c6e8d` Net: Improvements to Tor control port parser (str4d) +- #10460 `5c63d66` Broadcast address every day, not 9 hours (sipa) +- #10471 `400fdd0` Denote functions CNode::GetRecvVersion() and CNode::GetRefCount() as const (pavlosantoniou) +- #10345 `67700b3` [P2P] Timeout for headers sync (sdaftuar) +- #10564 `8d9f45e` Return early in IsBanned (gmaxwell) +- #10587 `de8db47` Net: Fix resource leak in ReadBinaryFile(...) (practicalswift) +- #9549 `b33ca14` [net] Avoid possibility of NULL pointer dereference in MarkBlockAsInFlight(...) (practicalswift) +- #10446 `2772dc9` net: avoid extra dns query per seed (theuni) +- #10824 `9dd6a2b` Avoid unnecessary work in SetNetworkActive (promag) +- #10948 `df3a6f4` p2p: Hardcoded seeds update pre-0.15 branch (laanwj) +- #10977 `02f4c4a` [net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest&) (practicalswift) +- #10982 `c8b62c7` Disconnect network service bits 6 and 8 until Aug 1, 2018 (TheBlueMatt) +- #11012 `0e5cff6` Make sure to clean up mapBlockSource if we've already seen the block (theuni) + +### Validation +- #9725 `67023e9` CValidationInterface Cleanups (TheBlueMatt) +- #10178 `2584925` Remove CValidationInterface::UpdatedTransaction (TheBlueMatt) +- #10201 `a6548a4` pass Consensus::Params& to functions in validation.cpp and make them static (mariodian) +- #10297 `431a548` Simplify DisconnectBlock arguments/return value (sipa) +- #10464 `f94b7d5` Introduce static DoWarning (simplify UpdateTip) (jtimon) +- #10569 `2e7d8f8` Fix stopatheight (achow101) +- #10192 `2935b46` Cache full script execution results in addition to signatures (TheBlueMatt) +- #10179 `21ed30a` Give CValidationInterface Support for calling notifications on the CScheduler Thread (TheBlueMatt) +- #10557 `66270a4` Make check to distinguish between orphan txs and old txs more efficient (morcos) +- #10775 `7c2400c` nCheckDepth chain height fix (romanornr) +- #10821 `16240f4` Add SSE4 optimized SHA256 (sipa) +- #10854 `04d395e` Avoid using sizes on non-fixed-width types to derive protocol constants (gmaxwell) +- #10945 `2a50b11` Update defaultAssumeValid according to release-process.md (gmaxwell) +- #10986 `2361208` Update chain transaction statistics (sipa) +- #11028 `6bdf4b3` Avoid masking of difficulty adjustment errors by checkpoints (sipa) +- #9533 `cb598cf` Allow non-power-of-2 signature cache sizes (sipa) +- #9208 `acd9957` Improve DisconnectTip performance (sdaftuar) +- #10618 `f90603a` Remove confusing MAX_BLOCK_BASE_SIZE (gmaxwell) +- #10758 `bd92424` Fix some chainstate-init-order bugs (TheBlueMatt) +- #10550 `b7296bc` Don't return stale data from CCoinsViewCache::Cursor() (ryanofsky) +- #10998 `2507fd5` Fix upgrade cancel warnings (TheBlueMatt) +- #9868 `cbdb473` Abstract out the command line options for block assembly (sipa) + +### Build system +- #9727 `5f0556d` Remove fallbacks for boost_filesystem < v3 (laanwj) +- #9788 `50a2265` gitian: bump descriptors for master (theuni) +- #9794 `7ca2f54` Minor update to qrencode package builder (mitchellcash) +- #9514 `2cc0df1` release: Windows signing script (theuni) +- #9921 `8b789d8` build: Probe MSG_DONTWAIT in the same way as MSG_NOSIGNAL (laanwj) +- #10011 `32d1b34` build: Fix typo s/HAVE_DONTWAIT/HAVE_MSG_DONTWAIT (laanwj) +- #9946 `90dd9e6` Fix build errors if spaces in path or parent directory (pinheadmz) +- #10136 `81da4c7` build: Disable Wshadow warning (laanwj) +- #10166 `64962ae` Ignore Doxyfile generated from Doxyfile.in template (paveljanik) +- #10239 `0416ea9` Make Boost use std::atomic internally (sipa) +- #10228 `27faa6c` build: regenerate bitcoin-config.h as necessary (theuni) +- #10273 `8979f45` [scripts] Minor improvements to `macdeployqtplus` script (chrisgavin) +- #10325 `a26280b` 0.15.0 Depends Updates (fanquake) +- #10328 `79aeff6` Update contrib/debian to latest Ubuntu PPA upload (TheBlueMatt) +- #7522 `d25449f` Bugfix: Only use git for build info if the repository is actually the right one (luke-jr) +- #10489 `e654d61` build: silence gcc7's implicit fallthrough warning (theuni) +- #10549 `ad1a13e` Avoid printing generic and duplicated "checking for QT" during ./configure (drizzt) +- #10628 `8465b68` [depends] expat 2.2.1 (fanquake) +- #10806 `db825d2` build: verify that the assembler can handle crc32 functions (theuni) +- #10766 `b4d03be` Building Environment: Set ARFLAGS to cr (ReneNyffenegger) +- #10803 `91edda8` Explicitly search for bdb5.3 (pstratem) +- #10855 `81560b0` random: only use getentropy on openbsd (theuni) +- #10508 `1caafa6` Run Qt wallet tests on travis (ryanofsky) +- #10851 `e222618` depends: fix fontconfig with newer glibc (theuni) +- #10971 `88b1e4b` build: fix missing sse42 in depends builds (theuni) +- #11097 `129b03f` gitian: quick hack to fix version string in releases (theuni) +- #10039 `919aaf6` Fix compile errors with Qt 5.3.2 and Boost 1.55.0 (ryanofsky) +- #10168 `7032021` Fix build warning from #error text (jnewbery) +- #10301 `318392c` Check if sys/random.h is required for getentropy (jameshilliard) + +### GUI +- #9724 `1a9fd5c` Qt/Intro: Add explanation of IBD process (luke-jr) +- #9834 `b00ba62` qt: clean up initialize/shutdown signals (benma) +- #9481 `ce01e62` [Qt] Show more significant warning if we fall back to the default fee (jonasschnelli) +- #9974 `b9f930b` Add basic Qt wallet test (ryanofsky) +- #9690 `a387d3a` Change 'Clear' button string to 'Reset' (da2x) +- #9592 `9c7b7cf` [Qt] Add checkbox in the GUI to opt-in to RBF when creating a transaction (ryanofsky) +- #10098 `2b477e6` Make qt wallet test compatible with qt4 (ryanofsky) +- #9890 `1fa4ae6` Add a button to open the config file in a text editor (ericshawlinux) +- #10156 `51833a1` Fix for issues with startup and multiple monitors on windows (AllanDoensen) +- #10177 `de01da7` Changed "Send" button default status from true to false (KibbledJiveElkZoo) +- #10221 `e96486c` Stop treating coinbase outputs differently in GUI: show them at 1conf (TheBlueMatt) +- #10231 `987a6c0` [Qt] Reduce a significant cs_main lock freeze (jonasschnelli) +- #10242 `f6f3b58` [qt] Don't call method on null WalletModel object (ryanofsky) +- #10093 `a3e756b` [Qt] Don't add arguments of sensitive command to console window (jonasschnelli) +- #10362 `95546c8` [GUI] Add OSX keystroke to RPCConsole info (spencerlievens) +- #9697 `962cd3f` [Qt] simple fee bumper with user verification (jonasschnelli) +- #10390 `e477516` [wallet] remove minimum total fee option (instagibbs) +- #10420 `4314544` Add Qt tests for wallet spends & bumpfee (ryanofsky) +- #10454 `c1c9a95` Fix broken q4 test build (ryanofsky) +- #10449 `64beb13` Overhaul Qt fee bumper (jonasschnelli) +- #10582 `7c72fb9` Pass in smart fee slider value to coin control dialog (morcos) +- #10673 `4c72cc3` [qt] Avoid potential null pointer dereference in TransactionView::exportClicked() (practicalswift) +- #10769 `8fdd23a` [Qt] replace fee slider with a Dropdown, extend conf. targets (jonasschnelli) +- #10870 `412b466` [Qt] Use wallet 0 in rpc console if running with multiple wallets (jonasschnelli) +- #10988 `a9dd111` qt: Increase BLOCK_CHAIN_SIZE constants (laanwj) +- #10644 `e292140` Slightly overhaul NSI pixmaps (jonasschnelli) +- #10660 `0c3542e` Allow to cancel the txdb upgrade via splashscreen keypress 'q' (jonasschnelli) + +### Wallet +- #9359 `f7ec7cf` Add test for CWalletTx::GetImmatureCredit() returning stale values (ryanofsky) +- #9576 `56ab672` [wallet] Remove redundant initialization (practicalswift) +- #9333 `fa625b0` Document CWalletTx::mapValue entries and remove erase of nonexistent "version" entry (ryanofsky) +- #9906 `72fb515` Disallow copy constructor CReserveKeys (instagibbs) +- #9369 `3178b2c` Factor out CWallet::nTimeSmart computation into a method (ryanofsky) +- #9830 `afcd7c0` Add safe flag to listunspent result (NicolasDorier) +- #9993 `c49355c` Initialize nRelockTime (pstratem) +- #9818 `3d857f3` Save watch only key timestamps when reimporting keys (ryanofsky) +- #9294 `f34cdcb` Use internal HD chain for change outputs (hd split) (jonasschnelli) +- #10164 `e183ea2` Wallet: reduce excess logic InMempool() (kewde) +- #10186 `c9ff4f8` Remove SYNC_TRANSACTION_NOT_IN_BLOCK magic number (jnewbery) +- #10226 `64c45aa` wallet: Use boost to more portably ensure -wallet specifies only a filename (luke-jr) +- #9827 `c91ca0a` Improve ScanForWalletTransactions return value (ryanofsky) +- #9951 `fa1ac28` Wallet database handling abstractions/simplifications (laanwj) +- #10265 `c29a0d4` [wallet] [moveonly] Check non-null pindex before potentially referencing (kallewoof) +- #10283 `a550f6e` Cleanup: reduce to one GetMinimumFee call signature (morcos) +- #10294 `e2b99b1` [Wallet] unset change position when there is no change (instagibbs) +- #10115 `d3dce0e` Avoid reading the old hd master key during wallet encryption (TheBlueMatt) +- #10341 `18c9deb` rpc/wallet: Workaround older UniValue which returns a std::string temporary for get_str (luke-jr) +- #10308 `94e5227` [wallet] Securely erase potentially sensitive keys/values (tjps) +- #10257 `ea1fd43` [test] Add test for getmemoryinfo (jimmysong) +- #10295 `ce8176d` [qt] Move some WalletModel functions into CWallet (ryanofsky) +- #10506 `7cc2c67` Fix bumpfee test after #10449 (ryanofsky) +- #10500 `098b01d` Avoid CWalletTx copies in GetAddressBalances and GetAddressGroupings (ryanofsky) +- #10455 `0747d33` Simplify feebumper minimum fee code slightly (ryanofsky) +- #10522 `2805d60` [wallet] Remove unused variables (practicalswift) +- #8694 `177433a` Basic multiwallet support (luke-jr) +- #10598 `7a74f88` Supress struct/class mismatch warnings introduced in #10284 (paveljanik) +- #9343 `209eef6` Don't create change at dust limit (morcos) +- #10744 `ed88e31` Use method name via __func__ macro (darksh1ne) +- #10712 `e8b9523` Add change output if necessary to reduce excess fee (morcos) +- #10816 `1c011ff` Properly forbid -salvagewallet and -zapwallettxes for multi wallet (morcos) +- #10235 `5cfdda2` Track keypool entries as internal vs external in memory (TheBlueMatt) +- #10330 `bf0a08b` [wallet] fix zapwallettxes interaction with persistent mempool (jnewbery) +- #10831 `0b01935` Batch flushing operations to the walletdb during top up and increase keypool size (gmaxwell) +- #10795 `7b6e8bc` No longer ever reuse keypool indexes (TheBlueMatt) +- #10849 `bde4f93` Multiwallet: simplest endpoint support (jonasschnelli) +- #10817 `9022aa3` Redefine Dust and add a discard_rate (morcos) +- #10883 `bf3b742` Rename -usewallet to -rpcwallet (morcos) +- #10604 `420238d` [wallet] [tests] Add listwallets RPC, include wallet name in `getwalletinfo` and add multiwallet test (jnewbery) +- #10885 `70888a3` Reject invalid wallets (promag) +- #10949 `af56397` Clarify help message for -discardfee (morcos) +- #10942 `2e857bb` Eliminate fee overpaying edge case when subtracting fee from recipients (morcos) +- #10995 `fa64636` Fix resendwallettransactions assert failure if -walletbroadcast=0 (TheBlueMatt) +- #11022 `653a46d` Basic keypool topup (jnewbery) +- #11081 `9fe1f6b` Add length check for CExtKey deserialization (jonasschnelli, guidovranken) +- #11044 `4ef8374` [wallet] Keypool topup cleanups (jnewbery) +- #11145 `e51bb71` Fix rounding bug in calculation of minimum change (morcos) +- #9605 `779f2f9` Use CScheduler for wallet flushing, remove ThreadFlushWalletDB (TheBlueMatt) +- #10108 `4e3efd4` ApproximateBestSubset should take inputs by reference, not value (RHavar) + +### Tests and QA +- #9744 `8efd1c8` Remove unused module from rpc-tests (34ro) +- #9657 `7ff4a53` Improve rpc-tests.py (jnewbery) +- #9766 `7146d96` Add --exclude option to rpc-tests.py (jnewbery) +- #9577 `d6064a8` Fix docstrings in qa tests (jnewbery) +- #9823 `a13a417` qa: Set correct path for binaries in rpc tests (MarcoFalke) +- #9847 `6206252` Extra test vector for BIP32 (sipa) +- #9350 `88c2ae3` [Trivial] Adding label for amount inside of tx_valid/tx_invalid.json (Christewart) +- #9888 `36afd4d` travis: Verify commits only for one target (MarcoFalke) +- #9904 `58861ad` test: Fail if InitBlockIndex fails (laanwj) +- #9828 `67c5cc1` Avoid -Wshadow warnings in wallet_tests (ryanofsky) +- #9832 `48c3429` [qa] assert_start_raises_init_error (NicolasDorier) +- #9739 `9d5fcbf` Fix BIP68 activation test (jnewbery) +- #9547 `d32581c` bench: Assert that division by zero is unreachable (practicalswift) +- #9843 `c78adbf` Fix segwit getblocktemplate test (jnewbery) +- #9929 `d5ce14e` tests: Delete unused function _rpchost_to_args (laanwj) +- #9555 `19be26a` [test] Avoid reading a potentially uninitialized variable in tx_invalid-test (transaction_tests.cpp) (practicalswift) +- #9945 `ac23a7c` Improve logging in bctest.py if there is a formatting mismatch (jnewbery) +- #9768 `8910b47` [qa] Add logging to test_framework.py (jnewbery) +- #9972 `21833f9` Fix extended rpc tests broken by #9768 (jnewbery) +- #9977 `857d1e1` QA: getblocktemplate_longpoll.py should always use >0 fee tx (sdaftuar) +- #9970 `3cc13ea` Improve readability of segwit.py, smartfees.py (sdaftuar) +- #9497 `2c781fb` CCheckQueue Unit Tests (JeremyRubin) +- #10024 `9225de2` [trivial] Use log.info() instead of print() in remaining functional test cases (jnewbery) +- #9956 `3192e52` Reorganise qa directory (jnewbery) +- #10017 `02d64bd` combine_logs.py - aggregates log files from multiple bitcoinds during functional tests (jnewbery) +- #10047 `dfef6b6` [tests] Remove unused variables and imports (practicalswift) +- #9701 `a230b05` Make bumpfee tests less fragile (ryanofsky) +- #10053 `ca20923` [test] Allow functional test cases to be skipped (jnewbery) +- #10052 `a0b1e57` [test] Run extended tests once daily in Travis (jnewbery) +- #10069 `1118493` [QA] Fix typo in fundrawtransaction test (NicolasDorier) +- #10083 `c044f03` [QA] Renaming rawTx into rawtx (NicolasDorier) +- #10073 `b1a4f27` Actually run assumevalid.py (jnewbery) +- #9780 `c412fd8` Suppress noisy output from qa tests in Travis (jnewbery) +- #10096 `79af9fb` Check that all test scripts in test/functional are being run (jnewbery) +- #10076 `5b029aa` [qa] combine_logs: Use ordered list for logfiles (MarcoFalke) +- #10107 `f2734c2` Remove unused variable. Remove accidental trailing semicolons in Python code (practicalswift) +- #10109 `8ac8041` Remove SingleNodeConnCB (jnewbery) +- #10114 `edc62c9` [tests] sync_with_ping should assert that ping hasn't timed out (jnewbery) +- #10128 `427d2fd` Speed Up CuckooCache tests (JeremyRubin) +- #10072 `12af74b` Remove sources of unreliablility in extended functional tests (jnewbery) +- #10077 `ebfd653` [qa] Add setnetworkactive smoke test (MarcoFalke) +- #10152 `080d7c7` [trivial] remove unused line in Travis config (jnewbery) +- #10159 `df1ca9e` [tests] color test results and sort alphabetically (jnewbery) +- #10124 `88799ea` [test] Suppress test logging spam (jnewbery) +- #10142 `ed09dd3` Run bitcoin_test-qt under minimal QPA platform (ryanofsky) +- #9949 `a27dbc5` [bench] Avoid function call arguments which are pointers to uninitialized values (practicalswift) +- #10187 `b44adf9` tests: Fix test_runner return value in case of skipped test (laanwj) +- #10197 `d86bb07` [tests] Functional test warnings (jnewbery) +- #10219 `9111df9` Tests: Order Python Tests Differently (jimmysong) +- #10229 `f3db4c6` Tests: Add test for getdifficulty (jimmysong) +- #10224 `2723bcd` [test] Add test for getaddednodeinfo (jimmysong) +- #10023 `c530c15` [tests] remove maxblocksinflight.py (functionality covered by other test) (jnewbery) +- #10097 `1b25b6d` Move zmq test skipping logic into individual test case (jnewbery) +- #10272 `54e2d87` [Tests] Prevent warning: variable 'x' is uninitialized (paveljanik) +- #10225 `e0a7e19` [test] Add aborttrescan tests (kallewoof) +- #10278 `8254a8a` [test] Add Unit Test for GetListenPort (jimmysong) +- #10280 `47535d7` [test] Unit test amount.h/amount.cpp (jimmysong) +- #10256 `80c3a73` [test] Add test for gettxout to wallet.py (jimmysong) +- #10264 `492d22f` [test] Add tests for getconnectioncount, getnettotals and ping (jimmysong) +- #10169 `8f3e384` [tests] Remove func test code duplication (jnewbery) +- #10198 `dc8fc0c` [tests] Remove is_network_split from functional test framework (jnewbery) +- #10255 `3c5e6c9` [test] Add test for listaddressgroupings (jimmysong) +- #10137 `75171f0` Remove unused import. Remove accidental trailing semicolons (practicalswift) +- #10307 `83073de` [tests] allow zmq test to be run in out-of-tree builds (jnewbery) +- #10344 `e927483` [tests] Fix abandonconflict.py intermittency (jnewbery) +- #10318 `170bc2c` [tests] fix wait_for_inv() (jnewbery) +- #10171 `fff72de` [tests] Add node methods to test framework (jnewbery) +- #10352 `23d78c4` test: Add elapsed time to RPC tracing (laanwj) +- #10342 `6a796b2` [tests] Improve mempool_persist test (jnewbery) +- #10287 `776ba23` [tests] Update Unit Test for addrman.h/addrman.cpp (jimmysong) +- #10365 `7ee5236` [tests] increase timeouts in sendheaders test (jnewbery) +- #10361 `f6241b3` qa: disablewallet: Check that wallet is really disabled (MarcoFalke) +- #10371 `4b766fc` [tests] Clean up addrman_tests.cpp (jimmysong) +- #10253 `87abe20` [test] Add test for getnetworkhashps (jimmysong) +- #10376 `8bd16ee` [tests] fix disconnect_ban intermittency (jnewbery) +- #10374 `5411997` qa: Warn when specified test is not found (MarcoFalke) +- #10405 `0542978` tests: Correct testcase in script_tests.json for large number OP_EQUAL (laanwj) +- #10429 `6b99daf` tests: fix spurious addrman test failure (theuni) +- #10433 `8e57256` [tests] improve tmpdir structure (jnewbery) +- #10415 `217b416` [tests] Speed up fuzzing by ~200x when using afl-fuzz (practicalswift) +- #10445 `b4b057a` Add test for empty chain and reorg consistency for gettxoutsetinfo (gmaxwell) +- #10423 `1aefc94` [tests] skipped tests should clean up after themselves (jnewbery) +- #10359 `329fc1d` [tests] functional tests should call BitcoinTestFramework start/stop node methods (jnewbery) +- #10514 `e103b3f` Bugfix: missing == 0 after randrange (sipa) +- #10515 `c871f32` [test] Add test for getchaintxstats (jimmysong) +- #10509 `bea5b00` Remove xvfb configuration from travis (ryanofsky) +- #10535 `30853e1` [qa] fundrawtx: Fix shutdown race (MarcoFalke) +- #9909 `300f8e7` tests: Add FindEarliestAtLeast test for edge cases (ryanofsky) +- #10331 `75e898c` Share config between util and functional tests (jnewbery) +- #10321 `e801084` Use FastRandomContext for all tests (sipa) +- #10524 `6c2d81f` [tests] Remove printf(...) (practicalswift) +- #10547 `71ab6e5` [tests] Use FastRandomContext instead of boost::random::{mt19937,uniform_int_distribution} (practicalswift) +- #10551 `6702617` [Tests] Wallet encryption functional tests (achow101) +- #10555 `643fa0b` [tests] various improvements to zmq_test.py (jnewbery) +- #10533 `d083bd9` [tests] Use cookie auth instead of rpcuser and rpcpassword (achow101) +- #10632 `c68a9a6` qa: Add stopatheight test (MarcoFalke) +- #10636 `4bc853b` [qa] util: Check return code after closing bitcoind proc (MarcoFalke) +- #10662 `e0a7801` Initialize randomness in benchmarks (achow101) +- #10612 `7c87a9c` The young person's guide to the test_framework (jnewbery) +- #10659 `acb1153` [qa] blockchain: Pass on closed connection during generate call (MarcoFalke) +- #10690 `416af3e` [qa] Bugfix: allow overriding extra_args in ComparisonTestFramework (sdaftuar) +- #10556 `65cc7aa` Move stop/start functions from utils.py into BitcoinTestFramework (jnewbery) +- #10704 `dd07f47` [tests] nits in dbcrash.py (jnewbery) +- #10743 `be82498` [test] don't run dbcrash.py on Travis (jnewbery) +- #10761 `d3b5870` [tests] fix replace_by_fee.py (jnewbery) +- #10759 `1d4805c` Fix multi_rpc test for hosts that dont default to utf8 (TheBlueMatt) +- #10190 `e4f226a` [tests] mining functional tests (including regression test for submitblock) (jnewbery) +- #10739 `1fc783f` test: Move variable `state` down where it is used (paveljanik) +- #9980 `fee0d80` Fix mem access violation merkleblock (Christewart) +- #10893 `0c173a1` [QA] Avoid running multiwallet.py twice (jonasschnelli) +- #10927 `9d5e8f9` test: Make sure wallet.backup is created in temp path (laanwj) +- #10899 `f29d5db` [test] Qt: Use _putenv_s instead of setenv on Windows builds (brianmcmichael) +- #10912 `5c8eb79` [tests] Fix incorrect memory_cleanse(…) call in crypto_tests.cpp (practicalswift) +- #11001 `fa8a063` [tests] Test disconnecting unsupported service bits logic (jnewbery) +- #10695 `929fd72` [qa] Rewrite BIP65/BIP66 functional tests (sdaftuar) +- #10963 `ecd2135` [bench] Restore format state of cout after printing with std::fixed/setprecision (practicalswift) +- #11025 `e5d26e4` qa: Fix inv race in example_test (MarcoFalke) +- #10765 `2c811e0` Tests: address placement should be deterministic by default (ReneNyffenegger) +- #11000 `ac016e1` test: Add resendwallettransactions functional tests (promag) +- #11032 `aeb3175` [qa] Fix block message processing error in sendheaders.py (sdaftuar) +- #10105 `0b9fb68` [tests] fixup - make all Travis test runs quiet, non just cron job runs (jnewbery) +- #10222 `6ce7337` [tests] test_runner - check unicode (jnewbery) +- #10327 `35da2ae` [tests] remove import-abort-rescan.py (jnewbery) +- #11023 `bf74d37` [tests] Add option to attach a python debugger if functional test fails (jnewbery) +- #10565 `8c2098a` [coverage] Remove subtrees and benchmarks from coverage report (achow101) + +### Miscellaneous +- #9871 `be8ba2c` Add a tree sha512 hash to merge commits (sipa) +- #9821 `d19d45a` util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD (laanwj) +- #9903 `ba80a68` Docs: add details to -rpcclienttimeout doc (ian-kelling) +- #9910 `53c300f` Docs: correct and elaborate -rpcbind doc (ian-kelling) +- #9905 `01b7cda` [contrib] gh-merge: Move second sha512 check to the end (MarcoFalke) +- #9880 `4df8213` Verify Tree-SHA512s in merge commits, enforce sigs are not SHA1 (TheBlueMatt) +- #9932 `00c13ea` Fix verify-commits on travis and always check top commit's tree (TheBlueMatt) +- #9952 `6996e06` Add historical release notes for 0.14.0 (laanwj) +- #9940 `fa99663` Fix verify-commits on OSX, update for new bad Tree-SHA512, point travis to different keyservers (TheBlueMatt) +- #9963 `8040ae6` util: Properly handle errors during log message formatting (laanwj) +- #9984 `cce056d` devtools: Make github-merge compute SHA512 from git, instead of worktree (laanwj) +- #9995 `8bcf934` [doc] clarify blockchain size and pruning (askmike) +- #9734 `0c17afc` Add updating of chainTxData to release process (sipa) +- #10063 `530fcbd` add missing spaces so that markdown recognizes headline (flack) +- #10085 `db1ae54` Docs: remove 'noconnect' option (jlopp) +- #10090 `8e4f7e7` Update bitcoin.conf with example for pruning (coinables) +- #9424 `1a5aaab` Change LogAcceptCategory to use uint32_t rather than sets of strings (gmaxwell) +- #10036 `fbf36ca` Fix init README format to render correctly on github (jlopp) +- #10058 `a2cd0b0` No need to use OpenSSL malloc/free (tjps) +- #10123 `471ed00` Allow debug logs to be excluded from specified component (jnewbery) +- #10104 `fadf078` linearize script: Option to use RPC cookie (achow101) +- #10162 `a3a2160` [trivial] Log calls to getblocktemplate (jnewbery) +- #10155 `928695b` build: Deduplicate version numbers (laanwj) +- #10211 `a86255b` [doc] Contributor fixes & new "finding reviewers" section (kallewoof) +- #10250 `1428f30` Fix some empty vector references (sipa) +- #10270 `95f5e44` Remove Clang workaround for Boost 1.46 (fanquake) +- #10263 `cb007e4` Trivial: fix fee estimate write error log message (CryptAxe) +- #9670 `bd9ec0e` contrib: github-merge improvements (laanwj) +- #10260 `1d75597` [doc] Minor corrections to osx dependencies (fanquake) +- #10189 `750c5a5` devtools/net: add a verifier for scriptable changes. Use it to make CNode::id private (theuni) +- #10322 `bc64b5a` Use hardware timestamps in RNG seeding (sipa) +- #10381 `7f2b9e0` Shadowing warnings are not enabled by default, update doc accordingly (paveljanik) +- #10380 `b6ee855` [doc] Removing comments about dirty entries on txmempool (madeo) +- #10383 `d0c37ee` [logging] log system time and mock time (jnewbery) +- #10404 `b45a52a` doc: Add logging to FinalizeNode() (sdaftuar) +- #10388 `526e839` Output line to debug.log when IsInitialBlockDownload latches to false (morcos) +- #10372 `15254e9` Add perf counter data to GetStrongRandBytes state in scheduler (TheBlueMatt) +- #10461 `55b72f3` Update style guide (sipa) +- #10486 `10e8c0a` devtools: Retry after signing fails in github-merge (laanwj) +- #10447 `f259263` Make bitcoind invalid argument error message specific (laanwj) +- #10495 `6a38b79` contrib: Update location of seeds.txt (laanwj) +- #10469 `b6b150b` Fixing typo in rpcdump.cpp help message (keystrike) +- #10451 `27b9931` contrib/init/bitcoind.openrcconf: Don't disable wallet by default (luke-jr) +- #10323 `00d3692` Update to latest libsecp256k1 master (sipa) +- #10422 `cec9e1e` Fix timestamp in fee estimate debug message (morcos) +- #10566 `5d034ee` [docs] Use the "domain name setup" image (previously unused) in the gitian docs (practicalswift) +- #10534 `a514ac3` Clarify prevector::erase and avoid swap-to-clear (sipa) +- #10575 `22ec768` Header include guideline (sipa) +- #10480 `fbf5d3b` Improve commit-check-script.sh (sipa) +- #10502 `1ad3d4e` scripted-diff: Remove BOOST_FOREACH, Q_FOREACH and PAIRTYPE (jtimon) +- #10377 `b63be2c` Use rdrand as entropy source on supported platforms (sipa) +- #9895 `228c319` Turn TryCreateDirectory() into TryCreateDirectories() (benma) +- #10602 `d76e84a` Make clang-format use C++11 features (e.g. A> instead of A >) (practicalswift) +- #10623 `c38f540` doc: Add 0.14.2 release notes (MarcoFalke) +- #10276 `b750b33` contrib/verifybinaries: allow filtering by platform (knocte) +- #10248 `01c4b14` Rewrite addrdb with less duplication using CHashVerifier (sipa) +- #10577 `232508f` Add an explanation of quickly hashing onto a non-power of two range (gmaxwell) +- #10608 `eee398f` Add a comment explaining the use of MAX_BLOCK_BASE_SIZE (gmaxwell) +- #10728 `7397af9` fix typo in help text for removeprunedfunds (AkioNak) +- #10193 `6dbcc74` scripted-diff: Remove #include (jtimon) +- #10676 `379aed0` document script-based return fields for validateaddress (instagibbs) +- #10651 `cef4b5c` Verify binaries from bitcoincore.org and bitcoin.org (TheBlueMatt) +- #10786 `ca4c545` Add PR description to merge commit in github-merge.py (sipa) +- #10812 `c5904e8` [utils] Allow bitcoin-cli's -rpcconnect option to be used with square brackets (jnewbery) +- #10842 `3895e25` Fix incorrect Doxygen tag (@ince → @since). Doxygen parameter name matching (practicalswift) +- #10681 `df0793f` add gdb attach process to test README (instagibbs) +- #10789 `1124328` Punctuation/grammer fixes in rpcwallet.cpp (stevendlander) +- #10655 `78f307b` Properly document target_confirmations in listsinceblock (RHavar) +- #10917 `5c003cb` developer-notes: add reference to snake_case and PascalCase (benma) +- #11003 `4b5a7ce` Docs: Capitalize bullet points in CONTRIBUTING guide (eklitzke) +- #10968 `98aa3f6` Add instructions for parallel gitian builds (coblee) +- #11076 `1c4b9b3` 0.15 release-notes nits: fix redundancy, remove accidental parenthesis & fix range style (practicalswift) +- #11090 `8f0121c` Update contributor names in release-notes.md (Derek701) +- #11056 `cbdd338` disable jni in builds (instagibbs) +- #11080 `2b59cfb` doc: Update build-openbsd for 6.1 (laanwj) +- #11119 `0a6af47` [doc] build-windows: Mention that only trusty works (MarcoFalke) +- #11108 `e8ad101` Changing -txindex requires -reindex, not -reindex-chainstate (TheBlueMatt) +- #9792 `342b9bc` FastRandomContext improvements and switch to ChaCha20 (sipa) +- #9505 `67ed40e` Prevector Quick Destruct (JeremyRubin) +- #10820 `ef37f20` Use cpuid intrinsics instead of asm code (sipa) +- #9999 `a328904` [LevelDB] Plug leveldb logs to bitcoin logs (NicolasDorier) +- #9693 `c5e9e42` Prevent integer overflow in ReadVarInt (gmaxwell) +- #10129 `351d0ad` scheduler: fix sub-second precision with boost < 1.50 (theuni) +- #10153 `fade788` logging: Fix off-by-one for shrinkdebugfile default (MarcoFalke) +- #10305 `c45da32` Fix potential NPD introduced in b297426c (TheBlueMatt) +- #10338 `daf3e7d` Maintain state across GetStrongRandBytes calls (sipa) +- #10544 `a4fe077` Update to LevelDB 1.20 (sipa) +- #10614 `cafe24f` random: fix crash on some 64bit platforms (theuni) +- #10714 `2a09a38` Avoid printing incorrect block indexing time due to uninitialized variable (practicalswift) +- #10837 `8bc6d1f` Fix resource leak on error in GetDevURandom (corebob) +- #10832 `89bb036` init: Factor out AppInitLockDataDirectory and fix startup core dump issue (laanwj) +- #10914 `b995a37` Add missing lock in CScheduler::AreThreadsServicingQueue() (TheBlueMatt) +- #10958 `659c096` Update to latest Bitcoin patches for LevelDB (sipa) +- #10919 `c1c671f` Fix more init bugs (TheBlueMatt) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- ロハン ダル +- Ahmad Kazi +- aideca +- Akio Nakamura +- Alex Morcos +- Allan Doensen +- Andres G. Aragoneses +- Andrew Chow +- Angel Leon +- Awemany +- Bob McElrath +- Brian McMichael +- BtcDrak +- Charlie Lee +- Chris Gavin +- Chris Stewart +- Cory Fields +- CryptAxe +- Dag Robole +- Daniel Aleksandersen +- Daniel Cousens +- darksh1ne +- Dimitris Tsapakidis +- Eric Shaw +- Evan Klitzke +- fanquake +- Felix Weis +- flack +- Guido Vranken +- Greg Griffith +- Gregory Maxwell +- Gregory Sanders +- Ian Kelling +- Jack Grigg +- James Evans +- James Hilliard +- Jameson Lopp +- Jeremy Rubin +- Jimmy Song +- João Barbosa +- Johnathan Corgan +- John Newbery +- Jonas Schnelli +- Jorge Timón +- Karl-Johan Alm +- kewde +- KibbledJiveElkZoo +- Kirit Thadaka +- kobake +- Kyle Honeycutt +- Lawrence Nahum +- Luke Dashjr +- Marco Falke +- Marcos Mayorga +- Marijn Stollenga +- Mario Dian +- Mark Friedenbach +- Marko Bencun +- Masahiko Hyuga +- Matt Corallo +- Matthew Zipkin +- Matthias Grundmann +- Michael Goldstein +- Michael Rotarius +- Mikerah +- Mike van Rossum +- Mitchell Cash +- Nicolas Dorier +- Patrick Strateman +- Pavel Janík +- Pavlos Antoniou +- Pavol Rusnak +- Pedro Branco +- Peter Todd +- Pieter Wuille +- practicalswift +- René Nyffenegger +- Ricardo Velhote +- romanornr +- Russell Yanofsky +- Rusty Russell +- Ryan Havar +- shaolinfry +- Shigeya Suzuki +- Simone Madeo +- Spencer Lievens +- Steven D. Lander +- Suhas Daftuar +- Takashi Mitsuta +- Thomas Snider +- Timothy Redaelli +- tintinweb +- tnaka +- Warren Togami +- Wladimir J. van der Laan + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From d8dd8e7356b4109cfde48d2667ea4da29c849cf8 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 4 Sep 2017 11:45:01 -0400 Subject: [PATCH 069/196] [tests] fixup dbcrash interaction with add_nodes() Github-Pull: #11230 Rebased-From: 8fdb6f9126fe1e13b60de11fd34c204247679ef4 --- test/functional/dbcrash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index 71424f641b55..24b9765b4e37 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -64,7 +64,7 @@ def set_test_params(self): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.add_nodes(self.num_nodes, timewait=90) + self.add_nodes(self.num_nodes, extra_args=self.extra_args, timewait=90) self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test From b6468d3c420f73627956fc94c9743d26d75af8b0 Mon Sep 17 00:00:00 2001 From: Cristian Mircea Messel Date: Wed, 13 Sep 2017 00:41:14 +0300 Subject: [PATCH 070/196] Add listwallets RPC test to multiwallet.py Github-Pull: #11310 Rebased-From: fb1f3258225a7052f4fc9e3f2accc3811c53e221 --- test/functional/multiwallet.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index e5453e9aaddc..b4e15a332219 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -18,6 +18,8 @@ def set_test_params(self): self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']] def run_test(self): + assert_equal(set(self.nodes[0].listwallets()), {"w1", "w2", "w3"}) + self.stop_node(0) # should not initialize if there are duplicate wallets From 2e1ac70df97be758a2a9869104a81cb454008174 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 12 Sep 2017 17:20:26 +0200 Subject: [PATCH 071/196] [qa] zapwallettxes: Wait up to 3s for mempool reload Github-Pull: #11308 Rebased-From: fadd0c16b6bd62e9d663d906755320ae089e02d3 --- test/functional/zapwallettxes.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index c001517a6d4f..83b11035c89e 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -15,9 +15,11 @@ been zapped. """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_equal, - assert_raises_jsonrpc, - ) +from test_framework.util import ( + assert_equal, + assert_raises_jsonrpc, + wait_until, +) class ZapWalletTXesTest (BitcoinTestFramework): def set_test_params(self): @@ -56,6 +58,8 @@ def run_test(self): self.stop_node(0) self.start_node(0, ["-persistmempool=1", "-zapwallettxes=2"]) + wait_until(lambda: self.nodes[0].getmempoolinfo()['size'] == 1, timeout=3) + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) From f1ced0d7761d1316c6b522b2b426e79833e4cbae Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 17 Aug 2017 11:35:45 -0400 Subject: [PATCH 072/196] [tests] Make p2p-leaktests.py more robust Github-Pull: #11078 Rebased-From: 0063d2c3dce9d9c1678197d2c65ee878793d1ef9 --- test/functional/p2p-leaktests.py | 9 +++++++-- test/functional/test_framework/mininode.py | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index f27086c97eb2..1dc8f72cd632 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -139,6 +139,9 @@ def run_test(self): [conn.disconnect_node() for conn in connections] + # Wait until all connections are closed + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0) + # Make sure no unexpected messages came in assert(no_version_bannode.unexpected_msg == False) assert(no_version_idlenode.unexpected_msg == False) @@ -157,8 +160,10 @@ def run_test(self): allowed_service_bit5_node.add_connection(connections[5]) allowed_service_bit7_node.add_connection(connections[6]) - wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10, lock=mininode_lock) - wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10, lock=mininode_lock) + NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it + + wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock) + wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock) if __name__ == '__main__': P2PLeakTest().main() diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index d0753276db2b..59245302303c 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1837,6 +1837,7 @@ def run(self): disconnected.append(obj) [ obj.handle_close() for obj in disconnected ] asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1) + logger.debug("Network thread closing") # An exception we can raise if we detect a potential disconnect From f9cf7b589f430b2d7c52e477b6d62f29d748c38e Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 15 Sep 2017 14:36:12 -0400 Subject: [PATCH 073/196] [tests] Check connectivity before sending in assumevalid.py assumevalid.py would try to send over a closed P2P connection in a loop, hitting the following failure many times: TestFramework.mininode (ERROR): Cannot send message. No connection to node! The test still passes, but this is a lot of noise in the test log. Just check that the connection is open before trying to send. Github-Pull: #11345 Rebased-From: e9e9391083721ca9733cc00a1907384f83b6435e --- test/functional/assumevalid.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index beaf8c705586..65685c48b7ee 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -68,6 +68,8 @@ def setup_network(self): def send_blocks_until_disconnected(self, node): """Keep sending blocks to the node until we're disconnected.""" for i in range(len(self.blocks)): + if not node.connection: + break try: node.send_message(msg_block(self.blocks[i])) except IOError as e: From 794a80eee335a10d239aed7fdbdd013bce45161d Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 18 Aug 2017 14:40:29 -0700 Subject: [PATCH 074/196] [script] Unit tests for script/standard functions Github-Pull: #11116 Rebased-From: d7afe2d1577eb3f6775301c81b94a191e0db99d9 --- src/Makefile.test.include | 1 + src/test/multisig_tests.cpp | 91 ------- src/test/script_standard_tests.cpp | 385 +++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+), 91 deletions(-) create mode 100644 src/test/script_standard_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 01ab0134fee5..3a932f460d69 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -65,6 +65,7 @@ BITCOIN_TESTS =\ test/scheduler_tests.cpp \ test/script_P2SH_tests.cpp \ test/script_tests.cpp \ + test/script_standard_tests.cpp \ test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ test/sighash_tests.cpp \ diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 5e89ef60d211..de7f3b48f5d6 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -16,8 +16,6 @@ #include -typedef std::vector valtype; - BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript @@ -173,95 +171,6 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) BOOST_CHECK(!::IsStandard(malformed[i], whichType)); } -BOOST_AUTO_TEST_CASE(multisig_Solver1) -{ - // Tests Solver() that returns lists of keys that are - // required to satisfy a ScriptPubKey - // - // Also tests IsMine() and ExtractDestination() - // - // Note: ExtractDestination for the multisignature transactions - // always returns false for this release, even if you have - // one key that would satisfy an (a|b) or 2-of-3 keys needed - // to spend an escrow transaction. - // - CBasicKeyStore keystore, emptykeystore, partialkeystore; - CKey key[3]; - CTxDestination keyaddr[3]; - for (int i = 0; i < 3; i++) - { - key[i].MakeNewKey(true); - keystore.AddKey(key[i]); - keyaddr[i] = key[i].GetPubKey().GetID(); - } - partialkeystore.AddKey(key[0]); - - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK(solutions.size() == 1); - CTxDestination addr; - BOOST_CHECK(ExtractDestination(s, addr)); - BOOST_CHECK(addr == keyaddr[0]); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK(solutions.size() == 1); - CTxDestination addr; - BOOST_CHECK(ExtractDestination(s, addr)); - BOOST_CHECK(addr == keyaddr[0]); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4U); - CTxDestination addr; - BOOST_CHECK(!ExtractDestination(s, addr)); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - BOOST_CHECK(!IsMine(partialkeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4U); - std::vector addrs; - int nRequired; - BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); - BOOST_CHECK(addrs[0] == keyaddr[0]); - BOOST_CHECK(addrs[1] == keyaddr[1]); - BOOST_CHECK(nRequired == 1); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - BOOST_CHECK(!IsMine(partialkeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK(solutions.size() == 5); - } -} - BOOST_AUTO_TEST_CASE(multisig_Sign) { // Test SignSignature() (and therefore the version of Solver() that signs transactions) diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp new file mode 100644 index 000000000000..e6a63ad54eb3 --- /dev/null +++ b/src/test/script_standard_tests.cpp @@ -0,0 +1,385 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "key.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/standard.h" +#include "test/test_bitcoin.h" + +#include + + +BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(script_standard_Solver_success) +{ + CKey keys[3]; + CPubKey pubkeys[3]; + for (int i = 0; i < 3; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CScript s; + txnouttype whichType; + std::vector > solutions; + + // TX_PUBKEY + s.clear(); + s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0])); + + // TX_PUBKEYHASH + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); + + // TX_SCRIPTHASH + CScript redeemScript(s); // initialize with leftover P2PKH script + s.clear(); + s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript))); + + // TX_MULTISIG + s.clear(); + s << OP_1 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(solutions.size(), 4); + BOOST_CHECK(solutions[0] == std::vector({1})); + BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); + BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1])); + BOOST_CHECK(solutions[3] == std::vector({2})); + + s.clear(); + s << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + ToByteVector(pubkeys[2]) << + OP_3 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(solutions.size(), 5); + BOOST_CHECK(solutions[0] == std::vector({2})); + BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); + BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1])); + BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2])); + BOOST_CHECK(solutions[4] == std::vector({3})); + + // TX_NULL_DATA + solutions.clear(); + s.clear(); + s << OP_RETURN << + std::vector({0}) << + std::vector({75}) << + std::vector({255}); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA); + BOOST_CHECK_EQUAL(solutions.size(), 0); + + // TX_WITNESS_V0_KEYHASH + solutions.clear(); + s.clear(); + s << OP_0 << ToByteVector(pubkeys[0].GetID()); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); + + // TX_WITNESS_V0_SCRIPTHASH + uint256 scriptHash; + CSHA256().Write(&redeemScript[0], redeemScript.size()).Finalize(scriptHash.begin()); + + solutions.clear(); + s.clear(); + s << OP_0 << ToByteVector(scriptHash); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); + + // TX_NONSTANDARD + solutions.clear(); + s.clear(); + s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; + BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD); +} + +BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) +{ + CKey key; + CPubKey pubkey; + key.MakeNewKey(true); + pubkey = key.GetPubKey(); + + CScript s; + txnouttype whichType; + std::vector > solutions; + + // TX_PUBKEY with incorrectly sized pubkey + s.clear(); + s << std::vector(30, 0x01) << OP_CHECKSIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_PUBKEYHASH with incorrectly sized key hash + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_SCRIPTHASH with incorrectly sized script hash + s.clear(); + s << OP_HASH160 << std::vector(21, 0x01) << OP_EQUAL; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG 0/2 + s.clear(); + s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG 2/1 + s.clear(); + s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG n = 2 with 1 pubkey + s.clear(); + s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG n = 1 with 0 pubkeys + s.clear(); + s << OP_1 << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_NULL_DATA with other opcodes + s.clear(); + s << OP_RETURN << std::vector({75}) << OP_ADD; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_WITNESS with unknown version + s.clear(); + s << OP_1 << ToByteVector(pubkey); + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_WITNESS with incorrect program size + s.clear(); + s << OP_0 << std::vector(19, 0x01); + BOOST_CHECK(!Solver(s, whichType, solutions)); +} + +BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) +{ + CKey key; + CPubKey pubkey; + key.MakeNewKey(true); + pubkey = key.GetPubKey(); + + CScript s; + CTxDestination address; + + // TX_PUBKEY + s.clear(); + s << ToByteVector(pubkey) << OP_CHECKSIG; + BOOST_CHECK(ExtractDestination(s, address)); + BOOST_CHECK(boost::get(&address) && + *boost::get(&address) == pubkey.GetID()); + + // TX_PUBKEYHASH + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(ExtractDestination(s, address)); + BOOST_CHECK(boost::get(&address) && + *boost::get(&address) == pubkey.GetID()); + + // TX_SCRIPTHASH + CScript redeemScript(s); // initialize with leftover P2PKH script + s.clear(); + s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + BOOST_CHECK(ExtractDestination(s, address)); + BOOST_CHECK(boost::get(&address) && + *boost::get(&address) == CScriptID(redeemScript)); + + // TX_MULTISIG + s.clear(); + s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!ExtractDestination(s, address)); + + // TX_NULL_DATA + s.clear(); + s << OP_RETURN << std::vector({75}); + BOOST_CHECK(!ExtractDestination(s, address)); + + // TX_WITNESS_V0_KEYHASH + s.clear(); + s << OP_0 << ToByteVector(pubkey); + BOOST_CHECK(!ExtractDestination(s, address)); + + // TX_WITNESS_V0_SCRIPTHASH + s.clear(); + s << OP_0 << ToByteVector(CScriptID(redeemScript)); + BOOST_CHECK(!ExtractDestination(s, address)); +} + +BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) +{ + CKey keys[3]; + CPubKey pubkeys[3]; + for (int i = 0; i < 3; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CScript s; + txnouttype whichType; + std::vector addresses; + int nRequired; + + // TX_PUBKEY + s.clear(); + s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); + BOOST_CHECK_EQUAL(addresses.size(), 1); + BOOST_CHECK_EQUAL(nRequired, 1); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == pubkeys[0].GetID()); + + // TX_PUBKEYHASH + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); + BOOST_CHECK_EQUAL(addresses.size(), 1); + BOOST_CHECK_EQUAL(nRequired, 1); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == pubkeys[0].GetID()); + + // TX_SCRIPTHASH + CScript redeemScript(s); // initialize with leftover P2PKH script + s.clear(); + s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); + BOOST_CHECK_EQUAL(addresses.size(), 1); + BOOST_CHECK_EQUAL(nRequired, 1); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == CScriptID(redeemScript)); + + // TX_MULTISIG + s.clear(); + s << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(addresses.size(), 2); + BOOST_CHECK_EQUAL(nRequired, 2); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == pubkeys[0].GetID()); + BOOST_CHECK(boost::get(&addresses[1]) && + *boost::get(&addresses[1]) == pubkeys[1].GetID()); + + // TX_NULL_DATA + s.clear(); + s << OP_RETURN << std::vector({75}); + BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); + + // TX_WITNESS_V0_KEYHASH + s.clear(); + s << OP_0 << ToByteVector(pubkeys[0].GetID()); + BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); + + // TX_WITNESS_V0_SCRIPTHASH + s.clear(); + s << OP_0 << ToByteVector(CScriptID(redeemScript)); + BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); +} + +BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) +{ + CKey keys[3]; + CPubKey pubkeys[3]; + for (int i = 0; i < 3; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CScript expected, result; + + // CKeyID + expected.clear(); + expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + result = GetScriptForDestination(pubkeys[0].GetID()); + BOOST_CHECK(result == expected); + + // CScriptID + CScript redeemScript(result); + expected.clear(); + expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + result = GetScriptForDestination(CScriptID(redeemScript)); + BOOST_CHECK(result == expected); + + // CNoDestination + expected.clear(); + result = GetScriptForDestination(CNoDestination()); + BOOST_CHECK(result == expected); + + // GetScriptForRawPubKey + expected.clear(); + expected << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + result = GetScriptForRawPubKey(pubkeys[0]); + BOOST_CHECK(result == expected); + + // GetScriptForMultisig + expected.clear(); + expected << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + ToByteVector(pubkeys[2]) << + OP_3 << OP_CHECKMULTISIG; + result = GetScriptForMultisig(2, std::vector(pubkeys, pubkeys + 3)); + BOOST_CHECK(result == expected); + + // GetScriptForWitness + CScript witnessScript; + + witnessScript << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + expected.clear(); + expected << OP_0 << ToByteVector(pubkeys[0].GetID()); + result = GetScriptForWitness(witnessScript); + BOOST_CHECK(result == expected); + + witnessScript.clear(); + witnessScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + result = GetScriptForWitness(witnessScript); + BOOST_CHECK(result == expected); + + witnessScript.clear(); + witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()).Finalize(scriptHash.begin()); + + expected.clear(); + expected << OP_0 << ToByteVector(scriptHash); + result = GetScriptForWitness(witnessScript); + BOOST_CHECK(result == expected); +} + +BOOST_AUTO_TEST_SUITE_END() From 2c4ff35a8fce0c40884886a93c1bf12395fb105d Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Tue, 22 Aug 2017 17:47:59 -0700 Subject: [PATCH 075/196] [script] Unit tests for IsMine Does not test watch-only addresses. Github-Pull: #11116 Rebased-From: 7a1e873b27b790c965d9927ecd465710dc103136 --- src/script/ismine.cpp | 2 + src/test/script_standard_tests.cpp | 367 ++++++++++++++++++++++++++++- 2 files changed, 363 insertions(+), 6 deletions(-) diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 0a39619734cf..c3aade177476 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -46,6 +46,8 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion) { + isInvalid = false; + std::vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index e6a63ad54eb3..3d17a0dbb6c6 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" +#include "keystore.h" +#include "script/ismine.h" #include "script/script.h" #include "script/script_error.h" #include "script/standard.h" @@ -81,7 +83,6 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK(solutions[4] == std::vector({3})); // TX_NULL_DATA - solutions.clear(); s.clear(); s << OP_RETURN << std::vector({0}) << @@ -92,7 +93,6 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK_EQUAL(solutions.size(), 0); // TX_WITNESS_V0_KEYHASH - solutions.clear(); s.clear(); s << OP_0 << ToByteVector(pubkeys[0].GetID()); BOOST_CHECK(Solver(s, whichType, solutions)); @@ -102,9 +102,9 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) // TX_WITNESS_V0_SCRIPTHASH uint256 scriptHash; - CSHA256().Write(&redeemScript[0], redeemScript.size()).Finalize(scriptHash.begin()); + CSHA256().Write(&redeemScript[0], redeemScript.size()) + .Finalize(scriptHash.begin()); - solutions.clear(); s.clear(); s << OP_0 << ToByteVector(scriptHash); BOOST_CHECK(Solver(s, whichType, solutions)); @@ -113,7 +113,6 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); // TX_NONSTANDARD - solutions.clear(); s.clear(); s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; BOOST_CHECK(!Solver(s, whichType, solutions)); @@ -374,7 +373,8 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG; uint256 scriptHash; - CSHA256().Write(&witnessScript[0], witnessScript.size()).Finalize(scriptHash.begin()); + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); expected.clear(); expected << OP_0 << ToByteVector(scriptHash); @@ -382,4 +382,359 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) BOOST_CHECK(result == expected); } +BOOST_AUTO_TEST_CASE(script_standard_IsMine) +{ + CKey keys[2]; + CPubKey pubkeys[2]; + for (int i = 0; i < 2; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CKey uncompressedKey; + uncompressedKey.MakeNewKey(false); + CPubKey uncompressedPubkey = uncompressedKey.GetPubKey(); + + CScript scriptPubKey; + isminetype result; + bool isInvalid; + + // P2PK compressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(keys[0]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2PK uncompressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << ToByteVector(uncompressedPubkey) << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(uncompressedKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2PKH compressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(keys[0]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2PKH uncompressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(uncompressedPubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(uncompressedKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2SH + { + CBasicKeyStore keystore; + + CScript redeemScript; + redeemScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + + scriptPubKey.clear(); + scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + + // Keystore does not have redeemScript or key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has redeemScript but no key + keystore.AddCScript(redeemScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has redeemScript and key + keystore.AddKey(keys[0]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WPKH compressed + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(pubkeys[0].GetID()); + + // Keystore has key, but no P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key and P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WPKH uncompressed + { + CBasicKeyStore keystore; + keystore.AddKey(uncompressedKey); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(uncompressedPubkey.GetID()); + + // Keystore has key, but no P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key and P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(isInvalid); + } + + // scriptPubKey multisig + { + CBasicKeyStore keystore; + + scriptPubKey.clear(); + scriptPubKey << OP_2 << + ToByteVector(uncompressedPubkey) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + // Keystore does not have any keys + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has 1/2 keys + keystore.AddKey(uncompressedKey); + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has 2/2 keys + keystore.AddKey(keys[1]); + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2SH multisig + { + CBasicKeyStore keystore; + keystore.AddKey(uncompressedKey); + keystore.AddKey(keys[1]); + + CScript redeemScript; + redeemScript << OP_2 << + ToByteVector(uncompressedPubkey) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + scriptPubKey.clear(); + scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + + // Keystore has no redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has redeemScript + keystore.AddCScript(redeemScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WSH multisig with compressed keys + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + keystore.AddKey(keys[1]); + + CScript witnessScript; + witnessScript << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(scriptHash); + + // Keystore has keys, but no witnessScript or P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys and witnessScript, but no P2SH redeemScript + keystore.AddCScript(witnessScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys, witnessScript, P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WSH multisig with uncompressed key + { + CBasicKeyStore keystore; + keystore.AddKey(uncompressedKey); + keystore.AddKey(keys[1]); + + CScript witnessScript; + witnessScript << OP_2 << + ToByteVector(uncompressedPubkey) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(scriptHash); + + // Keystore has keys, but no witnessScript or P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys and witnessScript, but no P2SH redeemScript + keystore.AddCScript(witnessScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys, witnessScript, P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(isInvalid); + } + + // P2WSH multisig wrapped in P2SH + { + CBasicKeyStore keystore; + + CScript witnessScript; + witnessScript << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); + + CScript redeemScript; + redeemScript << OP_0 << ToByteVector(scriptHash); + + scriptPubKey.clear(); + scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + + // Keystore has no witnessScript, P2SH redeemScript, or keys + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has witnessScript and P2SH redeemScript, but no keys + keystore.AddCScript(redeemScript); + keystore.AddCScript(witnessScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys, witnessScript, P2SH redeemScript + keystore.AddKey(keys[0]); + keystore.AddKey(keys[1]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // OP_RETURN + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + + scriptPubKey.clear(); + scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]); + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + } + + // Nonstandard + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + + scriptPubKey.clear(); + scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL; + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + } +} + BOOST_AUTO_TEST_SUITE_END() From e4605d9dd498a1fa713e6a916347a7c887f2c2b8 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 7 Jun 2017 17:08:32 -0700 Subject: [PATCH 076/196] Tests for zmqpubrawtx and zmqpubrawblock Github-Pull: #10552 Rebased-From: d3677ab757ea57b21d8aed24d5bc3c4bfe9bb68c --- test/functional/test_framework/util.py | 8 ++++ test/functional/zmq_test.py | 52 +++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index b2d8199d12b8..64966adb9738 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -7,6 +7,7 @@ from base64 import b64encode from binascii import hexlify, unhexlify from decimal import Decimal, ROUND_DOWN +import hashlib import json import logging import os @@ -173,6 +174,13 @@ def count_bytes(hex_string): def bytes_to_hex_str(byte_str): return hexlify(byte_str).decode('ascii') +def hash256(byte_str): + sha256 = hashlib.sha256() + sha256.update(byte_str) + sha256d = hashlib.sha256() + sha256d.update(sha256.digest()) + return sha256d.digest()[::-1] + def hex_str_to_bytes(hex_str): return unhexlify(hex_str.encode('ascii')) diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index 3f2668ee8724..382ef5bae289 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -10,7 +10,8 @@ from test_framework.test_framework import BitcoinTestFramework, SkipTest from test_framework.util import (assert_equal, bytes_to_hex_str, - ) + hash256, + ) class ZMQTest (BitcoinTestFramework): def set_test_params(self): @@ -37,9 +38,12 @@ def setup_nodes(self): self.zmqSubSocket.set(zmq.RCVTIMEO, 60000) self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock") self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawblock") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtx") ip_address = "tcp://127.0.0.1:28332" self.zmqSubSocket.connect(ip_address) - self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] + self.extra_args = [['-zmqpubhashblock=%s' % ip_address, '-zmqpubhashtx=%s' % ip_address, + '-zmqpubrawblock=%s' % ip_address, '-zmqpubrawtx=%s' % ip_address], []] self.add_nodes(self.num_nodes, self.extra_args) self.start_nodes() @@ -59,28 +63,51 @@ def _zmq_test(self): msg = self.zmqSubSocket.recv_multipart() topic = msg[0] assert_equal(topic, b"hashtx") - body = msg[1] + txhash = msg[1] msgSequence = struct.unpack(' Date: Wed, 13 Sep 2017 09:17:15 -0400 Subject: [PATCH 077/196] qa: Treat mininode p2p exceptions as fatal Github-Pull: #11319 Rebased-From: a7820422e0b182db6f1df8904242e5d76d6c73fa --- test/functional/test_framework/mininode.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 59245302303c..843b67cd5cac 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1505,6 +1505,7 @@ def deliver(self, conn, message): except: print("ERROR delivering %s (%s)" % (repr(message), sys.exc_info()[0])) + raise def set_deliver_sleep_time(self, value): with mininode_lock: @@ -1708,13 +1709,10 @@ def handle_close(self): self.cb.on_close(self) def handle_read(self): - try: - t = self.recv(8192) - if len(t) > 0: - self.recvbuf += t - self.got_data() - except: - pass + t = self.recv(8192) + if len(t) > 0: + self.recvbuf += t + self.got_data() def readable(self): return True @@ -1780,8 +1778,10 @@ def got_data(self): self.got_message(t) else: logger.warning("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg))) + raise ValueError("Unknown command: '%s'" % (command)) except Exception as e: logger.exception('got_data:', repr(e)) + raise def send_message(self, message, pushbuf=False): if self.state != "connected" and not pushbuf: From 8d2e51d86253881abadb5b11f93b12e3761f6232 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 13 Sep 2017 09:21:27 -0400 Subject: [PATCH 078/196] qa: Fix bug introduced in p2p-segwit.py Changing __init__() -> set_test_params() in the tests should not have applied to NodeConnCB-derived objects. Github-Pull: #11319 Rebased-From: f97ab35fa9687fd5c110ad6cca5be5b4a5c2142d --- test/functional/p2p-segwit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 9bb72c819945..9105f0ee06c5 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -33,8 +33,8 @@ def get_virtual_size(witness_block): return vsize class TestNode(NodeConnCB): - def set_test_params(self): - self.num_nodes = 3 + def __init__(self): + super().__init__() self.getdataset = set() def on_getdata(self, conn, message): From a36f3320a94aa70328e133d53146fc1ef57e1e34 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 29 Sep 2017 17:33:50 -0400 Subject: [PATCH 079/196] Verify DBWrapper iterators are taking snapshots The LevelDB docs seem to indicate that an iterator will not take snapshots (even providing instructions on how to do so yourself). In several of the places we use them, we assume snapshots to have been taken. In order to make sure LevelDB doesn't change out from under us (and to prevent the next person who reads the docs from having the same fright I did), verify that snapshots are taken in our tests. Github-Pull: #11422 Rebased-From: bb8376bbc3d96af727444f90e5f60d47105609dc --- src/test/dbwrapper_tests.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 6ed6e7744e3e..d90fe5027705 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -204,19 +204,31 @@ BOOST_AUTO_TEST_CASE(iterator_ordering) for (int x=0x00; x<256; ++x) { uint8_t key = x; uint32_t value = x*x; - BOOST_CHECK(dbw.Write(key, value)); + if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value)); } + // Check that creating an iterator creates a snapshot std::unique_ptr it(const_cast(dbw).NewIterator()); + + for (int x=0x00; x<256; ++x) { + uint8_t key = x; + uint32_t value = x*x; + if (x & 1) BOOST_CHECK(dbw.Write(key, value)); + } + for (int seek_start : {0x00, 0x80}) { it->Seek((uint8_t)seek_start); - for (int x=seek_start; x<256; ++x) { + for (int x=seek_start; x<255; ++x) { uint8_t key; uint32_t value; BOOST_CHECK(it->Valid()); if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure break; BOOST_CHECK(it->GetKey(key)); + if (x & 1) { + BOOST_CHECK_EQUAL(key, x + 1); + continue; + } BOOST_CHECK(it->GetValue(value)); BOOST_CHECK_EQUAL(key, x); BOOST_CHECK_EQUAL(value, x*x); From a825d4af5e3ca353bce421e966ddcb9fc643075c Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Mon, 25 Sep 2017 18:14:03 +0800 Subject: [PATCH 080/196] Fix bip68-sequence rpc test Github-Pull: #11399 Rebased-From: 49f869fe91716785b3276925d64bf8955feff69f --- test/functional/bip68-sequence.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/functional/bip68-sequence.py b/test/functional/bip68-sequence.py index 39012adf9533..1391b9ed466f 100755 --- a/test/functional/bip68-sequence.py +++ b/test/functional/bip68-sequence.py @@ -369,11 +369,14 @@ def test_bip68_not_consensus(self): def activateCSV(self): # activation should happen at block height 432 (3 periods) + # getblockchaininfo will show CSV as active at block 431 (144 * 3 -1) since it's returning whether CSV is active for the next block. min_activation_height = 432 height = self.nodes[0].getblockcount() - assert(height < min_activation_height) - self.nodes[0].generate(min_activation_height-height) - assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') + assert_greater_than(min_activation_height - height, 2) + self.nodes[0].generate(min_activation_height - height - 2) + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "locked_in") + self.nodes[0].generate(1) + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "active") sync_blocks(self.nodes) # Use self.nodes[1] to test that version 2 transactions are standard. From 806c78f014f6be9e12afb181d85e135f3b44e33e Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Tue, 26 Sep 2017 17:24:26 -0400 Subject: [PATCH 081/196] add functional test for mempoolreplacement command line arg Github-Pull: #11407 Rebased-From: 1088b5322d0e7a8366a285e2baa49c766a9ba5bd --- test/functional/replace-by-fee.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index 220e88968663..5e1f33991b4b 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -62,13 +62,14 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): class ReplaceByFeeTest(BitcoinTestFramework): def set_test_params(self): - self.num_nodes = 1 + self.num_nodes = 2 self.extra_args= [["-maxorphantx=1000", "-whitelist=127.0.0.1", "-limitancestorcount=50", "-limitancestorsize=101", "-limitdescendantcount=200", - "-limitdescendantsize=101"]] + "-limitdescendantsize=101"], + ["-mempoolreplacement=0"]] def run_test(self): make_utxo(self.nodes[0], 1*COIN) @@ -115,6 +116,8 @@ def test_simple_doublespend(self): tx1a_hex = txToHex(tx1a) tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + self.sync_all([self.nodes]) + # Should fail because we haven't changed the fee tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] @@ -123,12 +126,17 @@ def test_simple_doublespend(self): # This will raise an exception due to insufficient fee assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) + # This will raise an exception due to transaction replacement being disabled + assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) # Extra 0.1 BTC fee tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] tx1b_hex = txToHex(tx1b) + # Replacement still disabled even with "enough fee" + assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) + # Works when enabled tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) mempool = self.nodes[0].getrawmempool() @@ -138,6 +146,11 @@ def test_simple_doublespend(self): assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid)) + # Second node is running mempoolreplacement=0, will not replace originally-seen txn + mempool = self.nodes[1].getrawmempool() + assert tx1a_txid in mempool + assert tx1b_txid not in mempool + def test_doublespend_chain(self): """Doublespend of a long chain""" From 6b4d9f273607bcacaa65a7a030eef5cc9d6bb6e8 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Sun, 3 Sep 2017 08:43:35 -0400 Subject: [PATCH 082/196] wallet: update stored witness in AddToWallet Replace witness-stripped wallet transactions with full transactions; this can happen when upgrading from a pre-segwit wallet to a segwit- aware wallet. Github-Pull: #11225 Rebased-From: d01a9682b126a5f83c7311e652e6e62f2c2e1d20 --- src/wallet/wallet.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bf8981e4e871..5e833ebee70e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -969,6 +969,15 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) wtx.fFromMe = wtxIn.fFromMe; fUpdated = true; } + // If we have a witness-stripped version of this transaction, and we + // see a new version with a witness, then we must be upgrading a pre-segwit + // wallet. Store the new version of the transaction with the witness, + // as the stripped-version must be invalid. + // TODO: Store all versions of the transaction, instead of just one. + if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) { + wtx.SetTx(wtxIn.tx); + fUpdated = true; + } } //// debug print From 0fe2a9a196b2f81fed2ea84a5979e95f37094b22 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Tue, 5 Sep 2017 17:32:06 -0700 Subject: [PATCH 083/196] when clearing addrman clear mapInfo and mapAddr Github-Pull: #11252 Rebased-From: b86a42077a134888c53bfd406b87bf0a39c78264 --- src/addrman.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/addrman.h b/src/addrman.h index 547088aedf4f..18f306228730 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -472,6 +472,8 @@ class CAddrMan nTried = 0; nNew = 0; nLastGood = 1; //Initially at 1 so that "never" is strictly worse. + mapInfo.clear(); + mapAddr.clear(); } CAddrMan() From 6a62c745a9ce7d08667ab544ee3627e035e9d0ce Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 15 Sep 2017 11:50:45 +0200 Subject: [PATCH 084/196] qt: Backup former GUI settings on `-resetguisettings` Writes the GUI settings to `guisettings.bak` in the data directory before wiping them. This can be used to retroactively troubleshoot issues (e.g. #11262) where `-resetguisettings` solves the problem. Github-Pull: #11338 Rebased-From: 723aa1b8752c1d6c6c0a76059c532ebe2f406fc1 --- doc/files.md | 1 + src/qt/optionsmodel.cpp | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/doc/files.md b/doc/files.md index 928977143be3..3d603445fbfc 100644 --- a/doc/files.md +++ b/doc/files.md @@ -15,6 +15,7 @@ * wallet.dat: personal wallet (BDB) with keys and transactions * .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0 * onion_private_key: cached Tor hidden service private key for `-listenonion`: since 0.12.0 +* guisettings.ini.bak: backup of former GUI settings after `-resetguisettings` is used Only used in pre-0.8.0 --------------------- diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 77efef3e3ca2..a2dd52d9cbe4 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -151,10 +151,32 @@ void OptionsModel::Init(bool resetSettings) language = settings.value("language").toString(); } +/** Helper function to copy contents from one QSettings to another. + * By using allKeys this also covers nested settings in a hierarchy. + */ +static void CopySettings(QSettings& dst, const QSettings& src) +{ + for (const QString& key : src.allKeys()) { + dst.setValue(key, src.value(key)); + } +} + +/** Back up a QSettings to an ini-formatted file. */ +static void BackupSettings(const fs::path& filename, const QSettings& src) +{ + qWarning() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename); + QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat); + dst.clear(); + CopySettings(dst, src); +} + void OptionsModel::Reset() { QSettings settings; + // Backup old settings to chain-specific datadir for troubleshooting + BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings); + // Save the strDataDir setting QString dataDir = Intro::getDefaultDataDirectory(); dataDir = settings.value("strDataDir", dataDir).toString(); From b6c0209aaf372a21090c0a3eed973022af14ece0 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 2 Oct 2017 18:24:59 -0400 Subject: [PATCH 085/196] Fix validationinterface build on super old boost/clang This should fix all the non-dependancy issues for termux builds. See Github issue #11388. Github-Pull: #11440 Rebased-From: 96c2ce9d343147608c197bc2333138b82141340f --- src/validationinterface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index bf20d606f833..cd2fecd22455 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -4,7 +4,9 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "validationinterface.h" + #include "init.h" +#include "primitives/block.h" #include "scheduler.h" #include "sync.h" #include "util.h" From e169349f8c25d8998492b38500c1fee1074ed6fe Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 1 Oct 2017 11:19:49 +0200 Subject: [PATCH 086/196] qa: Restore bitcoin-util-test py2 compatibility Github-Pull: #11433 Rebased-From: fafff1220cf798e25f02cdd8affb70506dd366cc --- src/Makefile.test.include | 2 +- test/util/bitcoin-util-test.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 3a932f460d69..b48bfc76b785 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -147,7 +147,7 @@ bitcoin_test_clean : FORCE check-local: @echo "Running test/util/bitcoin-util-test.py..." - $(top_builddir)/test/util/bitcoin-util-test.py + $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py index d15d6a6011cc..ef34955d9090 100755 --- a/test/util/bitcoin-util-test.py +++ b/test/util/bitcoin-util-test.py @@ -9,9 +9,14 @@ Can also be run manually.""" +from __future__ import division,print_function,unicode_literals + import argparse import binascii -import configparser +try: + import configparser +except ImportError: + import ConfigParser as configparser import difflib import json import logging @@ -22,7 +27,9 @@ def main(): config = configparser.ConfigParser() - config.read_file(open(os.path.dirname(__file__) + "/../config.ini")) + config.optionxform = str + config.readfp(open(os.path.join(os.path.dirname(__file__), "../config.ini"))) + env_conf = dict(config.items('environment')) parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-v', '--verbose', action='store_true') @@ -37,7 +44,7 @@ def main(): # Add the format/level to the logger logging.basicConfig(format=formatter, level=level) - bctester(config["environment"]["SRCDIR"] + "/test/util/data", "bitcoin-util-test.json", config["environment"]) + bctester(os.path.join(env_conf["SRCDIR"], "test/util/data"), "bitcoin-util-test.json", env_conf) def bctester(testDir, input_basename, buildenv): """ Loads and parses the input file, runs all tests and reports results""" From 019c492490077a7581ab526b4208439200cbff24 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 2 Oct 2017 13:35:08 +0200 Subject: [PATCH 087/196] qa: Fix lcov for out-of-tree builds Github-Pull: #11443 Rebased-From: fae60e338639b3a09d2f26d8eb5feb3bb576b1fd --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 71e22dc28cc6..e8aa7d5ae121 100644 --- a/configure.ac +++ b/configure.ac @@ -1231,6 +1231,7 @@ AC_SUBST(QR_LIBS) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) AC_CONFIG_FILES([doc/Doxyfile]) +AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py]) AC_CONFIG_LINKS([test/util/bitcoin-util-test.py:test/util/bitcoin-util-test.py]) From a43be5bcdb27a68abe9bb5fec57185a1b6652479 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 7 Mar 2017 09:50:41 +0100 Subject: [PATCH 088/196] rpc: Prevent `dumpwallet` from overwriting files Prevent arbitrary files from being overwritten. There have been reports that users have overwritten wallet files this way. It may also avoid other security issues. Fixes #9934. Adds mention to release notes and adds a test. Github-Pull: #9937 Rebased-From: 0cd9273fd959c6742574259d026039f7da0309a2 --- doc/release-notes.md | 3 +++ src/wallet/rpcdump.cpp | 14 ++++++++++++-- test/functional/wallet-dump.py | 5 ++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index ef8de316a505..0235e1c606ec 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -65,6 +65,9 @@ Notable changes 0.15.1 Change log ================= +- `dumpwallet` no longer allows overwriting files. This is a security measure + as well as prevents dangerous user mistakes. + Credits ======= diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 67c6d9ec6460..e56485e29621 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -595,7 +595,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "dumpwallet \"filename\"\n" - "\nDumps all wallet keys in a human-readable format.\n" + "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n" "\nArguments:\n" "1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n" "\nResult:\n" @@ -611,9 +611,19 @@ UniValue dumpwallet(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - std::ofstream file; boost::filesystem::path filepath = request.params[0].get_str(); filepath = boost::filesystem::absolute(filepath); + + /* Prevent arbitrary files from being overwritten. There have been reports + * that users have overwritten wallet files this way: + * https://github.com/bitcoin/bitcoin/issues/9934 + * It may also avoid other security issues. + */ + if (boost::filesystem::exists(filepath)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first"); + } + + std::ofstream file; file.open(filepath.string().c_str()); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index 569cc46e6cf9..016bd95925a9 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -7,7 +7,7 @@ import os from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import (assert_equal, assert_raises_jsonrpc) def read_dump(file_name, addrs, hd_master_addr_old): @@ -108,5 +108,8 @@ def run_test (self): assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now assert_equal(found_addr_rsv, 90*2) + # Overwriting should fail + assert_raises_jsonrpc(-8, "already exists", self.nodes[0].dumpwallet, tmpdir + "/node0/wallet.unencrypted.dump") + if __name__ == '__main__': WalletDumpTest().main () From dea3b87dd974edc18961005e66395c9238f0ab16 Mon Sep 17 00:00:00 2001 From: Donal OConnor Date: Tue, 5 Sep 2017 21:26:20 +0100 Subject: [PATCH 089/196] Add new step to clean $PATH var by removing /mnt specific Window's %PATH% paths that cause issues with the make system Github-Pull: #11437 Rebased-From: 4f890ba6bc8caba5394c7a5388d7f07959ced78b --- doc/build-windows.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/build-windows.md b/doc/build-windows.md index ca1a05dfb45d..24ca8fd41f2f 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -70,6 +70,7 @@ To build executables for Windows 64-bit, install the following dependencies: Then build using: + PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var cd depends make HOST=x86_64-w64-mingw32 cd .. @@ -85,6 +86,7 @@ To build executables for Windows 32-bit, install the following dependencies: Then build using: + PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var cd depends make HOST=i686-w64-mingw32 cd .. From 27e861a9b394857b0005347962ced92ac65e5dac Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 23 Sep 2017 10:36:23 +0200 Subject: [PATCH 090/196] net: Improve and document SOCKS code Make the SOCKS code more consistent, and document the constants used. Github-Pull: #11397 Rebased-From: 22f816ef4dd57785627d801c247714cace7fc5b5 --- src/netbase.cpp | 125 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 36 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index 05f9f6961c45..914124cb1781 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -184,6 +184,48 @@ struct timeval MillisToTimeval(int64_t nTimeout) return timeout; } +/** SOCKS version */ +enum SOCKSVersion: uint8_t { + SOCKS4 = 0x04, + SOCKS5 = 0x05 +}; + +/** Values defined for METHOD in RFC1928 */ +enum SOCKS5Method: uint8_t { + NOAUTH = 0x00, //! No authentication required + GSSAPI = 0x01, //! GSSAPI + USER_PASS = 0x02, //! Username/password + NO_ACCEPTABLE = 0xff, //! No acceptable methods +}; + +/** Values defined for CMD in RFC1928 */ +enum SOCKS5Command: uint8_t { + CONNECT = 0x01, + BIND = 0x02, + UDP_ASSOCIATE = 0x03 +}; + +/** Values defined for REP in RFC1928 */ +enum SOCKS5Reply: uint8_t { + SUCCEEDED = 0x00, //! Succeeded + GENFAILURE = 0x01, //! General failure + NOTALLOWED = 0x02, //! Connection not allowed by ruleset + NETUNREACHABLE = 0x03, //! Network unreachable + HOSTUNREACHABLE = 0x04, //! Network unreachable + CONNREFUSED = 0x05, //! Connection refused + TTLEXPIRED = 0x06, //! TTL expired + CMDUNSUPPORTED = 0x07, //! Command not supported + ATYPEUNSUPPORTED = 0x08, //! Address type not supported +}; + +/** Values defined for ATYPE in RFC1928 */ +enum SOCKS5Atyp: uint8_t { + IPV4 = 0x01, + DOMAINNAME = 0x03, + IPV6 = 0x04, +}; + +/** Status codes that can be returned by InterruptibleRecv */ enum class IntrRecvError { OK, Timeout, @@ -203,7 +245,7 @@ enum class IntrRecvError { * * @note This function requires that hSocket is in non-blocking mode. */ -static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, const SOCKET& hSocket) +static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket) { int64_t curTime = GetTimeMillis(); int64_t endTime = curTime + timeout; @@ -211,7 +253,7 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons // to break off in case of an interruption. const int64_t maxWait = 1000; while (len > 0 && curTime < endTime) { - ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first + ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first if (ret > 0) { len -= ret; data += ret; @@ -242,24 +284,35 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; } +/** Credentials for proxy authentication */ struct ProxyCredentials { std::string username; std::string password; }; -std::string Socks5ErrorString(int err) +/** Convert SOCKS5 reply to a an error message */ +std::string Socks5ErrorString(uint8_t err) { switch(err) { - case 0x01: return "general failure"; - case 0x02: return "connection not allowed"; - case 0x03: return "network unreachable"; - case 0x04: return "host unreachable"; - case 0x05: return "connection refused"; - case 0x06: return "TTL expired"; - case 0x07: return "protocol error"; - case 0x08: return "address type not supported"; - default: return "unknown"; + case SOCKS5Reply::GENFAILURE: + return "general failure"; + case SOCKS5Reply::NOTALLOWED: + return "connection not allowed"; + case SOCKS5Reply::NETUNREACHABLE: + return "network unreachable"; + case SOCKS5Reply::HOSTUNREACHABLE: + return "host unreachable"; + case SOCKS5Reply::CONNREFUSED: + return "connection refused"; + case SOCKS5Reply::TTLEXPIRED: + return "TTL expired"; + case SOCKS5Reply::CMDUNSUPPORTED: + return "protocol error"; + case SOCKS5Reply::ATYPEUNSUPPORTED: + return "address type not supported"; + default: + return "unknown"; } } @@ -274,34 +327,34 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials } // Accepted authentication methods std::vector vSocks5Init; - vSocks5Init.push_back(0x05); + vSocks5Init.push_back(SOCKSVersion::SOCKS5); if (auth) { - vSocks5Init.push_back(0x02); // # METHODS - vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED - vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929) + vSocks5Init.push_back(0x02); // Number of methods + vSocks5Init.push_back(SOCKS5Method::NOAUTH); + vSocks5Init.push_back(SOCKS5Method::USER_PASS); } else { - vSocks5Init.push_back(0x01); // # METHODS - vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED + vSocks5Init.push_back(0x01); // Number of methods + vSocks5Init.push_back(SOCKS5Method::NOAUTH); } ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vSocks5Init.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); } - char pchRet1[2]; + uint8_t pchRet1[2]; if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); return false; } - if (pchRet1[0] != 0x05) { + if (pchRet1[0] != SOCKSVersion::SOCKS5) { CloseSocket(hSocket); return error("Proxy failed to initialize"); } - if (pchRet1[1] == 0x02 && auth) { + if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) { // Perform username/password authentication (as described in RFC1929) std::vector vAuth; - vAuth.push_back(0x01); + vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation if (auth->username.size() > 255 || auth->password.size() > 255) return error("Proxy username or password too long"); vAuth.push_back(auth->username.size()); @@ -314,7 +367,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials return error("Error sending authentication to proxy"); } LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); - char pchRetA[2]; + uint8_t pchRetA[2]; if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading proxy authentication response"); @@ -323,17 +376,17 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials CloseSocket(hSocket); return error("Proxy authentication unsuccessful"); } - } else if (pchRet1[1] == 0x00) { + } else if (pchRet1[1] == SOCKS5Method::NOAUTH) { // Perform no authentication } else { CloseSocket(hSocket); return error("Proxy requested wrong authentication method %02x", pchRet1[1]); } std::vector vSocks5; - vSocks5.push_back(0x05); // VER protocol version - vSocks5.push_back(0x01); // CMD CONNECT - vSocks5.push_back(0x00); // RSV Reserved - vSocks5.push_back(0x03); // ATYP DOMAINNAME + vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version + vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT + vSocks5.push_back(0x00); // RSV Reserved must be 0 + vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); vSocks5.push_back((port >> 8) & 0xFF); @@ -343,7 +396,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials CloseSocket(hSocket); return error("Error sending to proxy"); } - char pchRet2[4]; + uint8_t pchRet2[4]; if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); if (recvr == IntrRecvError::Timeout) { @@ -355,26 +408,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials return error("Error while reading proxy response"); } } - if (pchRet2[0] != 0x05) { + if (pchRet2[0] != SOCKSVersion::SOCKS5) { CloseSocket(hSocket); return error("Proxy failed to accept request"); } - if (pchRet2[1] != 0x00) { + if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) { // Failures to connect to a peer that are not proxy errors CloseSocket(hSocket); LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1])); return false; } - if (pchRet2[2] != 0x00) { + if (pchRet2[2] != 0x00) { // Reserved field must be 0 CloseSocket(hSocket); return error("Error: malformed proxy response"); } - char pchRet3[256]; + uint8_t pchRet3[256]; switch (pchRet2[3]) { - case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; - case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break; - case 0x03: + case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; + case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break; + case SOCKS5Atyp::DOMAINNAME: { recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); if (recvr != IntrRecvError::OK) { From c94527a973611d7bc230af37d946d0c2d8b3ad13 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 2 Oct 2017 19:16:04 +0800 Subject: [PATCH 091/196] [Docs] Update Windows build instructions for using WSL and Ubuntu 17.04 Github-Pull: #11437 Rebased-From: 696ce46306e40f48dc4b2d7010812d564a43289d --- doc/build-windows.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/build-windows.md b/doc/build-windows.md index 24ca8fd41f2f..7527a418584b 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -4,10 +4,11 @@ WINDOWS BUILD NOTES Below are some notes on how to build Bitcoin Core for Windows. Most developers use cross-compilation from Ubuntu to build executables for -Windows. This is also used to build the release binaries. +Windows. Cross-compilation is also used to build the release binaries. -Currently only building on Ubuntu Trusty 14.04 is supported. -Other versions are unsupported or known to be broken (e.g. Ubuntu Xenial 16.04). +Currently only building on Ubuntu Trusty 14.04 or Ubuntu Zesty 17.04 or later is supported. +Building on Ubuntu Xenial 16.04 is known to be broken, see extensive discussion in issue [8732](https://github.com/bitcoin/bitcoin/issues/8732). +While it may be possible to do so with work arounds, it's potentially dangerous and not recommended. While there are potentially a number of ways to build on Windows (for example using msys / mingw-w64), using the Windows Subsystem For Linux is the most straightforward. If you are building with @@ -62,6 +63,14 @@ A host toolchain (`build-essential`) is necessary because some dependency packages (such as `protobuf`) need to build host utilities that are used in the build process. + +If you're building on Ubuntu 17.04 or later, run these two commands, selecting the 'posix' variant for both, +to work around issues with mingw-w64. See issue [8732](https://github.com/bitcoin/bitcoin/issues/8732) for more information. +``` +sudo update-alternatives --config x86_64-w64-mingw32-g++ +sudo update-alternatives --config x86_64-w64-mingw32-gcc +``` + ## Building for 64-bit Windows To build executables for Windows 64-bit, install the following dependencies: @@ -82,7 +91,7 @@ Then build using: To build executables for Windows 32-bit, install the following dependencies: - sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev + sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev Then build using: From 405e069d3b8c71b0f5161d9dfb2334a0bb988f2e Mon Sep 17 00:00:00 2001 From: Dusty Williams Date: Sun, 8 Oct 2017 23:18:48 -0400 Subject: [PATCH 092/196] Update importprivkey named args documentation Fixes #11462. Updated documentation for importprivkey function to use the correct name for the first argument. Also updates a call to importprivkey to use named args in functional test. Github-Pull: #11465 Rebased-From: aa57590d7c5eab1df5443e8ac9ed53ad0db46c02 --- src/wallet/rpcdump.cpp | 4 ++-- test/functional/importprunedfunds.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index e56485e29621..8e0e4a8e14ef 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -79,10 +79,10 @@ UniValue importprivkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n" + "importprivkey \"privkey\" ( \"label\" ) ( rescan )\n" "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" "\nArguments:\n" - "1. \"bitcoinprivkey\" (string, required) The private key (see dumpprivkey)\n" + "1. \"privkey\" (string, required) The private key (see dumpprivkey)\n" "2. \"label\" (string, optional, default=\"\") An optional label\n" "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" "\nNote: This call can take minutes to complete if rescan is true.\n" diff --git a/test/functional/importprunedfunds.py b/test/functional/importprunedfunds.py index 94753fe43114..198a2058aace 100755 --- a/test/functional/importprunedfunds.py +++ b/test/functional/importprunedfunds.py @@ -82,8 +82,8 @@ def run_test(self): assert_equal(balance2, Decimal('0.05')) #Import with private key with no rescan - self.nodes[1].importprivkey(address3_privkey, "add3", False) - result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3) + self.nodes[1].importprivkey(privkey=address3_privkey, label="add3", rescan=False) + self.nodes[1].importprunedfunds(rawtxn3, proof3) balance3 = self.nodes[1].getbalance("add3", 0, False) assert_equal(balance3, Decimal('0.025')) balance3 = self.nodes[1].getbalance("*", 0, True) From 20cdc2b36c40221a0eec942a1fbdf38ca7c4e005 Mon Sep 17 00:00:00 2001 From: Pedro Branco Date: Wed, 11 Oct 2017 11:12:59 +0100 Subject: [PATCH 093/196] Fix importmulti bug when importing an already imported key Github-Pull: #11483 Rebased-From: a44a215177ab55b4a3b36a7980c313e908e2dd18 --- src/wallet/rpcdump.cpp | 2 +- test/functional/importmulti.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 8e0e4a8e14ef..6c8ff7fc3b2e 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -960,7 +960,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 pwallet->SetAddressBook(vchAddress, label, "receive"); if (pwallet->HaveKey(vchAddress)) { - return false; + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); } pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp; diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index e83e85de138e..783f06f9121e 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -170,6 +170,18 @@ def run_test (self): assert_equal(address_assert['ismine'], True) assert_equal(address_assert['timestamp'], timestamp) + self.log.info("Should not import an address with private key if is already imported") + result = self.nodes[1].importmulti([{ + "scriptPubKey": { + "address": address['address'] + }, + "timestamp": "now", + "keys": [ self.nodes[0].dumpprivkey(address['address']) ] + }]) + assert_equal(result[0]['success'], False) + assert_equal(result[0]['error']['code'], -4) + assert_equal(result[0]['error']['message'], 'The wallet already contains the private key for this address or script') + # Address + Private key + watchonly self.log.info("Should not import an address with private key and with watchonly") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) From b28415baaed092724b021e8fa79dbd3f07349abf Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 18 Oct 2017 14:24:21 -0400 Subject: [PATCH 094/196] travis: move back to the minimal image The most recent update replaced the minimal image with a large one for the 'generic' image. Switching back to 'minimal' should reduce dependencies and maybe speed us up some. It should also eliminiate the need for aa2e0f09e. Github-Pull: #11521 Rebased-From: a86e81b78fc2a2ecc827a7890cba21ed229957f2 Tree-SHA512: 40f07304c60b11876a172b7ac75cb738b2da4209d54370714a6e731485643fbb33925a422accd3e065dcaa4fea84a1268f37ca0a8ee83b8cf70a71a25b59fb6b --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3220e76b063b..120d03341196 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: required dist: trusty os: linux -language: generic +language: minimal cache: directories: - depends/built From ca0f3f734c468f3c3d57f2d63c6ceb780325a2e7 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 18 Oct 2017 14:42:08 -0400 Subject: [PATCH 095/196] Revert "travis: filter out pyenv" This reverts commit aa2e0f09ec94dd0908f792ebc2249859ad174586. Github-Pull: #11521 Rebased-From: 3d1c31126b8ac9fe18d151dc4e9cf8598dd77362 Tree-SHA512: 3c42bb2715853178f1fa950d7f0926a860a81b563606633cc58a67cf7218c80dd6545b9a89db387e6352b4caed38d7dd04d50c28547c340c032e2ba2f7c79173 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 120d03341196..3bea8f36babf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,6 @@ env: before_install: - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") - - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/pyenv/d' | tr "\n" ":" | sed "s|::|:|g") install: - if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi From a2bd86a5ff1d75d85089e4ba6c908ece83451c5c Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Thu, 19 Oct 2017 12:45:11 +0200 Subject: [PATCH 096/196] Remove my testnet DNS seed as I currently don't have the capacity to keep it up to date. Github-Pull: #11527 Rebased-From: 132d3225f325b84afc282638c9e99623d249a52c Tree-SHA512: 3738afd8070fa601b5039e268088b7f3827613dbc37fae192b96b13c91f56d41fa3209533a3cad876c4e673b19015aabfce331b0b5f46a0ac518d00816e912a4 --- src/chainparams.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 2021ec51dbc8..872626f16089 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -228,7 +228,6 @@ class CTestNetParams : public CChainParams { vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true); vSeeds.emplace_back("seed.tbtc.petertodd.org", true); vSeeds.emplace_back("testnet-seed.bluematt.me", false); - vSeeds.emplace_back("testnet-seed.bitcoin.schildbach.de", false); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,111); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,196); From fdad04e6170cfab5028b64a02a091c717795c65e Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Fri, 20 Oct 2017 16:10:08 -0400 Subject: [PATCH 097/196] qa: Fix replace-by-fee race condition failures Github-Pull: #11538 Rebased-From: c96b2e4f096780c75e3fa8acba496d71322583a1 --- test/functional/replace-by-fee.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index 5e1f33991b4b..43005e98b958 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -72,6 +72,10 @@ def set_test_params(self): ["-mempoolreplacement=0"]] def run_test(self): + # Leave IBD and ensure nodes are synced + self.nodes[0].generate(1) + self.sync_all() + make_utxo(self.nodes[0], 1*COIN) self.log.info("Running test simple doublespend...") @@ -110,13 +114,18 @@ def test_simple_doublespend(self): """Simple doublespend""" tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + # make_utxo may have generated a bunch of blocks, so we need to sync + # before we can spend the coins generated, or else the resulting + # transactions might not be accepted by our peers. + self.sync_all() + tx1a = CTransaction() tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] tx1a_hex = txToHex(tx1a) tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) - self.sync_all([self.nodes]) + self.sync_all() # Should fail because we haven't changed the fee tx1b = CTransaction() From adbc9d164a52736408a146294981cdba66de9755 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Fri, 20 Oct 2017 16:24:10 -0400 Subject: [PATCH 098/196] qa: Fix race condition in sendheaders.py Github-Pull: #11538 Rebased-From: 6d51eaefe924bfaf2b0f4928dd6020023733480f --- test/functional/replace-by-fee.py | 6 ++++-- test/functional/sendheaders.py | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index 43005e98b958..1fd7c9127830 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -72,12 +72,14 @@ def set_test_params(self): ["-mempoolreplacement=0"]] def run_test(self): - # Leave IBD and ensure nodes are synced + # Leave IBD self.nodes[0].generate(1) - self.sync_all() make_utxo(self.nodes[0], 1*COIN) + # Ensure nodes are synced + self.sync_all() + self.log.info("Running test simple doublespend...") self.test_simple_doublespend() diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index fe577dc20a2d..60d107b248b8 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -225,6 +225,10 @@ def run_test(self): inv_node.wait_for_verack() test_node.wait_for_verack() + # Ensure verack's have been processed by our peer + inv_node.sync_with_ping() + test_node.sync_with_ping() + tip = int(self.nodes[0].getbestblockhash(), 16) # PART 1 From 01223a02613610c7477449929dc74db96229f13d Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 20 Oct 2017 16:35:16 -0400 Subject: [PATCH 099/196] [verify-commits] Allow revoked keys to expire Github-Pull: #11539 Rebased-From: d23be309c2c45f655d5f5405e031833fb4b6bbb4 --- contrib/verify-commits/gpg.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh index b01e2a6d39e5..abd8f5fd9fe3 100755 --- a/contrib/verify-commits/gpg.sh +++ b/contrib/verify-commits/gpg.sh @@ -46,6 +46,11 @@ for LINE in $(echo "$GPG_RES"); do REVSIG=true GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}" ;; + "[GNUPG:] EXPKEYSIG "*) + [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1 + REVSIG=true + GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}" + ;; esac done if ! $VALID; then From 265bb214ecf616a7a55fc979a227d5f215046d84 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 19 Oct 2017 22:19:57 +0200 Subject: [PATCH 100/196] Add share/rpcuser to dist. source code archive Github-Pull: #11530 Rebased-From: fa81534d068cb5479684ed9fb073dc51532b91ca Tree-SHA512: 97bc91760a3284a9b60dcde04e789aed3c83539ec6621cb38dbc5bd852bfc0cdcaffceff7ca6de0c64f00149e6774d7dd651520b39876a674f1e82efba98945d --- Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 3b62a106031c..ad522f5a56db 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,9 @@ DIST_CONTRIB = $(top_srcdir)/contrib/bitcoin-cli.bash-completion \ $(top_srcdir)/contrib/bitcoind.bash-completion \ $(top_srcdir)/contrib/init \ $(top_srcdir)/contrib/rpm +DIST_SHARE = \ + $(top_srcdir)/share/genbuild.sh \ + $(top_srcdir)/share/rpcuser BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ $(top_srcdir)/contrib/devtools/security-check.py @@ -213,7 +216,7 @@ endif dist_noinst_SCRIPTS = autogen.sh -EXTRA_DIST = $(top_srcdir)/share/genbuild.sh test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) +EXTRA_DIST = $(DIST_SHARE) test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) EXTRA_DIST += \ test/util/bitcoin-util-test.py \ From cf18f4289911c657eb876d91dee055db807870ad Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 3 Oct 2017 10:15:55 +0800 Subject: [PATCH 101/196] [Docs] Update OpenBSD Build Instructions for OpenBSD 6.2 Github-Pull: #11442 Rebased-From: 9d30f54ef1c9412f2c71b89664952dd95b6ef959 Tree-SHA512: fc7ae48126ed9569bda7d444a2464c09ba3db2398d05933df7e1ca92a0d03c2bd3c370fea977d1a3ffe70c76e9caf45ee69d41c9dc24abcc0139e4146d8c1abd --- doc/build-openbsd.md | 105 ++++++++++--------------------------------- 1 file changed, 23 insertions(+), 82 deletions(-) diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index cd800464b427..760bb69b158a 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -1,10 +1,10 @@ OpenBSD build guide ====================== -(updated for OpenBSD 6.1) +(updated for OpenBSD 6.2) This guide describes how to build bitcoind and command-line utilities on OpenBSD. -As OpenBSD is most common as a server OS, we will not bother with the GUI. +OpenBSD is most commonly used as a server OS, so this guide does not contain instructions for building the GUI. Preparation ------------- @@ -12,65 +12,33 @@ Preparation Run the following as root to install the base dependencies for building: ```bash -pkg_add gmake libtool libevent +pkg_add git gmake libevent libtool pkg_add autoconf # (select highest version, e.g. 2.69) pkg_add automake # (select highest version, e.g. 1.15) -pkg_add python # (select highest version, e.g. 3.5) +pkg_add python # (select highest version, e.g. 3.6) +pkg_add boost + +git clone https://github.com/bitcoin/bitcoin.git ``` -The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler. +See [dependencies.md](dependencies.md) for a complete overview. GCC ------- -You can install a newer version of gcc with: +The default C++ compiler that comes with OpenBSD 6.2 is g++ 4.2.1. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core because it has no C++11 support. We'll install a newer version of GCC: ```bash -pkg_add g++ # (select newest 4.x version, e.g. 4.9.3) -``` - -This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`. - -### Building boost - -Do not use `pkg_add boost`! The boost version installed thus is compiled using the `g++` compiler not `eg++`, which will result in a conflict between `/usr/local/lib/libestdc++.so.XX.0` and `/usr/lib/libstdc++.so.XX.0`, resulting in a test crash: - - test_bitcoin:/usr/lib/libstdc++.so.57.0: /usr/local/lib/libestdc++.so.17.0 : WARNING: symbol(_ZN11__gnu_debug17_S_debug_me ssagesE) size mismatch, relink your program - ... - Segmentation fault (core dumped) + pkg_add g++ + ``` -This makes it necessary to build boost, or at least the parts used by Bitcoin Core, manually: - -``` -# Pick some path to install boost to, here we create a directory within the bitcoin directory -BITCOIN_ROOT=$(pwd) -BOOST_PREFIX="${BITCOIN_ROOT}/boost" -mkdir -p $BOOST_PREFIX - -# Fetch the source and verify that it is not tampered with -curl -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2 -echo '7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 boost_1_64_0.tar.bz2' | sha256 -c -# MUST output: (SHA256) boost_1_64_0.tar.bz2: OK -tar -xjf boost_1_64_0.tar.bz2 - -# Boost 1.64 needs one small patch for OpenBSD -cd boost_1_64_0 -# Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch -patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp - -# Build w/ minimum configuration necessary for bitcoin -echo 'using gcc : : eg++ : "-fvisibility=hidden -fPIC" "" "ar" "strip" "ranlib" "" : ;' > user-config.jam -config_opts="runtime-link=shared threadapi=pthread threading=multi link=static variant=release --layout=tagged --build-type=complete --user-config=user-config.jam -sNO_BZIP2=1" -./bootstrap.sh --without-icu --with-libraries=chrono,filesystem,program_options,system,thread,test -./b2 -d2 -j2 -d1 ${config_opts} --prefix=${BOOST_PREFIX} stage -./b2 -d0 -j4 ${config_opts} --prefix=${BOOST_PREFIX} install -``` + This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`. ### Building BerkeleyDB BerkeleyDB is only necessary for the wallet functionality. To skip this, pass `--disable-wallet` to `./configure`. -See "Berkeley DB" in [build_unix.md](build_unix.md) for instructions on how to build BerkeleyDB 4.8. +See "Berkeley DB" in [build-unix.md](build-unix.md#berkeley-db) for instructions on how to build BerkeleyDB 4.8. You cannot use the BerkeleyDB library from ports, for the same reason as boost above (g++/libstd++ incompatibility). ```bash @@ -98,8 +66,8 @@ The standard ulimit restrictions in OpenBSD are very strict: data(kbytes) 1572864 -This is, unfortunately, no longer enough to compile some `.cpp` files in the project, -at least with gcc 4.9.3 (see issue https://github.com/bitcoin/bitcoin/issues/6658). +This, unfortunately, may no longer be enough to compile some `.cpp` files in the project, +at least with GCC 4.9.4 (see issue [#6658](https://github.com/bitcoin/bitcoin/issues/6658)). If your user is in the `staff` group the limit can be raised with: ulimit -d 3000000 @@ -118,59 +86,32 @@ export AUTOCONF_VERSION=2.69 # replace this with the autoconf version that you i export AUTOMAKE_VERSION=1.15 # replace this with the automake version that you installed ./autogen.sh ``` -Make sure `BDB_PREFIX` and `BOOST_PREFIX` are set to the appropriate paths from the above steps. +Make sure `BDB_PREFIX` is set to the appropriate path from the above steps. To configure with wallet: ```bash -./configure --with-gui=no --with-boost=$BOOST_PREFIX \ - CC=egcc CXX=eg++ CPP=ecpp \ +./configure --with-gui=no CC=egcc CXX=eg++ CPP=ecpp \ BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ``` To configure without wallet: ```bash -./configure --disable-wallet --with-gui=no --with-boost=$BOOST_PREFIX \ - CC=egcc CXX=eg++ CPP=ecpp +./configure --disable-wallet --with-gui=no CC=egcc CXX=eg++ CPP=ecpp ``` Build and run the tests: ```bash -gmake # can use -jX here for parallelism +gmake # use -jX here for parallelism gmake check ``` -Clang (not currently working) +Clang ------------------------------ -WARNING: This is outdated, needs to be updated for OpenBSD 6.0 and re-tried. - -Using a newer g++ results in linking the new code to a new libstdc++. -Libraries built with the old g++, will still import the old library. -This gives conflicts, necessitating rebuild of all C++ dependencies of the application. - -With clang this can - at least theoretically - be avoided because it uses the -base system's libstdc++. - ```bash -pkg_add llvm boost -``` +pkg_add llvm -```bash ./configure --disable-wallet --with-gui=no CC=clang CXX=clang++ -gmake +gmake # use -jX here for parallelism +gmake check ``` - -However, this does not appear to work. Compilation succeeds, but link fails -with many 'local symbol discarded' errors: - - local symbol 150: discarded in section `.text._ZN10tinyformat6detail14FormatIterator6finishEv' from libbitcoin_util.a(libbitcoin_util_a-random.o) - local symbol 151: discarded in section `.text._ZN10tinyformat6detail14FormatIterator21streamStateFromFormatERSoRjPKcii' from libbitcoin_util.a(libbitcoin_util_a-random.o) - local symbol 152: discarded in section `.text._ZN10tinyformat6detail12convertToIntIA13_cLb0EE6invokeERA13_Kc' from libbitcoin_util.a(libbitcoin_util_a-random.o) - -According to similar reported errors this is a binutils (ld) issue in 2.15, the -version installed by OpenBSD 5.7: - -- http://openbsd-archive.7691.n7.nabble.com/UPDATE-cppcheck-1-65-td248900.html -- https://llvm.org/bugs/show_bug.cgi?id=9758 - -There is no known workaround for this. From 7d4546f17dca84928bd2b6d1e2588b673c237321 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Thu, 26 Oct 2017 07:10:59 -0400 Subject: [PATCH 102/196] Make listsinceblock refuse unknown block hash Change suggested by Cory Fields who noticed listsinceblock would ignore invalid block hashes causing it to return a completely unfiltered list of transactions. Github-Pull: #11565 Rebased-From: 659b2061c4329472a45e913c5d45e6ab180600a3 Tree-SHA512: 2091a830b730421b49c806cb83a16c7da2ec0a7adac2bac0585324aad12a32bb99a840264c3d346937ea84786fac56e44befb6641511a417977803875efe5a21 --- doc/release-notes.md | 4 ++++ src/wallet/rpcwallet.cpp | 19 +++++++++-------- test/functional/listsinceblock.py | 35 ++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 0235e1c606ec..1bb02e376148 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -68,6 +68,10 @@ Notable changes - `dumpwallet` no longer allows overwriting files. This is a security measure as well as prevents dangerous user mistakes. +- `listsinceblock` will now throw an error if an unknown `blockhash` argument + value is passed, instead of returning a list of all wallet transactions since + the genesis block. + Credits ======= diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a6176c3485ea..6efbc23281fc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1823,19 +1823,20 @@ UniValue listsinceblock(const JSONRPCRequest& request) int target_confirms = 1; isminefilter filter = ISMINE_SPENDABLE; - if (!request.params[0].isNull()) { + if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { uint256 blockId; blockId.SetHex(request.params[0].get_str()); BlockMap::iterator it = mapBlockIndex.find(blockId); - if (it != mapBlockIndex.end()) { - paltindex = pindex = it->second; - if (chainActive[pindex->nHeight] != pindex) { - // the block being asked for is a part of a deactivated chain; - // we don't want to depend on its perceived height in the block - // chain, we want to instead use the last common ancestor - pindex = chainActive.FindFork(pindex); - } + if (it == mapBlockIndex.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + paltindex = pindex = it->second; + if (chainActive[pindex->nHeight] != pindex) { + // the block being asked for is a part of a deactivated chain; + // we don't want to depend on its perceived height in the block + // chain, we want to instead use the last common ancestor + pindex = chainActive.FindFork(pindex); } } diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py index 6f428388ecbb..67e7744bf843 100755 --- a/test/functional/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -5,7 +5,7 @@ """Test the listsincelast RPC.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import assert_equal, assert_array_result, assert_raises_rpc_error class ListSinceBlockTest (BitcoinTestFramework): def set_test_params(self): @@ -16,10 +16,43 @@ def run_test(self): self.nodes[2].generate(101) self.sync_all() + self.test_no_blockhash() + self.test_invalid_blockhash() self.test_reorg() self.test_double_spend() self.test_double_send() + def test_no_blockhash(self): + txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1) + blockhash, = self.nodes[2].generate(1) + self.sync_all() + + txs = self.nodes[0].listtransactions() + assert_array_result(txs, {"txid": txid}, { + "category": "receive", + "amount": 1, + "blockhash": blockhash, + "confirmations": 1, + }) + assert_equal( + self.nodes[0].listsinceblock(), + {"lastblock": blockhash, + "removed": [], + "transactions": txs}) + assert_equal( + self.nodes[0].listsinceblock(""), + {"lastblock": blockhash, + "removed": [], + "transactions": txs}) + + def test_invalid_blockhash(self): + assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, + "42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4") + assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, + "0000000000000000000000000000000000000000000000000000000000000000") + assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, + "invalid-hex") + def test_reorg(self): ''' `listsinceblock` did not behave correctly when handed a block that was From 5b728c8e98a4d3d72b1ca5f6ac287b453b0fb5d6 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 12 Jul 2017 10:29:02 -0400 Subject: [PATCH 103/196] [tests] remove direct testing on JSONRPCException from individual test cases Github-Pull: #10853 Rebased-From: 5864e9c1611e6034a8d49b78231abe6bfade686d --- test/functional/import-rescan.py | 30 +++++++++++--------------- test/functional/importmulti.py | 4 ++-- test/functional/segwit.py | 6 +----- test/functional/signrawtransactions.py | 2 +- test/functional/test_framework/util.py | 10 ++++++++- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index 02d7428120be..c7eb07ab12d7 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -19,9 +19,8 @@ happened previously. """ -from test_framework.authproxy import JSONRPCException from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (connect_nodes, sync_blocks, assert_equal, set_node_times) +from test_framework.util import (assert_raises_jsonrpc, connect_nodes, sync_blocks, assert_equal, set_node_times) import collections import enum @@ -35,21 +34,26 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): """Helper for importing one key and verifying scanned transactions.""" + def try_rpc(self, func, *args, **kwargs): + if self.expect_disabled: + assert_raises_jsonrpc(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs) + else: + return func(*args, **kwargs) + def do_import(self, timestamp): """Call one key import RPC.""" if self.call == Call.single: if self.data == Data.address: - response, error = try_rpc(self.node.importaddress, self.address["address"], self.label, - self.rescan == Rescan.yes) + response = self.try_rpc(self.node.importaddress, self.address["address"], self.label, + self.rescan == Rescan.yes) elif self.data == Data.pub: - response, error = try_rpc(self.node.importpubkey, self.address["pubkey"], self.label, - self.rescan == Rescan.yes) + response = self.try_rpc(self.node.importpubkey, self.address["pubkey"], self.label, + self.rescan == Rescan.yes) elif self.data == Data.priv: - response, error = try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes) + response = self.try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes) assert_equal(response, None) - assert_equal(error, {'message': 'Rescan is disabled in pruned mode', - 'code': -4} if self.expect_disabled else None) + elif self.call == Call.multi: response = self.node.importmulti([{ "scriptPubKey": { @@ -180,13 +184,5 @@ def run_test(self): else: variant.check() - -def try_rpc(func, *args, **kwargs): - try: - return func(*args, **kwargs), None - except JSONRPCException as e: - return None, e.error - - if __name__ == "__main__": ImportRescanTest().main() diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index 6907d6407052..f16c9ab97aad 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -448,11 +448,11 @@ def run_test (self): # Bad or missing timestamps self.log.info("Should throw on invalid or missing timestamp values") - assert_raises_message(JSONRPCException, 'Missing required timestamp field for key', + assert_raises_jsonrpc(-3, 'Missing required timestamp field for key', self.nodes[1].importmulti, [{ "scriptPubKey": address['scriptPubKey'], }]) - assert_raises_message(JSONRPCException, 'Expected number or "now" timestamp value for key. got type string', + assert_raises_jsonrpc(-3, 'Expected number or "now" timestamp value for key. got type string', self.nodes[1].importmulti, [{ "scriptPubKey": address['scriptPubKey'], "timestamp": "", diff --git a/test/functional/segwit.py b/test/functional/segwit.py index c08fbd3e7751..7571bd1a37bc 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -443,11 +443,7 @@ def run_test(self): for i in importlist: # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC # exceptions and continue. - try: - self.nodes[0].importaddress(i,"",False,True) - except JSONRPCException as exp: - assert_equal(exp.error["message"], "The wallet already contains the private key for this address or script") - assert_equal(exp.error["code"], -4) + try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True) self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py index b47ef939558a..00a58e108e76 100755 --- a/test/functional/signrawtransactions.py +++ b/test/functional/signrawtransactions.py @@ -82,7 +82,7 @@ def script_verification_error_test(self): assert_equal(decodedRawTx["vin"][i]["vout"], inp["vout"]) # Make sure decoderawtransaction throws if there is extra data - assert_raises(JSONRPCException, self.nodes[0].decoderawtransaction, rawTx + "00") + assert_raises_jsonrpc(-22, "TX decode failed", self.nodes[0].decoderawtransaction, rawTx + "00") rawTxSigned = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 64966adb9738..44d7e04a8980 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -99,6 +99,13 @@ def assert_raises_jsonrpc(code, message, fun, *args, **kwds): args*: positional arguments for the function. kwds**: named arguments for the function. """ + assert try_rpc(code, message, fun, *args, **kwds), "No exception raised" + +def try_rpc(code, message, fun, *args, **kwds): + """Tries to run an rpc command. + + Test against error code and message if the rpc fails. + Returns whether a JSONRPCException was raised.""" try: fun(*args, **kwds) except JSONRPCException as e: @@ -107,10 +114,11 @@ def assert_raises_jsonrpc(code, message, fun, *args, **kwds): raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"]) if (message is not None) and (message not in e.error['message']): raise AssertionError("Expected substring not found:" + e.error['message']) + return True except Exception as e: raise AssertionError("Unexpected exception raised: " + type(e).__name__) else: - raise AssertionError("No exception raised") + return False def assert_is_hex_string(string): try: From 623de0acbb7a586adba8d1f9a64c77fabb0e98a4 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 12 Jul 2017 10:29:21 -0400 Subject: [PATCH 104/196] [tests] do not allow assert_raises_message to be called with JSONRPCException Github-Pull: #10853 Rebased-From: 677d893ff758b61f66203730da224bd7ef8f0b43 --- test/functional/test_framework/util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 44d7e04a8980..ed35bf576eb8 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -51,6 +51,8 @@ def assert_raises(exc, fun, *args, **kwds): def assert_raises_message(exc, message, fun, *args, **kwds): try: fun(*args, **kwds) + except JSONRPCException: + raise AssertionError("Use assert_raises_jsonrpc() to test RPC failures") 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']) From d94fc336c47b5fd0f42217806faad1aa201b9d63 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 1 Nov 2017 10:41:28 -0400 Subject: [PATCH 105/196] scripted-diff: rename assert_raises_jsonrpc to assert_raises_rpc error -BEGIN VERIFY SCRIPT- sed -i 's/assert_raises_jsonrpc/assert_raises_rpc_error/g' test/functional/*py test/functional/test_framework/*py -END VERIFY SCRIPT- Github-Pull: #10853 Rebased-From: 47ba8cf71e9a3a6f7452488fc9ab3b350f0fae36 --- test/functional/bip68-sequence.py | 10 +++---- test/functional/blockchain.py | 4 +-- test/functional/bumpfee.py | 14 +++++----- test/functional/disablewallet.py | 4 +-- test/functional/disconnect_ban.py | 12 ++++----- test/functional/fundrawtransaction.py | 12 ++++----- test/functional/import-rescan.py | 4 +-- test/functional/importmulti.py | 4 +-- test/functional/importprunedfunds.py | 4 +-- test/functional/keypool.py | 8 +++--- test/functional/mempool_packages.py | 4 +-- test/functional/mempool_reorg.py | 4 +-- test/functional/mempool_spendcoinbase.py | 2 +- test/functional/merkle_blocks.py | 8 +++--- test/functional/mining.py | 10 +++---- test/functional/multiwallet.py | 6 ++--- test/functional/net.py | 4 +-- test/functional/nulldummy.py | 6 ++--- test/functional/p2p-acceptblock.py | 2 +- test/functional/prioritise_transaction.py | 2 +- test/functional/pruning.py | 8 +++--- test/functional/rawtransactions.py | 12 ++++----- test/functional/replace-by-fee.py | 30 ++++++++++----------- test/functional/resendwallettransactions.py | 4 +-- test/functional/rpcbind_test.py | 2 +- test/functional/rpcnamedargs.py | 4 +-- test/functional/segwit.py | 8 +++--- test/functional/signrawtransactions.py | 2 +- test/functional/test_framework/util.py | 4 +-- test/functional/wallet-dump.py | 4 +-- test/functional/wallet-encryption.py | 12 ++++----- test/functional/wallet.py | 8 +++--- test/functional/zapwallettxes.py | 4 +-- 33 files changed, 113 insertions(+), 113 deletions(-) diff --git a/test/functional/bip68-sequence.py b/test/functional/bip68-sequence.py index 1391b9ed466f..b3b5adf425c1 100755 --- a/test/functional/bip68-sequence.py +++ b/test/functional/bip68-sequence.py @@ -83,7 +83,7 @@ def test_disable_flag(self): tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))] tx2.rehash() - assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2)) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2)) # Setting the version back down to 1 should disable the sequence lock, # so this should be accepted. @@ -180,7 +180,7 @@ def test_sequence_lock_confirmed_inputs(self): if (using_sequence_locks and not should_pass): # This transaction should be rejected - assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx) else: # This raw transaction should be accepted self.nodes[0].sendrawtransaction(rawtx) @@ -227,7 +227,7 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock): if (orig_tx.hash in node.getrawmempool()): # sendrawtransaction should fail if the tx is in the mempool - assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx)) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx)) else: # sendrawtransaction should succeed if the tx is not in the mempool node.sendrawtransaction(ToHex(tx)) @@ -280,7 +280,7 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock): tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN) raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))["hex"] - assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5) # Test mempool-BIP68 consistency after reorg # @@ -353,7 +353,7 @@ def test_bip68_not_consensus(self): tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] tx3.rehash() - assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3)) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3)) # make a block that violates bip68; ensure that the tip updates tip = int(self.nodes[0].getbestblockhash(), 16) diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 50be9262e4f9..4c2997f8bdfd 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -25,7 +25,7 @@ from test_framework.util import ( assert_equal, assert_raises, - assert_raises_jsonrpc, + assert_raises_rpc_error, assert_is_hex_string, assert_is_hash_string, ) @@ -96,7 +96,7 @@ def _test_gettxoutsetinfo(self): def _test_getblockheader(self): node = self.nodes[0] - assert_raises_jsonrpc(-5, "Block not found", + assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "nonsense") besthash = node.getbestblockhash() diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index ede0df29d8d7..c2aa75209cae 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -133,7 +133,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address): def test_nonrbf_bumpfee_fails(peer_node, dest_address): # cannot replace a non RBF transaction (from node which did not enable RBF) not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000")) - assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) + assert_raises_rpc_error(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): @@ -153,7 +153,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): signedtx = rbf_node.signrawtransaction(rawtx) signedtx = peer_node.signrawtransaction(signedtx["hex"]) rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) - assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet", + assert_raises_rpc_error(-4, "Transaction contains inputs that don't belong to this wallet", rbf_node.bumpfee, rbfid) @@ -164,7 +164,7 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address) tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000}) tx = rbf_node.signrawtransaction(tx) txid = rbf_node.sendrawtransaction(tx["hex"]) - assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) + assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) def test_small_output_fails(rbf_node, dest_address): @@ -173,7 +173,7 @@ def test_small_output_fails(rbf_node, dest_address): rbf_node.bumpfee(rbfid, {"totalFee": 50000}) rbfid = spend_one_input(rbf_node, dest_address) - assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001}) + assert_raises_rpc_error(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001}) def test_dust_to_fee(rbf_node, dest_address): @@ -205,7 +205,7 @@ def test_rebumping(rbf_node, dest_address): # check that re-bumping the original tx fails, but bumping the bumper succeeds rbfid = spend_one_input(rbf_node, dest_address) bumped = rbf_node.bumpfee(rbfid, {"totalFee": 2000}) - assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000}) + assert_raises_rpc_error(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000}) rbf_node.bumpfee(bumped["txid"], {"totalFee": 3000}) @@ -213,7 +213,7 @@ def test_rebumping_not_replaceable(rbf_node, dest_address): # check that re-bumping a non-replaceable bump tx fails rbfid = spend_one_input(rbf_node, dest_address) bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False}) - assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], + assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], {"totalFee": 20000}) @@ -264,7 +264,7 @@ def test_bumpfee_metadata(rbf_node, dest_address): def test_locked_wallet_fails(rbf_node, dest_address): rbfid = spend_one_input(rbf_node, dest_address) rbf_node.walletlock() - assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.", + assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.", rbf_node.bumpfee, rbfid) diff --git a/test/functional/disablewallet.py b/test/functional/disablewallet.py index c1d37963bc60..c75ef9b9f12d 100755 --- a/test/functional/disablewallet.py +++ b/test/functional/disablewallet.py @@ -19,7 +19,7 @@ def set_test_params(self): def run_test (self): # Make sure wallet is really disabled - assert_raises_jsonrpc(-32601, 'Method not found', self.nodes[0].getwalletinfo) + assert_raises_rpc_error(-32601, 'Method not found', self.nodes[0].getwalletinfo) x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') assert(x['isvalid'] == False) x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') @@ -28,7 +28,7 @@ def run_test (self): # Checking mining to an address without a wallet. Generating to a valid address should succeed # but generating to an invalid address will fail. self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') - assert_raises_jsonrpc(-5, "Invalid address", self.nodes[0].generatetoaddress, 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') + assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].generatetoaddress, 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') if __name__ == '__main__': DisableWalletTest ().main () diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index a6445b9b35e4..59655d37fbe2 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -8,7 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_raises_jsonrpc, + assert_raises_rpc_error, connect_nodes_bi, wait_until, ) @@ -34,14 +34,14 @@ def run_test(self): self.log.info("setban: fail to ban an already banned subnet") assert_equal(len(self.nodes[1].listbanned()), 1) - assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add") + assert_raises_rpc_error(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add") self.log.info("setban: fail to ban an invalid subnet") - assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add") + assert_raises_rpc_error(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add") assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 self.log.info("setban remove: fail to unban a non-banned subnet") - assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove") + assert_raises_rpc_error(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[1].listbanned()), 1) self.log.info("setban remove: successfully unban subnet") @@ -81,10 +81,10 @@ def run_test(self): self.log.info("disconnectnode: fail to disconnect when calling with address and nodeid") address1 = self.nodes[0].getpeerinfo()[0]['addr'] node1 = self.nodes[0].getpeerinfo()[0]['addr'] - assert_raises_jsonrpc(-32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1) + assert_raises_rpc_error(-32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1) self.log.info("disconnectnode: fail to disconnect when calling with junk address") - assert_raises_jsonrpc(-29, "Node not found in connected nodes", self.nodes[0].disconnectnode, address="221B Baker Street") + assert_raises_rpc_error(-29, "Node not found in connected nodes", self.nodes[0].disconnectnode, address="221B Baker Street") self.log.info("disconnectnode: successfully disconnect node by address") address1 = self.nodes[0].getpeerinfo()[0]['addr'] diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 42d95dd5204e..1c4f269ec0e2 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -179,7 +179,7 @@ def run_test(self): dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) - assert_raises_jsonrpc(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'}) + assert_raises_rpc_error(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'}) ############################################################ # test a fundrawtransaction with an invalid change address # @@ -192,7 +192,7 @@ def run_test(self): dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) - assert_raises_jsonrpc(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'}) + assert_raises_rpc_error(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'}) ############################################################ # test a fundrawtransaction with a provided change address # @@ -206,7 +206,7 @@ def run_test(self): assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) change = self.nodes[2].getnewaddress() - assert_raises_jsonrpc(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2}) + assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0}) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) out = dec_tx['vout'][0] @@ -315,7 +315,7 @@ def run_test(self): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) - assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx) + assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx) ############################################################ #compare fee of a standard pubkeyhash transaction @@ -470,14 +470,14 @@ def run_test(self): 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 - assert_raises_jsonrpc(-4, "Keypool ran out, please call keypoolrefill first", self.nodes[1].fundrawtransaction, rawtx) + assert_raises_rpc_error(-4, "Keypool ran out, please call keypoolrefill first", self.nodes[1].fundrawtransaction, rawtx) #refill the keypool self.nodes[1].walletpassphrase("test", 100) self.nodes[1].keypoolrefill(8) #need to refill the keypool to get an internal change address self.nodes[1].walletlock() - assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2) + assert_raises_rpc_error(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2) oldBalance = self.nodes[0].getbalance() diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index c7eb07ab12d7..955554204d81 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -20,7 +20,7 @@ """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_raises_jsonrpc, connect_nodes, sync_blocks, assert_equal, set_node_times) +from test_framework.util import (assert_raises_rpc_error, connect_nodes, sync_blocks, assert_equal, set_node_times) import collections import enum @@ -36,7 +36,7 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): def try_rpc(self, func, *args, **kwargs): if self.expect_disabled: - assert_raises_jsonrpc(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs) + assert_raises_rpc_error(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs) else: return func(*args, **kwargs) diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index f16c9ab97aad..324f6458e305 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -448,11 +448,11 @@ def run_test (self): # Bad or missing timestamps self.log.info("Should throw on invalid or missing timestamp values") - assert_raises_jsonrpc(-3, 'Missing required timestamp field for key', + assert_raises_rpc_error(-3, 'Missing required timestamp field for key', self.nodes[1].importmulti, [{ "scriptPubKey": address['scriptPubKey'], }]) - assert_raises_jsonrpc(-3, 'Expected number or "now" timestamp value for key. got type string', + assert_raises_rpc_error(-3, 'Expected number or "now" timestamp value for key. got type string', self.nodes[1].importmulti, [{ "scriptPubKey": address['scriptPubKey'], "timestamp": "", diff --git a/test/functional/importprunedfunds.py b/test/functional/importprunedfunds.py index 996ff96cc38b..c445b66df3ac 100755 --- a/test/functional/importprunedfunds.py +++ b/test/functional/importprunedfunds.py @@ -67,7 +67,7 @@ def run_test(self): self.sync_all() #Import with no affiliated address - assert_raises_jsonrpc(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1) + assert_raises_rpc_error(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1) balance1 = self.nodes[1].getbalance("", 0, True) assert_equal(balance1, Decimal(0)) @@ -98,7 +98,7 @@ def run_test(self): assert_equal(address_info['ismine'], True) #Remove transactions - assert_raises_jsonrpc(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1) + assert_raises_rpc_error(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1) balance1 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance1, Decimal('0.075')) diff --git a/test/functional/keypool.py b/test/functional/keypool.py index b823ca63bb80..f2701c36bdca 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -28,7 +28,7 @@ def run_test(self): wallet_info = nodes[0].getwalletinfo() assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid']) assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid']) - assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) + assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) # put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min) nodes[0].walletpassphrase('test', 12000) @@ -47,7 +47,7 @@ def run_test(self): nodes[0].getrawchangeaddress() addr = set() # the next one should fail - assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].getrawchangeaddress) + assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getrawchangeaddress) # drain the external keys addr.add(nodes[0].getnewaddress()) @@ -58,7 +58,7 @@ def run_test(self): addr.add(nodes[0].getnewaddress()) assert(len(addr) == 6) # the next one should fail - assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) + assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) # refill keypool with three new addresses nodes[0].walletpassphrase('test', 1) @@ -72,7 +72,7 @@ def run_test(self): nodes[0].generate(1) nodes[0].generate(1) nodes[0].generate(1) - assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].generate, 1) + assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].generate, 1) nodes[0].walletpassphrase('test', 100) nodes[0].keypoolrefill(100) diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index 2dedadf8ce4a..6d3849bf57eb 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -115,7 +115,7 @@ def run_test(self): assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000) # Adding one more transaction on to the chain should fail. - assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1) + assert_raises_rpc_error(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1) # Check that prioritising a tx before it's added to the mempool works # First clear the mempool by mining a block. @@ -167,7 +167,7 @@ def run_test(self): # Sending one more chained transaction will fail utxo = transaction_package.pop(0) - assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) + assert_raises_rpc_error(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) # TODO: check that node1's mempool is as expected diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 7dfddd3230df..2803371f5b60 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -50,14 +50,14 @@ def run_test(self): timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000" timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"] # This will raise an exception because the timelock transaction is too immature to spend - assert_raises_jsonrpc(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx) + assert_raises_rpc_error(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx) # Broadcast and mine spend_102 and 103: spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) self.nodes[0].generate(1) # Time-locked transaction is still too immature to spend - assert_raises_jsonrpc(-26,'non-final', self.nodes[0].sendrawtransaction, timelock_tx) + assert_raises_rpc_error(-26,'non-final', self.nodes[0].sendrawtransaction, timelock_tx) # Create 102_1 and 103_1: spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98) diff --git a/test/functional/mempool_spendcoinbase.py b/test/functional/mempool_spendcoinbase.py index 58ccd3e3734f..6e8a635a7654 100755 --- a/test/functional/mempool_spendcoinbase.py +++ b/test/functional/mempool_spendcoinbase.py @@ -36,7 +36,7 @@ def run_test(self): spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0]) # coinbase at height 102 should be too immature to spend - assert_raises_jsonrpc(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1]) + assert_raises_rpc_error(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1]) # mempool should have just spend_101: assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ]) diff --git a/test/functional/merkle_blocks.py b/test/functional/merkle_blocks.py index a58334b2a540..b3989a4c5488 100755 --- a/test/functional/merkle_blocks.py +++ b/test/functional/merkle_blocks.py @@ -38,7 +38,7 @@ def run_test(self): tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 49.99}) txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"]) # This will raise an exception because the transaction is not yet in a block - assert_raises_jsonrpc(-5, "Transaction not yet in block", self.nodes[0].gettxoutproof, [txid1]) + assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].gettxoutproof, [txid1]) self.nodes[0].generate(1) blockhash = self.nodes[0].getblockhash(chain_height + 1) @@ -63,11 +63,11 @@ def run_test(self): txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2 # We can't find the block from a fully-spent tx - assert_raises_jsonrpc(-5, "Transaction not yet in block", self.nodes[2].gettxoutproof, [txid_spent]) + assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[2].gettxoutproof, [txid_spent]) # We can get the proof if we specify the block assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent]) # We can't get the proof if we specify a non-existent block - assert_raises_jsonrpc(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000") + assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000") # We can get the proof if the transaction is unspent assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent]) # We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter. @@ -76,7 +76,7 @@ def run_test(self): # We can always get a proof if we have a -txindex assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent]) # We can't get a proof if we specify transactions from different blocks - assert_raises_jsonrpc(-5, "Not all transactions found in specified or retrieved block", self.nodes[2].gettxoutproof, [txid1, txid3]) + assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[2].gettxoutproof, [txid1, txid3]) if __name__ == '__main__': diff --git a/test/functional/mining.py b/test/functional/mining.py index 93f98388960f..085bdb568bdc 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -15,7 +15,7 @@ from test_framework.blocktools import create_coinbase from test_framework.mininode import CBlock from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_jsonrpc +from test_framework.util import assert_equal, assert_raises_rpc_error def b2x(b): return b2a_hex(b).decode('ascii') @@ -69,7 +69,7 @@ def run_test(self): assert_template(node, block, None) self.log.info("submitblock: Test block decode failure") - assert_raises_jsonrpc(-22, "Block decode failed", node.submitblock, b2x(block.serialize()[:-15])) + assert_raises_rpc_error(-22, "Block decode failed", node.submitblock, b2x(block.serialize()[:-15])) self.log.info("getblocktemplate: Test bad input hash for coinbase transaction") bad_block = copy.deepcopy(block) @@ -78,10 +78,10 @@ def run_test(self): assert_template(node, bad_block, 'bad-cb-missing') self.log.info("submitblock: Test invalid coinbase transaction") - assert_raises_jsonrpc(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize())) + assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize())) self.log.info("getblocktemplate: Test truncated final transaction") - assert_raises_jsonrpc(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal'}) + assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal'}) self.log.info("getblocktemplate: Test duplicate transaction") bad_block = copy.deepcopy(block) @@ -108,7 +108,7 @@ def run_test(self): bad_block_sn = bytearray(block.serialize()) assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1) bad_block_sn[TX_COUNT_OFFSET] += 1 - assert_raises_jsonrpc(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal'}) + assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal'}) self.log.info("getblocktemplate: Test bad bits") bad_block = copy.deepcopy(block) diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index b4e15a332219..6adcc1fd8828 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -9,7 +9,7 @@ import os from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_jsonrpc +from test_framework.util import assert_equal, assert_raises_rpc_error class MultiWalletTest(BitcoinTestFramework): def set_test_params(self): @@ -43,10 +43,10 @@ def run_test(self): w1.generate(1) # accessing invalid wallet fails - assert_raises_jsonrpc(-18, "Requested wallet does not exist or is not loaded", wallet_bad.getwalletinfo) + assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", wallet_bad.getwalletinfo) # accessing wallet RPC without using wallet endpoint fails - assert_raises_jsonrpc(-19, "Wallet file not specified", self.nodes[0].getwalletinfo) + assert_raises_rpc_error(-19, "Wallet file not specified", self.nodes[0].getwalletinfo) # check w1 wallet balance w1_info = w1.getwalletinfo() diff --git a/test/functional/net.py b/test/functional/net.py index 37ea6824d570..61a5e1f2e9d4 100755 --- a/test/functional/net.py +++ b/test/functional/net.py @@ -12,7 +12,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_raises_jsonrpc, + assert_raises_rpc_error, connect_nodes_bi, p2p_port, ) @@ -84,7 +84,7 @@ def _test_getaddednodeinfo(self): assert_equal(len(added_nodes), 1) assert_equal(added_nodes[0]['addednode'], ip_port) # check that a non-existant node returns an error - assert_raises_jsonrpc(-24, "Node has not been added", + assert_raises_rpc_error(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1') def _test_getpeerinfo(self): diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py index 60d0d876df70..91c455065382 100755 --- a/test/functional/nulldummy.py +++ b/test/functional/nulldummy.py @@ -71,7 +71,7 @@ def run_test(self): self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation") test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 47) trueDummy(test2tx) - assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True) + assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True) self.log.info("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]") self.block_submit(self.nodes[0], [test2tx], False, True) @@ -80,14 +80,14 @@ def run_test(self): test4tx = self.create_transaction(self.nodes[0], test2tx.hash, self.address, 46) test6txs=[CTransaction(test4tx)] trueDummy(test4tx) - assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True) + assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True) self.block_submit(self.nodes[0], [test4tx]) self.log.info("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation") test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48) test6txs.append(CTransaction(test5tx)) test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01' - assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True) + assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True) self.block_submit(self.nodes[0], [test5tx], True) self.log.info("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]") diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 293bc055393e..5b6429b41019 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -171,7 +171,7 @@ def run_test(self): # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead for x in all_blocks[:-1]: self.nodes[0].getblock(x.hash) - assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash) + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash) headers_message.headers.pop() # Ensure the last block is unrequested white_node.send_message(headers_message) # Send headers leading to tip diff --git a/test/functional/prioritise_transaction.py b/test/functional/prioritise_transaction.py index 7ad368acd4b8..bb56db9b40f3 100755 --- a/test/functional/prioritise_transaction.py +++ b/test/functional/prioritise_transaction.py @@ -101,7 +101,7 @@ def run_test(self): tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"] # This will raise an exception due to min relay fee not being met - assert_raises_jsonrpc(-26, "66: min relay fee not met", self.nodes[0].sendrawtransaction, tx_hex) + assert_raises_rpc_error(-26, "66: min relay fee not met", self.nodes[0].sendrawtransaction, tx_hex) assert(tx_id not in self.nodes[0].getrawmempool()) # This is a less than 1000-byte transaction, so just set the fee diff --git a/test/functional/pruning.py b/test/functional/pruning.py index a4afbd46d73f..1b0f0ba1cdaf 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -185,7 +185,7 @@ def reorg_test(self): def reorg_back(self): # Verify that a block on the old main chain fork has been pruned away - assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash) + assert_raises_rpc_error(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash) self.log.info("Will need to redownload block %d" % self.forkheight) # Verify that we have enough history to reorg back to the fork point @@ -232,7 +232,7 @@ def manual_test(self, node_number, use_timestamp): self.start_node(node_number) node = self.nodes[node_number] assert_equal(node.getblockcount(), 995) - assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500) + assert_raises_rpc_error(-1, "not in prune mode", node.pruneblockchain, 500) # now re-start in manual pruning mode self.stop_node(node_number) @@ -265,14 +265,14 @@ def has_block(index): return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index)) # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000) - assert_raises_jsonrpc(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500)) + assert_raises_rpc_error(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500)) # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight) node.generate(6) assert_equal(node.getblockchaininfo()["blocks"], 1001) # negative heights should raise an exception - assert_raises_jsonrpc(-8, "Negative", node.pruneblockchain, -10) + assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10) # height=100 too low to prune first block file so this is a no-op prune(100) diff --git a/test/functional/rawtransactions.py b/test/functional/rawtransactions.py index 51dda09ac415..ec9467eb445a 100755 --- a/test/functional/rawtransactions.py +++ b/test/functional/rawtransactions.py @@ -48,7 +48,7 @@ def run_test(self): rawtx = self.nodes[2].signrawtransaction(rawtx) # This will raise an exception since there are missing inputs - assert_raises_jsonrpc(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) + assert_raises_rpc_error(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) ######################### # RAW TX MULTISIG TESTS # @@ -190,13 +190,13 @@ def run_test(self): assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex']) # 6. invalid parameters - supply txid and string "Flase" - assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase") + assert_raises_rpc_error(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase") # 7. invalid parameters - supply txid and empty array - assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, []) + assert_raises_rpc_error(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, []) # 8. invalid parameters - supply txid and empty dict - assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {}) + assert_raises_rpc_error(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {}) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] outputs = { self.nodes[0].getnewaddress() : 1 } @@ -207,12 +207,12 @@ def run_test(self): # 9. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}] outputs = { self.nodes[0].getnewaddress() : 1 } - assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) + assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) # 10. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}] outputs = { self.nodes[0].getnewaddress() : 1 } - assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) + assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}] outputs = { self.nodes[0].getnewaddress() : 1 } diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index 1fd7c9127830..4ef10e6b3651 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -136,9 +136,9 @@ def test_simple_doublespend(self): tx1b_hex = txToHex(tx1b) # This will raise an exception due to insufficient fee - assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) + assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) # This will raise an exception due to transaction replacement being disabled - assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) + assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) # Extra 0.1 BTC fee tx1b = CTransaction() @@ -146,7 +146,7 @@ def test_simple_doublespend(self): tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] tx1b_hex = txToHex(tx1b) # Replacement still disabled even with "enough fee" - assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) + assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) # Works when enabled tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) @@ -189,7 +189,7 @@ def test_doublespend_chain(self): dbl_tx_hex = txToHex(dbl_tx) # This will raise an exception due to insufficient fee - assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) + assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) # Accepted with sufficient fee dbl_tx = CTransaction() @@ -250,7 +250,7 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))] dbl_tx_hex = txToHex(dbl_tx) # This will raise an exception due to insufficient fee - assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) + assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) # 1 BTC fee is enough dbl_tx = CTransaction() @@ -278,7 +278,7 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))] dbl_tx_hex = txToHex(dbl_tx) # This will raise an exception - assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) + assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) for tx in tree_txs: tx.rehash() @@ -302,7 +302,7 @@ def test_replacement_feeperkb(self): tx1b_hex = txToHex(tx1b) # This will raise an exception due to insufficient fee - assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) + assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) def test_spends_of_conflicting_outputs(self): """Replacements that spend conflicting tx outputs are rejected""" @@ -325,7 +325,7 @@ def test_spends_of_conflicting_outputs(self): tx2_hex = txToHex(tx2) # This will raise an exception - assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True) + assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True) # Spend tx1a's output to test the indirect case. tx1b = CTransaction() @@ -342,7 +342,7 @@ def test_spends_of_conflicting_outputs(self): tx2_hex = txToHex(tx2) # This will raise an exception - assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True) + assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True) def test_new_unconfirmed_inputs(self): """Replacements that add new unconfirmed inputs are rejected""" @@ -361,7 +361,7 @@ def test_new_unconfirmed_inputs(self): tx2_hex = txToHex(tx2) # This will raise an exception - assert_raises_jsonrpc(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, True) + assert_raises_rpc_error(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, True) def test_too_many_replacements(self): """Replacements that evict too many transactions are rejected""" @@ -407,7 +407,7 @@ def test_too_many_replacements(self): double_tx_hex = txToHex(double_tx) # This will raise an exception - assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, True) + assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, True) # If we remove an input, it should pass double_tx = CTransaction() @@ -434,7 +434,7 @@ def test_opt_in(self): tx1b_hex = txToHex(tx1b) # This will raise an exception - assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, True) + assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, True) tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) @@ -452,7 +452,7 @@ def test_opt_in(self): tx2b_hex = txToHex(tx2b) # This will raise an exception - assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, True) + assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, True) # Now create a new transaction that spends from tx1a and tx2a # opt-in on one of the inputs @@ -504,7 +504,7 @@ def test_prioritised_transactions(self): tx1b_hex = txToHex(tx1b) # Verify tx1b cannot replace tx1a. - assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) + assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) # Use prioritisetransaction to set tx1a's fee to 0. self.nodes[0].prioritisetransaction(txid=tx1a_txid, fee_delta=int(-0.1*COIN)) @@ -531,7 +531,7 @@ def test_prioritised_transactions(self): tx2b_hex = txToHex(tx2b) # Verify tx2b cannot replace tx2a. - assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True) + assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True) # Now prioritise tx2b to have a higher modified fee self.nodes[0].prioritisetransaction(txid=tx2b.hash, fee_delta=int(0.1*COIN)) diff --git a/test/functional/resendwallettransactions.py b/test/functional/resendwallettransactions.py index d6ba5913912d..d959bb4c3836 100755 --- a/test/functional/resendwallettransactions.py +++ b/test/functional/resendwallettransactions.py @@ -5,7 +5,7 @@ """Test resendwallettransactions RPC.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_jsonrpc +from test_framework.util import assert_equal, assert_raises_rpc_error class ResendWalletTransactionsTest(BitcoinTestFramework): def set_test_params(self): @@ -14,7 +14,7 @@ def set_test_params(self): def run_test(self): # Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled. - assert_raises_jsonrpc(-4, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast", self.nodes[0].resendwallettransactions) + assert_raises_rpc_error(-4, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast", self.nodes[0].resendwallettransactions) # Should return an empty array if there aren't unconfirmed wallet transactions. self.stop_node(0) diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index 0cf64beebd40..0e8c3fa209ee 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -101,7 +101,7 @@ def run_test(self): # Check that with invalid rpcallowip, we are denied self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport) - assert_raises_jsonrpc(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], non_loopback_ip, defaultport) + assert_raises_rpc_error(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], non_loopback_ip, defaultport) if __name__ == '__main__': RPCBindTest().main() diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py index da61cc66e685..0fb0a62afd02 100755 --- a/test/functional/rpcnamedargs.py +++ b/test/functional/rpcnamedargs.py @@ -7,7 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_raises_jsonrpc, + assert_raises_rpc_error, ) class NamedArgumentTest(BitcoinTestFramework): @@ -19,7 +19,7 @@ def run_test(self): h = node.help(command='getinfo') assert(h.startswith('getinfo\n')) - assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getinfo') + assert_raises_rpc_error(-8, 'Unknown named parameter', node.help, random='getinfo') h = node.getblockhash(height=0) node.getblock(blockhash=h) diff --git a/test/functional/segwit.py b/test/functional/segwit.py index 7571bd1a37bc..7cd87e562698 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -100,11 +100,11 @@ def skip_mine(self, node, txid, sign, redeem_script=""): sync_blocks(self.nodes) def fail_accept(self, node, error_msg, txid, sign, redeem_script=""): - assert_raises_jsonrpc(-26, error_msg, send_to_witness, 1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) + assert_raises_rpc_error(-26, error_msg, send_to_witness, 1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) def fail_mine(self, node, txid, sign, redeem_script=""): send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) - assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed", node.generate, 1) + assert_raises_rpc_error(-1, "CreateNewBlock: TestBlockValidity failed", node.generate, 1) sync_blocks(self.nodes) def run_test(self): @@ -456,7 +456,7 @@ def run_test(self): # addwitnessaddress should refuse to return a witness address if an uncompressed key is used # note that no witness address should be returned by unsolvable addresses for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address: - assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) + assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) # addwitnessaddress should return a witness addresses even if keys are not in the wallet self.nodes[0].addwitnessaddress(multisig_without_privkey_address) @@ -539,7 +539,7 @@ def run_test(self): # premature_witaddress are not accepted until the script is added with addwitnessaddress first for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress: # This will raise an exception - assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) + assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) # after importaddress it should pass addwitnessaddress v = self.nodes[0].validateaddress(compressed_solvable_address[1]) diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py index 00a58e108e76..9a45d53cb856 100755 --- a/test/functional/signrawtransactions.py +++ b/test/functional/signrawtransactions.py @@ -82,7 +82,7 @@ def script_verification_error_test(self): assert_equal(decodedRawTx["vin"][i]["vout"], inp["vout"]) # Make sure decoderawtransaction throws if there is extra data - assert_raises_jsonrpc(-22, "TX decode failed", self.nodes[0].decoderawtransaction, rawTx + "00") + assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, rawTx + "00") rawTxSigned = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index ed35bf576eb8..102c903018fe 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -52,7 +52,7 @@ def assert_raises_message(exc, message, fun, *args, **kwds): try: fun(*args, **kwds) except JSONRPCException: - raise AssertionError("Use assert_raises_jsonrpc() to test RPC failures") + raise AssertionError("Use assert_raises_rpc_error() to test RPC failures") 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']) @@ -85,7 +85,7 @@ def assert_raises_process_error(returncode, output, fun, *args, **kwds): else: raise AssertionError("No exception raised") -def assert_raises_jsonrpc(code, message, fun, *args, **kwds): +def assert_raises_rpc_error(code, message, fun, *args, **kwds): """Run an RPC and verify that a specific JSONRPC exception code and message is raised. Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index bd745ac854e7..2ca01c7f0822 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -7,7 +7,7 @@ import os from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_equal, assert_raises_jsonrpc) +from test_framework.util import (assert_equal, assert_raises_rpc_error) def read_dump(file_name, addrs, hd_master_addr_old): @@ -106,7 +106,7 @@ def run_test (self): assert_equal(found_addr_rsv, 90*2) # Overwriting should fail - assert_raises_jsonrpc(-8, "already exists", self.nodes[0].dumpwallet, tmpdir + "/node0/wallet.unencrypted.dump") + assert_raises_rpc_error(-8, "already exists", self.nodes[0].dumpwallet, tmpdir + "/node0/wallet.unencrypted.dump") if __name__ == '__main__': WalletDumpTest().main () diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index ce1e7744e903..db62e1e30f48 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -9,7 +9,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_raises_jsonrpc, + assert_raises_rpc_error, ) class WalletEncryptionTest(BitcoinTestFramework): @@ -32,7 +32,7 @@ def run_test(self): self.start_node(0) # Test that the wallet is encrypted - assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) + assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) # Check that walletpassphrase works self.nodes[0].walletpassphrase(passphrase, 2) @@ -40,20 +40,20 @@ def run_test(self): # Check that the timeout is right time.sleep(2) - assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) + assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) # Test wrong passphrase - assert_raises_jsonrpc(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase + "wrong", 10) + assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase + "wrong", 10) # Test walletlock self.nodes[0].walletpassphrase(passphrase, 84600) assert_equal(privkey, self.nodes[0].dumpprivkey(address)) self.nodes[0].walletlock() - assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) + assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) # Test passphrase changes self.nodes[0].walletpassphrasechange(passphrase, passphrase2) - assert_raises_jsonrpc(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase, 10) + assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase, 10) self.nodes[0].walletpassphrase(passphrase2, 10) assert_equal(privkey, self.nodes[0].dumpprivkey(address)) diff --git a/test/functional/wallet.py b/test/functional/wallet.py index de3aa8a87554..7d6b0b24b6f4 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -102,7 +102,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_jsonrpc(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) + assert_raises_rpc_error(-4, "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) @@ -287,10 +287,10 @@ def run_test(self): assert_equal(txObj['amount'], Decimal('-0.0001')) # This will raise an exception because the amount type is wrong - assert_raises_jsonrpc(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") + assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string - assert_raises_jsonrpc(-1, "not an integer", self.nodes[0].generate, "2") + assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO @@ -423,7 +423,7 @@ def run_test(self): node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. - assert_raises_jsonrpc(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) + assert_raises_rpc_error(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999))) diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index 83b11035c89e..8cd622dc8ec3 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -17,7 +17,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_raises_jsonrpc, + assert_raises_rpc_error, wait_until, ) @@ -72,7 +72,7 @@ def run_test(self): assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) # This will raise an exception because the unconfirmed transaction has been zapped - assert_raises_jsonrpc(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2) + assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2) if __name__ == '__main__': ZapWalletTXesTest().main() From fd79ed6b202ec872aa794ba6a23d4dfc373a98f1 Mon Sep 17 00:00:00 2001 From: Tomas van der Wansem Date: Thu, 21 Sep 2017 00:10:46 +0200 Subject: [PATCH 106/196] Ensure backupwallet fails when attempting to backup to source file Previous behaviour was to destroy the wallet (to zero-length) Github-Pull: #11376 Rebased-From: 5d465e396249a0e2cc60b16984a2bdbe4c8993c3 --- src/wallet/db.cpp | 5 +++++ src/wallet/db.h | 2 +- test/functional/walletbackup.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index d2fe4866fae3..8c23d9c0722d 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -673,6 +673,11 @@ bool CWalletDBWrapper::Backup(const std::string& strDest) pathDest /= strFile; try { + if (fs::equivalent(pathSrc, pathDest)) { + LogPrintf("cannot backup to wallet source file %s\n", pathDest.string()); + return false; + } + fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists); LogPrintf("copied %s to %s\n", strFile, pathDest.string()); return true; diff --git a/src/wallet/db.h b/src/wallet/db.h index 3614e34fbba8..6f3cfe955704 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -45,7 +45,7 @@ class CDBEnv void Reset(); void MakeMock(); - bool IsMock() { return fMockDb; } + bool IsMock() const { return fMockDb; } /** * Verify that database file strFile is OK. If it is not, diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index 15ea26afa160..85a149793e73 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -190,6 +190,16 @@ def run_test(self): assert_equal(self.nodes[1].getbalance(), balance1) assert_equal(self.nodes[2].getbalance(), balance2) + # Backup to source wallet file must fail + sourcePaths = [ + tmpdir + "/node0/regtest/wallet.dat", + tmpdir + "/node0/./regtest/wallet.dat", + tmpdir + "/node0/regtest/", + tmpdir + "/node0/regtest"] + + for sourcePath in sourcePaths: + assert_raises_rpc_error(-4, "backup failed", self.nodes[0].backupwallet, sourcePath) + if __name__ == '__main__': WalletBackupTest().main() From de7053f1141756158c2107bcba376401b4cc94e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Thu, 12 Oct 2017 23:14:46 +0100 Subject: [PATCH 107/196] [wallet] Fix leak in CDB constructor Now using a std::unique_ptr, the Db instance is correctly released when CDB initialization fails. The internal CDB state and mapFileUseCount are only mutated when the CDB initialization succeeds. Github-Pull: #11492 Rebased-From: 7104de8b1f3a31d3a60009b5dc376adbedac6a9c --- src/wallet/db.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 8c23d9c0722d..f5f96768b074 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -379,45 +379,43 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb if (!env->Open(GetDataDir())) throw std::runtime_error("CDB: Failed to open database environment."); - strFile = strFilename; - ++env->mapFileUseCount[strFile]; - pdb = env->mapDb[strFile]; + pdb = env->mapDb[strFilename]; if (pdb == nullptr) { int ret; - pdb = new Db(env->dbenv, 0); + std::unique_ptr pdb_temp(new Db(env->dbenv, 0)); bool fMockDb = env->IsMock(); if (fMockDb) { - DbMpoolFile* mpf = pdb->get_mpf(); + DbMpoolFile* mpf = pdb_temp->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); - if (ret != 0) - throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile)); + if (ret != 0) { + throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFilename)); + } } - ret = pdb->open(nullptr, // Txn pointer - fMockDb ? nullptr : strFile.c_str(), // Filename - fMockDb ? strFile.c_str() : "main", // Logical db name - DB_BTREE, // Database type - nFlags, // Flags + ret = pdb_temp->open(nullptr, // Txn pointer + fMockDb ? nullptr : strFilename.c_str(), // Filename + fMockDb ? strFilename.c_str() : "main", // Logical db name + DB_BTREE, // Database type + nFlags, // Flags 0); if (ret != 0) { - delete pdb; - pdb = nullptr; - --env->mapFileUseCount[strFile]; - strFile = ""; throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); } + pdb = pdb_temp.release(); + env->mapDb[strFilename] = pdb; + if (fCreate && !Exists(std::string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; WriteVersion(CLIENT_VERSION); fReadOnly = fTmp; } - - env->mapDb[strFile] = pdb; } + ++env->mapFileUseCount[strFilename]; + strFile = strFilename; } } From 9c8006dc332139069d798f39406ec67186ecb311 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Tue, 10 Oct 2017 15:27:26 -0400 Subject: [PATCH 108/196] Avoid opening copied wallet databases simultaneously Make sure wallet databases have unique fileids. If they don't, throw an error. BDB caches do not work properly when more than one open database has the same fileid, because values written to one database may show up in reads to other databases. Bitcoin will never create different databases with the same fileid, but users can create them by manually copying database files. BDB caching bug was reported by Chris Moore https://github.com/bitcoin/bitcoin/issues/11429 Fixes #11429 Github-Pull: #11476 Rebased-From: 478a89c1ef79a75275d1b508122c06eee9386b2d --- src/wallet/db.cpp | 35 ++++++++++++++++++++++++++++++++++ test/functional/multiwallet.py | 6 ++++++ 2 files changed, 41 insertions(+) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index f5f96768b074..fb6e57607475 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -20,6 +20,40 @@ #include +namespace { +//! Make sure database has a unique fileid within the environment. If it +//! doesn't, throw an error. BDB caches do not work properly when more than one +//! open database has the same fileid (values written to one database may show +//! up in reads to other databases). +//! +//! BerkeleyDB generates unique fileids by default +//! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html), +//! so bitcoin should never create different databases with the same fileid, but +//! this error can be triggered if users manually copy database files. +void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db) +{ + if (env.IsMock()) return; + + u_int8_t fileid[DB_FILE_ID_LEN]; + int ret = db.get_mpf()->get_fileid(fileid); + if (ret != 0) { + throw std::runtime_error(strprintf("CDB: Can't open database %s (get_fileid failed with %d)", filename, ret)); + } + + for (const auto& item : env.mapDb) { + u_int8_t item_fileid[DB_FILE_ID_LEN]; + if (item.second && item.second->get_mpf()->get_fileid(item_fileid) == 0 && + memcmp(fileid, item_fileid, sizeof(fileid)) == 0) { + const char* item_filename = nullptr; + item.second->get_dbname(&item_filename, nullptr); + throw std::runtime_error(strprintf("CDB: Can't open database %s (duplicates fileid %s from %s)", filename, + HexStr(std::begin(item_fileid), std::end(item_fileid)), + item_filename ? item_filename : "(unknown database)")); + } + } +} +} // namespace + // // CDB // @@ -403,6 +437,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb if (ret != 0) { throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); } + CheckUniqueFileid(*env, strFilename, *pdb_temp); pdb = pdb_temp.release(); env->mapDb[strFilename] = pdb; diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index 6adcc1fd8828..ba6b659ddcfd 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -7,6 +7,7 @@ Verify that a bitcoind node can load multiple wallet files """ import os +import shutil from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error @@ -29,6 +30,11 @@ def run_test(self): os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11')) self.assert_start_raises_init_error(0, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') + # should not initialize if one wallet is a copy of another + shutil.copyfile(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w2'), + os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w22')) + self.assert_start_raises_init_error(0, ['-wallet=w2', '-wallet=w22'], 'duplicates fileid') + # should not initialize if wallet file is a symlink os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12')) self.assert_start_raises_init_error(0, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') From f3457d0e83c408770eeabb002f569e22c9832c1b Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 10 Oct 2017 00:04:45 +0200 Subject: [PATCH 109/196] qa: Make tmpdir option an absolute path This should fix issues with the multiwallet test and symlinks when the tmpdir is a relative path. Rather than fixing os.symlink to work with paths relative to a directory descriptor, which does not work on Windows, normalize the path instead. Github-Pull: #11472 Rebased-From: fa9de370b17297d6dd542da627c8dd2b31aec340 --- test/functional/test_framework/test_framework.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index a53eb517998d..7aabdd9c007c 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -102,8 +102,11 @@ def main(self): check_json_precision() + self.options.cachedir = os.path.abspath(self.options.cachedir) + # Set up temp directory and start logging if self.options.tmpdir: + self.options.tmpdir = os.path.abspath(self.options.tmpdir) os.makedirs(self.options.tmpdir, exist_ok=False) else: self.options.tmpdir = tempfile.mkdtemp(prefix="test") From 41088795dd9a1c90bb379b2d5237d88ae8889c90 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 11 Oct 2017 22:14:49 +0200 Subject: [PATCH 110/196] qa: Remove never used return value of sync_with_ping Github-Pull: #11472 Rebased-From: fafa0039708e15d1067be091b2bfc10195afa480 --- test/functional/p2p-acceptblock.py | 9 ++++++--- test/functional/test_framework/mininode.py | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 5b6429b41019..6c7e6a22ec9c 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -103,7 +103,8 @@ def run_test(self): test_node.send_message(msg_block(blocks_h2[0])) white_node.send_message(msg_block(blocks_h2[1])) - [ x.sync_with_ping() for x in [test_node, white_node] ] + for x in [test_node, white_node]: + x.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) assert_equal(self.nodes[1].getblockcount(), 2) self.log.info("First height 2 block accepted by both nodes") @@ -116,7 +117,8 @@ def run_test(self): test_node.send_message(msg_block(blocks_h2f[0])) white_node.send_message(msg_block(blocks_h2f[1])) - [ x.sync_with_ping() for x in [test_node, white_node] ] + for x in [test_node, white_node]: + x.sync_with_ping() for x in self.nodes[0].getchaintips(): if x['hash'] == blocks_h2f[0].hash: assert_equal(x['status'], "headers-only") @@ -135,7 +137,8 @@ def run_test(self): test_node.send_message(msg_block(blocks_h3[0])) white_node.send_message(msg_block(blocks_h3[1])) - [ x.sync_with_ping() for x in [test_node, white_node] ] + for x in [test_node, white_node]: + x.sync_with_ping() # Since the earlier block was not processed by node0, the new block # can't be fully validated. for x in self.nodes[0].getchaintips(): diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 843b67cd5cac..dc8731066b27 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1622,7 +1622,6 @@ def sync_with_ping(self, timeout=60): test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter wait_until(test_function, timeout=timeout, lock=mininode_lock) self.ping_counter += 1 - return True # The actual NodeConn class # This class provides an interface for a p2p connection to a specified node From da4908c3a05659846dae81b8d0bd73a04f7ed7c9 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Sun, 7 May 2017 14:10:19 -0400 Subject: [PATCH 111/196] Allow setting nMinimumChainWork on command line Github-Pull: #10357 Rebased-From: 0311836f6927aec4ba5687ea12af35df3c509682 --- src/init.cpp | 17 +++++++++++++++++ src/net_processing.cpp | 2 +- src/test/util_tests.cpp | 25 +++++++++++++++++++++++++ src/utilstrencodings.cpp | 13 +++++++++++++ src/utilstrencodings.h | 6 ++++++ src/validation.cpp | 7 +++---- src/validation.h | 3 +++ 7 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index a708295f43e6..c9bb827f8200 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -362,6 +362,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxorphantx=", strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-maxmempool=", strprintf(_("Keep the transaction memory pool below megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); strUsage += HelpMessageOpt("-mempoolexpiry=", strprintf(_("Do not keep transactions in the mempool longer than hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY)); + if (showDebug) { + strUsage += HelpMessageOpt("-minimumchainwork=", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex())); + } strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL)); strUsage += HelpMessageOpt("-blockreconstructionextratxn=", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); strUsage += HelpMessageOpt("-par=", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), @@ -979,6 +982,20 @@ bool AppInitParameterInteraction() else LogPrintf("Validating signatures for all blocks.\n"); + if (gArgs.IsArgSet("-minimumchainwork")) { + const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", ""); + if (!IsHexNumber(minChainWorkStr)) { + return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr)); + } + nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr)); + } else { + nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork); + } + LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex()); + if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { + LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex()); + } + // mempool limits int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index e09b56a63184..5f117dea7ebe 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -466,7 +466,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorpindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) { + if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { // This peer has nothing interesting. return; } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 567908696902..6ec544290daa 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -253,6 +253,31 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_CHECK(!IsHex("0x0000")); } +BOOST_AUTO_TEST_CASE(util_IsHexNumber) +{ + BOOST_CHECK(IsHexNumber("0x0")); + BOOST_CHECK(IsHexNumber("0")); + BOOST_CHECK(IsHexNumber("0x10")); + BOOST_CHECK(IsHexNumber("10")); + BOOST_CHECK(IsHexNumber("0xff")); + BOOST_CHECK(IsHexNumber("ff")); + BOOST_CHECK(IsHexNumber("0xFfa")); + BOOST_CHECK(IsHexNumber("Ffa")); + BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF")); + BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF")); + + BOOST_CHECK(!IsHexNumber("")); // empty string not allowed + BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed + BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end, + BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning, + BOOST_CHECK(!IsHexNumber("0x 0")); // or middle, + BOOST_CHECK(!IsHexNumber(" ")); // etc. + BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character + BOOST_CHECK(!IsHexNumber("x0")); // broken prefix + BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed + +} + BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { SeedInsecureRand(true); diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index fd233f67579c..741680e93f79 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -65,6 +65,19 @@ bool IsHex(const std::string& str) return (str.size() > 0) && (str.size()%2 == 0); } +bool IsHexNumber(const std::string& str) +{ + size_t starting_location = 0; + if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') { + starting_location = 2; + } + for (auto c : str.substr(starting_location)) { + if (HexDigit(c) < 0) return false; + } + // Return false for empty string or "0x". + return (str.size() > starting_location); +} + std::vector ParseHex(const char* psz) { // convert hex dump to vector diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 53da60e8f13f..192f33fb290e 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -38,7 +38,13 @@ std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); signed char HexDigit(char c); +/* Returns true if each character in str is a hex character, and has an even + * number of hex digits.*/ bool IsHex(const std::string& str); +/** +* Return true if the string is a hex number, optionally prefixed with "0x" +*/ +bool IsHexNumber(const std::string& str); std::vector DecodeBase64(const char* p, bool* pfInvalid = nullptr); std::string DecodeBase64(const std::string& str); std::string EncodeBase64(const unsigned char* pch, size_t len); diff --git a/src/validation.cpp b/src/validation.cpp index 8bd23a0f1d72..76b8401f1ba5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -80,6 +80,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; uint256 hashAssumeValid; +arith_uint256 nMinimumChainWork; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; @@ -1032,8 +1033,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) bool IsInitialBlockDownload() { - const CChainParams& chainParams = Params(); - // Once this function has returned false, it must remain false. static std::atomic latchToFalse{false}; // Optimization: pre-test latch before taking the lock. @@ -1047,7 +1046,7 @@ bool IsInitialBlockDownload() return true; if (chainActive.Tip() == nullptr) return true; - if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) + if (chainActive.Tip()->nChainWork < nMinimumChainWork) return true; if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) return true; @@ -1664,7 +1663,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (it != mapBlockIndex.end()) { if (it->second->GetAncestor(pindex->nHeight) == pindex && pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && - pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { + pindexBestHeader->nChainWork >= nMinimumChainWork) { // This block is a member of the assumed verified chain and an ancestor of the best header. // The equivalent time check discourages hash power from extorting the network via DOS attack // into accepting an invalid block through telling users they must manually set assumevalid. diff --git a/src/validation.h b/src/validation.h index edb8eab894b1..f3d88d318090 100644 --- a/src/validation.h +++ b/src/validation.h @@ -186,6 +186,9 @@ extern bool fEnableReplacement; /** Block hash whose ancestors we will assume to have valid scripts without checking them. */ extern uint256 hashAssumeValid; +/** Minimum work we will assume exists on some valid chain. */ +extern arith_uint256 nMinimumChainWork; + /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; From 0e9d04bf0a9465d085df1f8c8858cf427c6c97ba Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 8 May 2017 09:59:00 -0400 Subject: [PATCH 112/196] [qa] Test nMinimumChainWork Nodes don't consider themselves out of "initial block download" until their active chain has more work than nMinimumChainWork. While in initial block download, nodes won't relay blocks to their peers, so test that this parameter functions as intended by verifying that block relay only succeeds past a given node once its nMinimumChainWork has been exceeded. Github-Pull: #10357 Rebased-From: eac64bb7a3b6aba747403b23b3b1d3609843f8db --- test/functional/minchainwork.py | 81 +++++++++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 82 insertions(+) create mode 100755 test/functional/minchainwork.py diff --git a/test/functional/minchainwork.py b/test/functional/minchainwork.py new file mode 100755 index 000000000000..c7579d2548e4 --- /dev/null +++ b/test/functional/minchainwork.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test logic for setting nMinimumChainWork on command line. + +Nodes don't consider themselves out of "initial block download" until +their active chain has more work than nMinimumChainWork. + +Nodes don't download blocks from a peer unless the peer's best known block +has more work than nMinimumChainWork. + +While in initial block download, nodes won't relay blocks to their peers, so +test that this parameter functions as intended by verifying that block relay +only succeeds past a given node once its nMinimumChainWork has been exceeded. +""" + +import time + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import sync_blocks, connect_nodes, assert_equal + +# 2 hashes required per regtest block (with no difficulty adjustment) +REGTEST_WORK_PER_BLOCK = 2 + +class MinimumChainWorkTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 3 + self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]] + self.node_min_work = [0, 101, 101] + + def setup_network(self): + # This test relies on the chain setup being: + # node0 <- node1 <- node2 + # Before leaving IBD, nodes prefer to download blocks from outbound + # peers, so ensure that we're mining on an outbound peer and testing + # block relay to inbound peers. + self.setup_nodes() + for i in range(self.num_nodes-1): + connect_nodes(self.nodes[i+1], i) + + def run_test(self): + # Start building a chain on node0. node2 shouldn't be able to sync until node1's + # minchainwork is exceeded + starting_chain_work = REGTEST_WORK_PER_BLOCK # Genesis block's work + self.log.info("Testing relay across node %d (minChainWork = %d)", 1, self.node_min_work[1]) + + starting_blockcount = self.nodes[2].getblockcount() + + num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK) + self.log.info("Generating %d blocks on node0", num_blocks_to_generate) + hashes = self.nodes[0].generate(num_blocks_to_generate) + + self.log.info("Node0 current chain work: %s", self.nodes[0].getblockheader(hashes[-1])['chainwork']) + + # Sleep a few seconds and verify that node2 didn't get any new blocks + # or headers. We sleep, rather than sync_blocks(node0, node1) because + # it's reasonable either way for node1 to get the blocks, or not get + # them (since they're below node1's minchainwork). + time.sleep(3) + + self.log.info("Verifying node 2 has no more blocks than before") + self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes]) + # Node2 shouldn't have any new headers yet, because node1 should not + # have relayed anything. + assert_equal(len(self.nodes[2].getchaintips()), 1) + assert_equal(self.nodes[2].getchaintips()[0]['height'], 0) + + assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash() + assert_equal(self.nodes[2].getblockcount(), starting_blockcount) + + self.log.info("Generating one more block") + self.nodes[0].generate(1) + + self.log.info("Verifying nodes are all synced") + self.sync_all() + self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes]) + +if __name__ == '__main__': + MinimumChainWorkTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index fae4f66d70cd..714a907ee8da 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -121,6 +121,7 @@ 'bip65-cltv-p2p.py', 'uptime.py', 'resendwallettransactions.py', + 'minchainwork.py', ] EXTENDED_SCRIPTS = [ From 3acec3878133c52f4f3a594baf1dcbd6575244bb Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Fri, 6 Oct 2017 14:11:43 -0400 Subject: [PATCH 113/196] Don't process unrequested, low-work blocks A peer could try to waste our resources by sending us unrequested blocks with low work, eg to fill up our disk. Since e2652002b6011f793185d473f87f1730c625593b we no longer request blocks until we know we're on a chain with more than nMinimumChainWork (our anti-DoS threshold), but we would still process unrequested blocks that had more work than our tip. This commit fixes that behavior. Github-Pull: #11458 Rebased-From: ce8cd7a7da9174ab151172fc0ce97b5164637cf3 --- src/validation.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 76b8401f1ba5..3bff2d822876 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3120,6 +3120,12 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned if (!fHasMoreWork) return true; // Don't process less-work chains if (fTooFarAhead) return true; // Block height is too high + + // Protect against DoS attacks from low-work chains. + // If our tip is behind, a peer could try to send us + // low-work blocks on a fake chain that we would never + // request; don't process these. + if (pindex->nChainWork < nMinimumChainWork) return true; } if (fNewBlock) *fNewBlock = true; From 2df65eeb98100a376678cdf9cad4c973733df894 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Fri, 6 Oct 2017 14:32:07 -0400 Subject: [PATCH 114/196] qa: add test for minchainwork use in acceptblock Github-Pull: #11458 Rebased-From: 08fd822771bf8dae1c21698811f57aa691b2f25d --- test/functional/p2p-acceptblock.py | 44 ++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 6c7e6a22ec9c..27ae0c27e196 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -8,17 +8,22 @@ versus non-whitelisted peers, this tests the behavior of both (effectively two separate tests running in parallel). -Setup: two nodes, node0 and node1, not connected to each other. Node0 does not +Setup: three nodes, node0+node1+node2, not connected to each other. Node0 does not whitelist localhost, but node1 does. They will each be on their own chain for -this test. +this test. Node2 will have nMinimumChainWork set to 0x10, so it won't process +low-work unrequested blocks. -We have one NodeConn connection to each, test_node and white_node respectively. +We have one NodeConn connection to each, test_node, white_node, and min_work_node, +respectively. The test: 1. Generate one block on each node, to leave IBD. 2. Mine a new block on each tip, and deliver to each node from node's peer. - The tip should advance. + The tip should advance for node0 and node1, but node2 should skip processing + due to nMinimumChainWork. + +Node2 is unused in tests 3-7: 3. Mine a block that forks the previous block, and deliver to each node from corresponding peer. @@ -46,6 +51,10 @@ 7. Send Node0 the missing block again. Node0 should process and the tip should advance. + +8. Test Node2 is able to sync when connected to node0 (which should have sufficient +work on its chain). + """ from test_framework.mininode import * @@ -62,52 +71,60 @@ def add_options(self, parser): def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 2 - self.extra_args = [[], ["-whitelist=127.0.0.1"]] + self.num_nodes = 3 + self.extra_args = [[], ["-whitelist=127.0.0.1"], ["-minimumchainwork=0x10"]] def setup_network(self): # Node0 will be used to test behavior of processing unrequested blocks # from peers which are not whitelisted, while Node1 will be used for # the whitelisted case. + # Node2 will be used for non-whitelisted peers to test the interaction + # with nMinimumChainWork. self.setup_nodes() def run_test(self): # Setup the p2p connections and start up the network thread. test_node = NodeConnCB() # connects to node0 (not whitelisted) white_node = NodeConnCB() # connects to node1 (whitelisted) + min_work_node = NodeConnCB() # connects to node2 (not whitelisted) connections = [] connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)) connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node)) + connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], min_work_node)) test_node.add_connection(connections[0]) white_node.add_connection(connections[1]) + min_work_node.add_connection(connections[2]) NetworkThread().start() # Start up network handling in another thread # Test logic begins here test_node.wait_for_verack() white_node.wait_for_verack() + min_work_node.wait_for_verack() - # 1. Have both nodes mine a block (leave IBD) + # 1. Have nodes mine a block (nodes1/2 leave IBD) [ n.generate(1) for n in self.nodes ] tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ] # 2. Send one block that builds on each tip. - # This should be accepted. + # This should be accepted by nodes 1/2 blocks_h2 = [] # the height 2 blocks on each node's chain block_time = int(time.time()) + 1 - for i in range(2): + for i in range(3): blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time)) blocks_h2[i].solve() block_time += 1 test_node.send_message(msg_block(blocks_h2[0])) white_node.send_message(msg_block(blocks_h2[1])) + min_work_node.send_message(msg_block(blocks_h2[2])) - for x in [test_node, white_node]: + for x in [test_node, white_node, min_work_node]: x.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) assert_equal(self.nodes[1].getblockcount(), 2) - self.log.info("First height 2 block accepted by both nodes") + assert_equal(self.nodes[2].getblockcount(), 1) + self.log.info("First height 2 block accepted by node0/node1; correctly rejected by node2") # 3. Send another block that builds on the original tip. blocks_h2f = [] # Blocks at height 2 that fork off the main chain @@ -220,6 +237,11 @@ def run_test(self): assert_equal(self.nodes[0].getblockcount(), 290) self.log.info("Successfully reorged to longer chain from non-whitelisted peer") + # 8. Connect node2 to node0 and ensure it is able to sync + connect_nodes(self.nodes[0], 2) + sync_blocks([self.nodes[0], self.nodes[2]]) + self.log.info("Successfully synced nodes 2 and 0") + [ c.disconnect_node() for c in connections ] if __name__ == '__main__': From ffb6ea4e5ebfe109e9771aab058bdd4d2f6468a8 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 19 Oct 2017 20:52:30 -0400 Subject: [PATCH 115/196] Add comment explaining forced processing of compact blocks Github-Pull: #11458 Rebased-From: 01b52cedd42f50a93b40981c91af7c12de6e45ce --- src/net_processing.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5f117dea7ebe..5b97509d642c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2144,7 +2144,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false)); } bool fNewBlock = false; - ProcessNewBlock(chainparams, pblock, true, &fNewBlock); + // Setting fForceProcessing to true means that we bypass some of + // our anti-DoS protections in AcceptBlock, which filters + // unrequested blocks that might be trying to waste our resources + // (eg disk space). Because we only try to reconstruct blocks when + // we're close to caught up (via the CanDirectFetch() requirement + // above, combined with the behavior of not requesting blocks until + // we have a chain with at least nMinimumChainWork), and we ignore + // compact blocks with less work than our tip, it is safe to treat + // reconstructed compact blocks as having been requested. + ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); if (fNewBlock) { pfrom->nLastBlockTime = GetTime(); } else { @@ -2224,7 +2233,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr bool fNewBlock = false; // Since we requested this block (it was in mapBlocksInFlight), force it to be processed, // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc) - ProcessNewBlock(chainparams, pblock, true, &fNewBlock); + // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent + // disk-space attacks), but this should be safe due to the + // protections in the compact block handler -- see related comment + // in compact block optimistic reconstruction handling. + ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); if (fNewBlock) { pfrom->nLastBlockTime = GetTime(); } else { From 6f279652b04eea5d11a3fdf6eac5865f0b8557c5 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 1 Nov 2017 16:48:19 -0400 Subject: [PATCH 116/196] Rename fAddnode to a more-descriptive "manual_connection" Github-Pull: #11456 Rebased-From: 57edc0b0c86549020a39cd65f96496e9771c4769 --- src/net.cpp | 12 ++++++------ src/net.h | 6 +++--- src/net_processing.cpp | 2 +- src/rpc/net.cpp | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 599a6128fadb..864bd31cba23 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -665,7 +665,7 @@ void CNode::copyStats(CNodeStats &stats) X(cleanSubVer); } X(fInbound); - X(fAddnode); + X(m_manual_connection); X(nStartingHeight); { LOCK(cs_vSend); @@ -1738,7 +1738,7 @@ void CConnman::ThreadOpenConnections() { LOCK(cs_vNodes); for (CNode* pnode : vNodes) { - if (!pnode->fInbound && !pnode->fAddnode) { + if (!pnode->fInbound && !pnode->m_manual_connection) { // Count the peers that have all relevant services if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) { @@ -1934,7 +1934,7 @@ void CConnman::ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode) +bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection) { // // Initiate outbound network connection @@ -1963,8 +1963,8 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai pnode->fOneShot = true; if (fFeeler) pnode->fFeeler = true; - if (fAddnode) - pnode->fAddnode = true; + if (manual_connection) + pnode->m_manual_connection = true; GetNodeSignals().InitializeNode(pnode, *this); { @@ -2704,7 +2704,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn strSubVer = ""; fWhitelisted = false; fOneShot = false; - fAddnode = false; + m_manual_connection = false; fClient = false; // set by version message fFeeler = false; fSuccessfullyConnected = false; diff --git a/src/net.h b/src/net.h index a32736aa97bf..fa9404ffbcf9 100644 --- a/src/net.h +++ b/src/net.h @@ -170,7 +170,7 @@ class CConnman void Interrupt(); bool GetNetworkActive() const { return fNetworkActive; }; void SetNetworkActive(bool active); - bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false); + bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false); bool CheckIncomingNonce(uint64_t nonce); bool ForNode(NodeId id, std::function func); @@ -508,7 +508,7 @@ class CNodeStats int nVersion; std::string cleanSubVer; bool fInbound; - bool fAddnode; + bool m_manual_connection; int nStartingHeight; uint64_t nSendBytes; mapMsgCmdSize mapSendBytesPerMsgCmd; @@ -618,7 +618,7 @@ class CNode bool fWhitelisted; // This peer can bypass DoS banning. bool fFeeler; // If true this node is being used as a short lived feeler. bool fOneShot; - bool fAddnode; + bool m_manual_connection; bool fClient; const bool fInbound; std::atomic_bool fSuccessfullyConnected; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5b97509d642c..6e6b62484c5d 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2656,7 +2656,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) state.fShouldBan = false; if (pnode->fWhitelisted) LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString()); - else if (pnode->fAddnode) + else if (pnode->m_manual_connection) LogPrintf("Warning: not punishing addnoded peer %s!\n", pnode->addr.ToString()); else { pnode->fDisconnect = true; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index e463a4eda4f8..2916bdc02ff4 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -156,7 +156,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) // their ver message. obj.push_back(Pair("subver", stats.cleanSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); - obj.push_back(Pair("addnode", stats.fAddnode)); + obj.push_back(Pair("addnode", stats.m_manual_connection)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); if (fStateStats) { obj.push_back(Pair("banscore", statestats.nMisbehavior)); From 8aee55af3d21fb79edf148e42c3bd10bf80f7ec8 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 6 Jul 2017 13:53:52 -0400 Subject: [PATCH 117/196] net: pass CConnman via pointer rather than reference There are a few too many edge-cases here to make this a scripted diff. The following commits will move a few functions into PeerLogicValidation, where the local connman instance can be used. This change prepares for that usage. Github-Pull: #10756 Rebased-From: 28f11e9406b185dc87144f1f29af0d93eb115b4e --- src/net.cpp | 8 +- src/net.h | 6 +- src/net_processing.cpp | 168 ++++++++++++++++++++--------------------- src/net_processing.h | 4 +- src/test/DoS_tests.cpp | 22 +++--- 5 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 864bd31cba23..5bb1a82598bf 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1114,7 +1114,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; - GetNodeSignals().InitializeNode(pnode, *this); + GetNodeSignals().InitializeNode(pnode, this); LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString()); @@ -1966,7 +1966,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (manual_connection) pnode->m_manual_connection = true; - GetNodeSignals().InitializeNode(pnode, *this); + GetNodeSignals().InitializeNode(pnode, this); { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -1996,7 +1996,7 @@ void CConnman::ThreadMessageHandler() continue; // Receive messages - bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); + bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, this, flagInterruptMsgProc); fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); if (flagInterruptMsgProc) return; @@ -2004,7 +2004,7 @@ void CConnman::ThreadMessageHandler() // Send messages { LOCK(pnode->cs_sendProcessing); - GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); + GetNodeSignals().SendMessages(pnode, this, flagInterruptMsgProc); } if (flagInterruptMsgProc) return; diff --git a/src/net.h b/src/net.h index fa9404ffbcf9..9e1898d14d80 100644 --- a/src/net.h +++ b/src/net.h @@ -439,9 +439,9 @@ struct CombinerAll // Signals for message handling struct CNodeSignals { - boost::signals2::signal&), CombinerAll> ProcessMessages; - boost::signals2::signal&), CombinerAll> SendMessages; - boost::signals2::signal InitializeNode; + boost::signals2::signal&), CombinerAll> ProcessMessages; + boost::signals2::signal&), CombinerAll> SendMessages; + boost::signals2::signal InitializeNode; boost::signals2::signal FinalizeNode; }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6e6b62484c5d..e3d2a51e7ec6 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -244,7 +244,7 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state) nPreferredDownload += state->fPreferredDownload; } -void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) +void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) { ServiceFlags nLocalNodeServices = pnode->GetLocalServices(); uint64_t nonce = pnode->GetLocalNonce(); @@ -255,7 +255,7 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = CAddress(CService(), nLocalNodeServices); - connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes)); if (fLogIPs) { @@ -265,7 +265,7 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) } } -void InitializeNode(CNode *pnode, CConnman& connman) { +void InitializeNode(CNode *pnode, CConnman* connman) { CAddress addr = pnode->addr; std::string addrName = pnode->GetAddrName(); NodeId nodeid = pnode->GetId(); @@ -402,7 +402,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { } } -void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) { +void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) { AssertLockHeld(cs_main); CNodeState* nodestate = State(nodeid); if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) { @@ -417,20 +417,20 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) { return; } } - connman.ForNode(nodeid, [&connman](CNode* pfrom){ + connman->ForNode(nodeid, [connman](CNode* pfrom){ bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1; if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { // As per BIP152, we only get 3 of our peers to announce // blocks using compact encodings. - connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){ - connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), [connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){ + connman->PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); return true; }); lNodesAnnouncingHeaderAndIDs.pop_front(); } fAnnounceUsingCMPCTBLOCK = true; - connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); return true; }); @@ -865,7 +865,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta !IsInitialBlockDownload() && mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) { if (it != mapBlockSource.end()) { - MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman); + MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman); } } if (it != mapBlockSource.end()) @@ -910,16 +910,16 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) return true; } -static void RelayTransaction(const CTransaction& tx, CConnman& connman) +static void RelayTransaction(const CTransaction& tx, CConnman* connman) { CInv inv(MSG_TX, tx.GetHash()); - connman.ForEachNode([&inv](CNode* pnode) + connman->ForEachNode([&inv](CNode* pnode) { pnode->PushInventory(inv); }); } -static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman) +static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connman) { unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) @@ -927,7 +927,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the addrKnowns of the chosen nodes prevent repeats uint64_t hashAddr = addr.GetHash(); - const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); + const CSipHasher hasher = connman->GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); FastRandomContext insecure_rand; std::array,2> best{{{0, nullptr}, {0, nullptr}}}; @@ -952,10 +952,10 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma } }; - connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); + connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, const std::atomic& interruptMsgProc) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman* connman, const std::atomic& interruptMsgProc) { std::deque::iterator it = pfrom->vRecvGetData.begin(); std::vector vNotFound; @@ -1017,7 +1017,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // disconnect node in case we have reached the outbound limit for serving historical blocks // never disconnect whitelisted nodes static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) { LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -1040,9 +1040,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam pblock = pblockRead; } if (inv.type == MSG_BLOCK) - connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock)); + connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock)); else if (inv.type == MSG_WITNESS_BLOCK) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); else if (inv.type == MSG_FILTERED_BLOCK) { bool sendMerkleBlock = false; @@ -1055,7 +1055,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } if (sendMerkleBlock) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip // Note that there is currently no way for a node to request any single transactions we didn't send here - @@ -1064,7 +1064,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // however we MUST always provide at least what the remote peer needs typedef std::pair PairType; for (PairType& pair : merkleBlock.vMatchedTxn) - connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first])); + connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first])); } // else // no response @@ -1079,13 +1079,13 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == mi->second->GetBlockHash()) { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); } else { CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness); - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } } else { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); } } @@ -1097,7 +1097,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // wait for other stuff first. std::vector vInv; vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); pfrom->hashContinue.SetNull(); } } @@ -1109,14 +1109,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam auto mi = mapRelay.find(inv.hash); int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0); if (mi != mapRelay.end()) { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); push = true; } else if (pfrom->timeLastMempoolReq) { auto txinfo = mempool.info(inv.hash); // To protect privacy, do not answer getdata using the mempool when // that TX couldn't have been INVed in reply to a MEMPOOL request. if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); push = true; } } @@ -1143,7 +1143,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // do that because they want to know about (and store and rebroadcast and // risk analyze) the dependencies of transactions relevant to them, without // having to download the entire memory pool. - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); } } @@ -1155,7 +1155,7 @@ uint32_t GetFetchFlags(CNode* pfrom) { return nFetchFlags; } -inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman) { +inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman* connman) { BlockTransactions resp(req); for (size_t i = 0; i < req.indexes.size(); i++) { if (req.indexes[i] >= block.vtx.size()) { @@ -1169,10 +1169,10 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac LOCK(cs_main); const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; - connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); + connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); } -bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, const std::atomic& interruptMsgProc) +bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic& interruptMsgProc) { LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId()); if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) @@ -1225,7 +1225,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Each connection can only send one version message if (pfrom->nVersion != 0) { - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message"))); + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message"))); LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; @@ -1249,12 +1249,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr nServices = ServiceFlags(nServiceInt); if (!pfrom->fInbound) { - connman.SetServices(pfrom->addr, nServices); + connman->SetServices(pfrom->addr, nServices); } if (pfrom->nServicesExpected & ~nServices) { LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, pfrom->nServicesExpected); - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, strprintf("Expected to offer services %08x", pfrom->nServicesExpected))); pfrom->fDisconnect = true; return false; @@ -1275,7 +1275,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion); - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION))); pfrom->fDisconnect = true; return false; @@ -1295,7 +1295,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!vRecv.empty()) vRecv >> fRelay; // Disconnect if we connected to ourself - if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce)) + if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce)) { LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); pfrom->fDisconnect = true; @@ -1311,7 +1311,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (pfrom->fInbound) PushNodeVersion(pfrom, connman, GetAdjustedTime()); - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); pfrom->nServices = nServices; pfrom->SetAddrLocal(addrMe); @@ -1362,12 +1362,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } // Get recent addresses - if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000) + if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman->GetAddressCount() < 1000) { - connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); + connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); pfrom->fGetAddr = true; } - connman.MarkAddressGood(pfrom->addr); + connman->MarkAddressGood(pfrom->addr); } std::string remoteAddr; @@ -1386,7 +1386,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // If the peer is old enough to have the old alert system, send it the final alert. if (pfrom->nVersion <= 70012) { CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION); - connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert)); + connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert)); } // Feeler connections exist only to verify if address is online. @@ -1424,7 +1424,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // We send this to non-NODE NETWORK peers as well, because even // non-NODE NETWORK peers can announce blocks (such as pruning // nodes) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); } if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { // Tell our peer we are willing to provide version 1 or 2 cmpctblocks @@ -1435,9 +1435,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 2; if (pfrom->GetLocalServices() & NODE_WITNESS) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); nCMPCTBLOCKVersion = 1; - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); } pfrom->fSuccessfullyConnected = true; } @@ -1456,7 +1456,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr vRecv >> vAddr; // Don't want addr from older versions unless seeding - if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000) + if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000) return true; if (vAddr.size() > 1000) { @@ -1490,7 +1490,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (fReachable) vAddrOk.push_back(addr); } - connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60); + connman->AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60); if (vAddr.size() < 1000) pfrom->fGetAddr = false; if (pfrom->fOneShot) @@ -1568,7 +1568,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // fell back to inv we probably have a reorg which we should get the headers for first, // we now only provide a getheaders response here. When we receive the headers, we will // then ask for the blocks we need. - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash)); LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId()); } } @@ -1774,7 +1774,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // will re-announce the new block via headers (or compact blocks again) // in the SendMessages logic. nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); } @@ -1955,7 +1955,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->GetId(), FormatStateMessage(state)); if (state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash)); if (nDoS > 0) { Misbehaving(pfrom->GetId(), nDoS); @@ -1975,7 +1975,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) { // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers if (!IsInitialBlockDownload()) - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); return true; } } @@ -2030,7 +2030,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // so we just grab the block via normal getdata std::vector vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); } return true; } @@ -2074,7 +2074,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Duplicate txindexes, the block is now in-flight, so just request it std::vector vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return true; } @@ -2091,7 +2091,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr fProcessBLOCKTXN = true; } else { req.blockhash = pindex->GetBlockHash(); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); } } else { // This block is either already in flight from a different @@ -2117,7 +2117,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // mempool will probably be useless - request the block normally std::vector vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return true; } else { // If this was an announce-cmpctblock, we want the same treatment as a header message @@ -2200,7 +2200,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Might have collided, fall back to getdata now :( std::vector invs; invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash)); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); } else { // Block is either okay, or possibly we received // READ_STATUS_CHECKBLOCK_FAILED. @@ -2285,7 +2285,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // nUnconnectingHeaders gets reset back to 0. if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", headers[0].GetHash().ToString(), headers[0].hashPrevBlock.ToString(), @@ -2340,7 +2340,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); @@ -2390,7 +2390,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // In any case, we want to download using a compact block, not a regular one vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); } - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); } } } @@ -2451,7 +2451,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->fSentAddr = true; pfrom->vAddrToSend.clear(); - std::vector vAddr = connman.GetAddresses(); + std::vector vAddr = connman->GetAddresses(); FastRandomContext insecure_rand; for (const CAddress &addr : vAddr) pfrom->PushAddress(addr, insecure_rand); @@ -2467,7 +2467,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted) + if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted) { LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); pfrom->fDisconnect = true; @@ -2496,7 +2496,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // it, if the remote node sends a ping once per second and this node takes 5 // seconds to respond to each, the 5th ping the remote sends would appear to // return very quickly. - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); } } @@ -2642,13 +2642,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } -static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) +static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman) { AssertLockHeld(cs_main); CNodeState &state = *State(pnode->GetId()); for (const CBlockReject& reject : state.rejects) { - connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock)); + connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock)); } state.rejects.clear(); @@ -2664,7 +2664,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString()); else { - connman.Ban(pnode->addr, BanReasonNodeMisbehaving); + connman->Ban(pnode->addr, BanReasonNodeMisbehaving); } } return true; @@ -2672,7 +2672,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) return false; } -bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& interruptMsgProc) +bool ProcessMessages(CNode* pfrom, CConnman* connman, const std::atomic& interruptMsgProc) { const CChainParams& chainparams = Params(); // @@ -2706,7 +2706,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& i // Just take one message msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin()); pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE; - pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize(); + pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman->GetReceiveFloodSize(); fMoreWork = !pfrom->vProcessMsg.empty(); } CNetMessage& msg(msgs.front()); @@ -2755,7 +2755,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& i } catch (const std::ios_base::failure& e) { - connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message"))); + connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message"))); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv @@ -2809,7 +2809,7 @@ class CompareInvMempoolOrder } }; -bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interruptMsgProc) +bool SendMessages(CNode* pto, CConnman* connman, const std::atomic& interruptMsgProc) { const Consensus::Params& consensusParams = Params().GetConsensus(); { @@ -2841,11 +2841,11 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr pto->nPingUsecStart = GetTimeMicros(); if (pto->nVersion > BIP0031_VERSION) { pto->nPingNonceSent = nonce; - connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce)); } else { // Peer is too old to support ping command with nonce, pong will never arrive. pto->nPingNonceSent = 0; - connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING)); } } @@ -2880,14 +2880,14 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); vAddr.clear(); } } } pto->vAddrToSend.clear(); if (!vAddr.empty()) - connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); // we only send the big addr message once if (pto->vAddrToSend.capacity() > 40) pto->vAddrToSend.shrink_to_fit(); @@ -2914,7 +2914,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr if (pindexStart->pprev) pindexStart = pindexStart->pprev; LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight); - connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256())); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256())); } } @@ -2923,7 +2923,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - GetMainSignals().Broadcast(nTimeBestReceived, &connman); + GetMainSignals().Broadcast(nTimeBestReceived, connman); } // @@ -3007,10 +3007,10 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr LOCK(cs_most_recent_block); if (most_recent_block_hash == pBestIndex->GetBlockHash()) { if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock) - connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block)); + connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block)); else { CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness); - connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } fGotBlockFromCache = true; } @@ -3020,7 +3020,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams); assert(ret); CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness); - connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } state.pindexBestHeaderSent = pBestIndex; } else if (state.fPreferHeaders) { @@ -3033,7 +3033,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr LogPrint(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__, vHeaders.front().GetHash().ToString(), pto->GetId()); } - connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); state.pindexBestHeaderSent = pBestIndex; } else fRevertToInv = true; @@ -3079,7 +3079,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr for (const uint256& hash : pto->vInventoryBlockToSend) { vInv.push_back(CInv(MSG_BLOCK, hash)); if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } @@ -3125,7 +3125,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr pto->filterInventoryKnown.insert(hash); vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } @@ -3191,7 +3191,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr } } if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } pto->filterInventoryKnown.insert(hash); @@ -3199,7 +3199,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr } } if (!vInv.empty()) - connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); // Detect whether we're stalling nNow = GetTimeMicros(); @@ -3294,7 +3294,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr vGetData.push_back(inv); if (vGetData.size() >= 1000) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); vGetData.clear(); } } else { @@ -3304,7 +3304,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr pto->mapAskFor.erase(pto->mapAskFor.begin()); } if (!vGetData.empty()) - connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); // // Message: feefilter @@ -3321,7 +3321,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr // We always have a fee filter of at least minRelayTxFee filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); if (filterToSend != pto->lastSentFeeFilter) { - connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); pto->lastSentFeeFilter = filterToSend; } pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); diff --git a/src/net_processing.h b/src/net_processing.h index db6d81e6b67f..84ec7a766283 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -53,7 +53,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); void Misbehaving(NodeId nodeid, int howmuch); /** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& interrupt); +bool ProcessMessages(CNode* pfrom, CConnman* connman, const std::atomic& interrupt); /** * Send queued protocol messages to be sent to a give node. * @@ -62,6 +62,6 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& i * @param[in] interrupt Interrupt condition for processing threads * @return True if there is more work to be done */ -bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interrupt); +bool SendMessages(CNode* pto, CConnman* connman, const std::atomic& interrupt); #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index ffbeeb7d9186..39a75f7c820c 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -50,26 +50,26 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode1, *connman); + GetNodeSignals().InitializeNode(&dummyNode1, connman); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); // Should get banned - SendMessages(&dummyNode1, *connman, interruptDummy); + SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true); dummyNode2.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode2, *connman); + GetNodeSignals().InitializeNode(&dummyNode2, connman); dummyNode2.nVersion = 1; dummyNode2.fSuccessfullyConnected = true; Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, *connman, interruptDummy); + SendMessages(&dummyNode2, connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, *connman, interruptDummy); + SendMessages(&dummyNode2, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr2)); } @@ -82,17 +82,17 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode1, *connman); + GetNodeSignals().InitializeNode(&dummyNode1, connman); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); - SendMessages(&dummyNode1, *connman, interruptDummy); + SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); - SendMessages(&dummyNode1, *connman, interruptDummy); + SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); - SendMessages(&dummyNode1, *connman, interruptDummy); + SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); } @@ -108,12 +108,12 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true); dummyNode.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode, *connman); + GetNodeSignals().InitializeNode(&dummyNode, connman); dummyNode.nVersion = 1; dummyNode.fSuccessfullyConnected = true; Misbehaving(dummyNode.GetId(), 100); - SendMessages(&dummyNode, *connman, interruptDummy); + SendMessages(&dummyNode, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime+60*60); From dc897e53d8a6c29016a19c862ddd0b656ae8de3f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 6 Jul 2017 13:40:09 -0400 Subject: [PATCH 118/196] net: use an interface class rather than signals for message processing Drop boost signals in favor of a stateful class. This will allow the message processing loop to actually move to net_processing in a future step. Github-Pull: #10756 Rebased-From: 8ad663c1fa88d68843e45580deced56112343183 --- src/init.cpp | 5 +- src/net.cpp | 20 +++---- src/net.h | 25 +++++---- src/net_processing.cpp | 112 ++++++++++++++++---------------------- src/net_processing.h | 36 ++++++------ src/test/DoS_tests.cpp | 22 ++++---- src/test/test_bitcoin.cpp | 6 +- src/test/test_bitcoin.h | 2 + 8 files changed, 103 insertions(+), 125 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index c9bb827f8200..62250664e360 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -194,11 +194,10 @@ void Shutdown() #endif MapPort(false); UnregisterValidationInterface(peerLogic.get()); - peerLogic.reset(); g_connman.reset(); + peerLogic.reset(); StopTorControl(); - UnregisterNodeSignals(GetNodeSignals()); if (fDumpMempoolLater && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { DumpMempool(); } @@ -1277,7 +1276,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) peerLogic.reset(new PeerLogicValidation(&connman)); RegisterValidationInterface(peerLogic.get()); - RegisterNodeSignals(GetNodeSignals()); // sanitize comments per BIP-0014, format user agent and check total size std::vector uacomments; @@ -1668,6 +1666,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; + connOptions.m_msgproc = peerLogic.get(); connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); diff --git a/src/net.cpp b/src/net.cpp index 5bb1a82598bf..63ac833405bc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,10 +89,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -// Signals for message handling -static CNodeSignals g_signals; -CNodeSignals& GetNodeSignals() { return g_signals; } - void CConnman::AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); @@ -1114,7 +1110,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; - GetNodeSignals().InitializeNode(pnode, this); + m_msgproc->InitializeNode(pnode, this); LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString()); @@ -1966,7 +1962,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (manual_connection) pnode->m_manual_connection = true; - GetNodeSignals().InitializeNode(pnode, this); + m_msgproc->InitializeNode(pnode, this); { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -1996,16 +1992,16 @@ void CConnman::ThreadMessageHandler() continue; // Receive messages - bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, this, flagInterruptMsgProc); + bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, this, flagInterruptMsgProc); fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); if (flagInterruptMsgProc) return; - // Send messages { LOCK(pnode->cs_sendProcessing); - GetNodeSignals().SendMessages(pnode, this, flagInterruptMsgProc); + m_msgproc->SendMessages(pnode, this, flagInterruptMsgProc); } + if (flagInterruptMsgProc) return; } @@ -2324,6 +2320,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) // // Start threads // + assert(m_msgproc); InterruptSocks5(false); interruptNet.reset(); flagInterruptMsgProc = false; @@ -2443,9 +2440,10 @@ void CConnman::DeleteNode(CNode* pnode) { assert(pnode); bool fUpdateConnectionTime = false; - GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime); - if(fUpdateConnectionTime) + m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime); + if(fUpdateConnectionTime) { addrman.Connected(pnode->addr); + } delete pnode; } diff --git a/src/net.h b/src/net.h index 9e1898d14d80..fcbf93672f06 100644 --- a/src/net.h +++ b/src/net.h @@ -33,7 +33,6 @@ #include #endif -#include class CScheduler; class CNode; @@ -116,7 +115,7 @@ struct CSerializedNetMsg std::string command; }; - +class NetEventsInterface; class CConnman { public: @@ -138,6 +137,7 @@ class CConnman int nMaxFeeler = 0; int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; + NetEventsInterface* m_msgproc = nullptr; unsigned int nSendBufferMaxSize = 0; unsigned int nReceiveFloodSize = 0; uint64_t nMaxOutboundTimeframe = 0; @@ -156,6 +156,7 @@ class CConnman nMaxFeeler = connOptions.nMaxFeeler; nBestHeight = connOptions.nBestHeight; clientInterface = connOptions.uiInterface; + m_msgproc = connOptions.m_msgproc; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nReceiveFloodSize; nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; @@ -396,6 +397,7 @@ class CConnman int nMaxFeeler; std::atomic nBestHeight; CClientUIInterface* clientInterface; + NetEventsInterface* m_msgproc; /** SipHasher seeds for deterministic randomness */ const uint64_t nSeed0, nSeed1; @@ -436,19 +438,18 @@ struct CombinerAll } }; -// Signals for message handling -struct CNodeSignals +/** + * Interface for message handling + */ +class NetEventsInterface { - boost::signals2::signal&), CombinerAll> ProcessMessages; - boost::signals2::signal&), CombinerAll> SendMessages; - boost::signals2::signal InitializeNode; - boost::signals2::signal FinalizeNode; +public: + virtual bool ProcessMessages(CNode* pnode, CConnman* connman, std::atomic& interrupt) = 0; + virtual bool SendMessages(CNode* pnode, CConnman* connman, std::atomic& interrupt) = 0; + virtual void InitializeNode(CNode* pnode, CConnman* connman) = 0; + virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0; }; - -CNodeSignals& GetNodeSignals(); - - enum { LOCAL_NONE, // unknown diff --git a/src/net_processing.cpp b/src/net_processing.cpp index e3d2a51e7ec6..22d7ee194bb3 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -123,11 +123,6 @@ namespace { std::deque> vRelayExpiration; } // namespace -////////////////////////////////////////////////////////////////////////////// -// -// Registration of network node signals. -// - namespace { struct CBlockReject { @@ -265,49 +260,6 @@ void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) } } -void InitializeNode(CNode *pnode, CConnman* connman) { - CAddress addr = pnode->addr; - std::string addrName = pnode->GetAddrName(); - NodeId nodeid = pnode->GetId(); - { - LOCK(cs_main); - mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName))); - } - if(!pnode->fInbound) - PushNodeVersion(pnode, connman, GetTime()); -} - -void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { - fUpdateConnectionTime = false; - LOCK(cs_main); - CNodeState *state = State(nodeid); - - if (state->fSyncStarted) - nSyncStarted--; - - if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { - fUpdateConnectionTime = true; - } - - for (const QueuedBlock& entry : state->vBlocksInFlight) { - mapBlocksInFlight.erase(entry.hash); - } - EraseOrphansFor(nodeid); - nPreferredDownload -= state->fPreferredDownload; - nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); - assert(nPeersWithValidatedDownloads >= 0); - - mapNodeState.erase(nodeid); - - if (mapNodeState.empty()) { - // Do a consistency check after the last peer is removed. - assert(mapBlocksInFlight.empty()); - assert(nPreferredDownload == 0); - assert(nPeersWithValidatedDownloads == 0); - } - LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); -} - // Requires cs_main. // Returns a bool indicating whether we requested this block. // Also used if a block was /not/ received and timed out or started with another peer @@ -543,6 +495,50 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectoraddr; + std::string addrName = pnode->GetAddrName(); + NodeId nodeid = pnode->GetId(); + { + LOCK(cs_main); + mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName))); + } + if(!pnode->fInbound) + PushNodeVersion(pnode, connman, GetTime()); +} + +void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { + fUpdateConnectionTime = false; + LOCK(cs_main); + CNodeState *state = State(nodeid); + assert(state != nullptr); + + if (state->fSyncStarted) + nSyncStarted--; + + if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { + fUpdateConnectionTime = true; + } + + for (const QueuedBlock& entry : state->vBlocksInFlight) { + mapBlocksInFlight.erase(entry.hash); + } + EraseOrphansFor(nodeid); + nPreferredDownload -= state->fPreferredDownload; + nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); + assert(nPeersWithValidatedDownloads >= 0); + + mapNodeState.erase(nodeid); + + if (mapNodeState.empty()) { + // Do a consistency check after the last peer is removed. + assert(mapBlocksInFlight.empty()); + assert(nPreferredDownload == 0); + assert(nPeersWithValidatedDownloads == 0); + } + LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); +} + bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { LOCK(cs_main); CNodeState *state = State(nodeid); @@ -558,22 +554,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { return true; } -void RegisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.ProcessMessages.connect(&ProcessMessages); - nodeSignals.SendMessages.connect(&SendMessages); - nodeSignals.InitializeNode.connect(&InitializeNode); - nodeSignals.FinalizeNode.connect(&FinalizeNode); -} - -void UnregisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.ProcessMessages.disconnect(&ProcessMessages); - nodeSignals.SendMessages.disconnect(&SendMessages); - nodeSignals.InitializeNode.disconnect(&InitializeNode); - nodeSignals.FinalizeNode.disconnect(&FinalizeNode); -} - ////////////////////////////////////////////////////////////////////////////// // // mapOrphanTransactions @@ -2672,7 +2652,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman) return false; } -bool ProcessMessages(CNode* pfrom, CConnman* connman, const std::atomic& interruptMsgProc) +bool PeerLogicValidation::ProcessMessages(CNode* pfrom, CConnman* connman, std::atomic& interruptMsgProc) { const CChainParams& chainparams = Params(); // @@ -2809,7 +2789,7 @@ class CompareInvMempoolOrder } }; -bool SendMessages(CNode* pto, CConnman* connman, const std::atomic& interruptMsgProc) +bool PeerLogicValidation::SendMessages(CNode* pto, CConnman* connman, std::atomic& interruptMsgProc) { const Consensus::Params& consensusParams = Params().GetConsensus(); { diff --git a/src/net_processing.h b/src/net_processing.h index 84ec7a766283..d79b74fcb7f7 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -22,22 +22,32 @@ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header -/** Register with a network node to receive its signals */ -void RegisterNodeSignals(CNodeSignals& nodeSignals); -/** Unregister a network node */ -void UnregisterNodeSignals(CNodeSignals& nodeSignals); - -class PeerLogicValidation : public CValidationInterface { +class PeerLogicValidation : public CValidationInterface, public NetEventsInterface { private: CConnman* connman; public: - PeerLogicValidation(CConnman* connmanIn); + explicit PeerLogicValidation(CConnman* connman); void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected, const std::vector& vtxConflicted) override; void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; void BlockChecked(const CBlock& block, const CValidationState& state) override; void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) override; + + + void InitializeNode(CNode* pnode, CConnman* connman) override; + void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override; + /** Process protocol messages received from a given node */ + bool ProcessMessages(CNode* pfrom, CConnman* connman, std::atomic& interrupt) override; + /** + * Send queued protocol messages to be sent to a give node. + * + * @param[in] pto The node which we are sending messages to. + * @param[in] connman The connection manager for that node. + * @param[in] interrupt Interrupt condition for processing threads + * @return True if there is more work to be done + */ + bool SendMessages(CNode* pto, CConnman* connman, std::atomic& interrupt) override; }; struct CNodeStateStats { @@ -52,16 +62,4 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); /** Increase a node's misbehavior score. */ void Misbehaving(NodeId nodeid, int howmuch); -/** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom, CConnman* connman, const std::atomic& interrupt); -/** - * Send queued protocol messages to be sent to a give node. - * - * @param[in] pto The node which we are sending messages to. - * @param[in] connman The connection manager for that node. - * @param[in] interrupt Interrupt condition for processing threads - * @return True if there is more work to be done - */ -bool SendMessages(CNode* pto, CConnman* connman, const std::atomic& interrupt); - #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 39a75f7c820c..fc5ef84ad2ac 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -50,26 +50,26 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode1, connman); + peerLogic->InitializeNode(&dummyNode1, connman); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); // Should get banned - SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true); dummyNode2.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode2, connman); + peerLogic->InitializeNode(&dummyNode2, connman); dummyNode2.nVersion = 1; dummyNode2.fSuccessfullyConnected = true; Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode2, connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode2, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr2)); } @@ -82,17 +82,17 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode1, connman); + peerLogic->InitializeNode(&dummyNode1, connman); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); - SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); - SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); - SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); } @@ -108,12 +108,12 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true); dummyNode.SetSendVersion(PROTOCOL_VERSION); - GetNodeSignals().InitializeNode(&dummyNode, connman); + peerLogic->InitializeNode(&dummyNode, connman); dummyNode.nVersion = 1; dummyNode.fSuccessfullyConnected = true; Misbehaving(dummyNode.GetId(), 100); - SendMessages(&dummyNode, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode, connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime+60*60); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 194f62ca1183..045655983c66 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -48,7 +48,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); - g_connman.reset(); } TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) @@ -86,16 +85,17 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha threadGroup.create_thread(&ThreadScriptCheck); g_connman = std::unique_ptr(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. connman = g_connman.get(); - RegisterNodeSignals(GetNodeSignals()); + peerLogic.reset(new PeerLogicValidation(connman)); } TestingSetup::~TestingSetup() { - UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); GetMainSignals().FlushBackgroundCallbacks(); GetMainSignals().UnregisterBackgroundSignalScheduler(); + g_connman.reset(); + peerLogic.reset(); UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index dd3b13c8c894..5a39f8ab821c 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -49,12 +49,14 @@ struct BasicTestingSetup { * Included are data directory, coins database, script check threads setup. */ class CConnman; +class PeerLogicValidation; struct TestingSetup: public BasicTestingSetup { CCoinsViewDB *pcoinsdbview; fs::path pathTemp; boost::thread_group threadGroup; CConnman* connman; CScheduler scheduler; + std::unique_ptr peerLogic; TestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~TestingSetup(); From b4136f21cfbbeb043ce46ffa1bf5f353838bfbea Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 6 Jul 2017 14:08:23 -0400 Subject: [PATCH 119/196] net: drop unused connman param The copy in PeerLogicValidation can be used instead. Github-Pull: #10756 Rebased-From: 80e2e9d0cec890c5d2f81360ebb81e81c07ccb8c --- src/net.cpp | 8 ++++---- src/net.h | 6 +++--- src/net_processing.cpp | 6 +++--- src/net_processing.h | 7 +++---- src/test/DoS_tests.cpp | 22 +++++++++++----------- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 63ac833405bc..a07b22bf5d81 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1110,7 +1110,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; - m_msgproc->InitializeNode(pnode, this); + m_msgproc->InitializeNode(pnode); LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString()); @@ -1962,7 +1962,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (manual_connection) pnode->m_manual_connection = true; - m_msgproc->InitializeNode(pnode, this); + m_msgproc->InitializeNode(pnode); { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -1992,14 +1992,14 @@ void CConnman::ThreadMessageHandler() continue; // Receive messages - bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, this, flagInterruptMsgProc); + bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc); fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); if (flagInterruptMsgProc) return; // Send messages { LOCK(pnode->cs_sendProcessing); - m_msgproc->SendMessages(pnode, this, flagInterruptMsgProc); + m_msgproc->SendMessages(pnode, flagInterruptMsgProc); } if (flagInterruptMsgProc) diff --git a/src/net.h b/src/net.h index fcbf93672f06..9bb1d3c39b08 100644 --- a/src/net.h +++ b/src/net.h @@ -444,9 +444,9 @@ struct CombinerAll class NetEventsInterface { public: - virtual bool ProcessMessages(CNode* pnode, CConnman* connman, std::atomic& interrupt) = 0; - virtual bool SendMessages(CNode* pnode, CConnman* connman, std::atomic& interrupt) = 0; - virtual void InitializeNode(CNode* pnode, CConnman* connman) = 0; + virtual bool ProcessMessages(CNode* pnode, std::atomic& interrupt) = 0; + virtual bool SendMessages(CNode* pnode, std::atomic& interrupt) = 0; + virtual void InitializeNode(CNode* pnode) = 0; virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0; }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 22d7ee194bb3..24d8d49c0c39 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -495,7 +495,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectoraddr; std::string addrName = pnode->GetAddrName(); NodeId nodeid = pnode->GetId(); @@ -2652,7 +2652,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman) return false; } -bool PeerLogicValidation::ProcessMessages(CNode* pfrom, CConnman* connman, std::atomic& interruptMsgProc) +bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic& interruptMsgProc) { const CChainParams& chainparams = Params(); // @@ -2789,7 +2789,7 @@ class CompareInvMempoolOrder } }; -bool PeerLogicValidation::SendMessages(CNode* pto, CConnman* connman, std::atomic& interruptMsgProc) +bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic& interruptMsgProc) { const Consensus::Params& consensusParams = Params().GetConsensus(); { diff --git a/src/net_processing.h b/src/net_processing.h index d79b74fcb7f7..79745cdd42c9 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -35,19 +35,18 @@ class PeerLogicValidation : public CValidationInterface, public NetEventsInterfa void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) override; - void InitializeNode(CNode* pnode, CConnman* connman) override; + void InitializeNode(CNode* pnode) override; void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override; /** Process protocol messages received from a given node */ - bool ProcessMessages(CNode* pfrom, CConnman* connman, std::atomic& interrupt) override; + bool ProcessMessages(CNode* pfrom, std::atomic& interrupt) override; /** * Send queued protocol messages to be sent to a give node. * * @param[in] pto The node which we are sending messages to. - * @param[in] connman The connection manager for that node. * @param[in] interrupt Interrupt condition for processing threads * @return True if there is more work to be done */ - bool SendMessages(CNode* pto, CConnman* connman, std::atomic& interrupt) override; + bool SendMessages(CNode* pto, std::atomic& interrupt) override; }; struct CNodeStateStats { diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index fc5ef84ad2ac..b88ad5ed1b8a 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -50,26 +50,26 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - peerLogic->InitializeNode(&dummyNode1, connman); + peerLogic->InitializeNode(&dummyNode1); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); // Should get banned - peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true); dummyNode2.SetSendVersion(PROTOCOL_VERSION); - peerLogic->InitializeNode(&dummyNode2, connman); + peerLogic->InitializeNode(&dummyNode2); dummyNode2.nVersion = 1; dummyNode2.fSuccessfullyConnected = true; Misbehaving(dummyNode2.GetId(), 50); - peerLogic->SendMessages(&dummyNode2, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode2, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); - peerLogic->SendMessages(&dummyNode2, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode2, interruptDummy); BOOST_CHECK(connman->IsBanned(addr2)); } @@ -82,17 +82,17 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); - peerLogic->InitializeNode(&dummyNode1, connman); + peerLogic->InitializeNode(&dummyNode1); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100); - peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); - peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); - peerLogic->SendMessages(&dummyNode1, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); } @@ -108,12 +108,12 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true); dummyNode.SetSendVersion(PROTOCOL_VERSION); - peerLogic->InitializeNode(&dummyNode, connman); + peerLogic->InitializeNode(&dummyNode); dummyNode.nVersion = 1; dummyNode.fSuccessfullyConnected = true; Misbehaving(dummyNode.GetId(), 100); - peerLogic->SendMessages(&dummyNode, connman, interruptDummy); + peerLogic->SendMessages(&dummyNode, interruptDummy); BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime+60*60); From 0a5477c7e30667f4dc864b69975a8da5f63ca71e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 7 Sep 2017 14:26:20 -0400 Subject: [PATCH 120/196] net: stop both net/net_processing before destroying them This should avoid either attempting to use an invalid reference/pointer to the other. Github-Pull: #10756 Rebased-From: 2525b972af6645ca239ac1078cffb132b402bfbb --- src/init.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 62250664e360..798c24a2a83a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -193,9 +193,13 @@ void Shutdown() } #endif MapPort(false); + + // Because these depend on each-other, we make sure that neither can be + // using the other before destroying them. UnregisterValidationInterface(peerLogic.get()); - g_connman.reset(); + g_connman->Stop(); peerLogic.reset(); + g_connman.reset(); StopTorControl(); if (fDumpMempoolLater && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { From d570aa4290bf678bab764aa58dde19167bc927f5 Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Thu, 14 Sep 2017 15:18:55 +1200 Subject: [PATCH 121/196] Fix uninitialized g_connman crash in Shutdown() Github-Pull: #11326 Rebased-From: 77939f27f7dc42640ebfb9fe52490a2ddacc3ad4 --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 798c24a2a83a..4efc06a4be9b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -197,7 +197,7 @@ void Shutdown() // Because these depend on each-other, we make sure that neither can be // using the other before destroying them. UnregisterValidationInterface(peerLogic.get()); - g_connman->Stop(); + if(g_connman) g_connman->Stop(); peerLogic.reset(); g_connman.reset(); From bf191a71836f357d7949459f666db506dffd123b Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 11 Oct 2017 08:55:14 -0400 Subject: [PATCH 122/196] Disconnecting from bad outbound peers in IBD When in IBD, we'd like to use all our outbound peers to help us sync the chain. Disconnect any outbound peers whose headers have insufficient work. Github-Pull: #11490 Rebased-From: c60fd71a65e841efe187992f46c583a704cc37f5 --- src/net_processing.cpp | 18 ++++++++++++++++++ test/functional/minchainwork.py | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 24d8d49c0c39..87a36553072c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2374,6 +2374,24 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } } + // If we're in IBD, we want outbound peers that will serve us a useful + // chain. Disconnect peers that are on chains with insufficient work. + if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) { + // When nCount < MAX_HEADERS_RESULTS, we know we have no more + // headers to fetch from this peer. + if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { + // This peer has too little work on their headers chain to help + // us sync -- disconnect if using an outbound slot (unless + // whitelisted or addnode). + // Note: We compare their tip to nMinimumChainWork (rather than + // chainActive.Tip()) because we won't start block download + // until we have a headers chain that has at least + // nMinimumChainWork, even if a peer has a chain past our tip, + if (!(pfrom->fInbound || pfrom->fWhitelisted || pfrom->m_manual_connection)) { + pfrom->fDisconnect = true; + } + } + } } } diff --git a/test/functional/minchainwork.py b/test/functional/minchainwork.py index c7579d2548e4..35cd7ad14180 100755 --- a/test/functional/minchainwork.py +++ b/test/functional/minchainwork.py @@ -27,6 +27,7 @@ class MinimumChainWorkTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 + self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]] self.node_min_work = [0, 101, 101] @@ -74,6 +75,13 @@ def run_test(self): self.nodes[0].generate(1) self.log.info("Verifying nodes are all synced") + + # Because nodes in regtest are all manual connections (eg using + # addnode), node1 should not have disconnected node0. If not for that, + # we'd expect node1 to have disconnected node0 for serving an + # insufficient work chain, in which case we'd need to reconnect them to + # continue the test. + self.sync_all() self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes]) From 9961abf9e469da17a3142697007fb810ca88c145 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 12 Oct 2017 13:55:43 -0400 Subject: [PATCH 123/196] Permit disconnection of outbound peers on bad/slow chains Currently we have no rotation of outbound peers. If an outbound peer stops serving us blocks, or is on a consensus-incompatible chain with less work than our tip (but otherwise valid headers), then we will never disconnect that peer, even though that peer is using one of our 8 outbound connection slots. Because we rely on our outbound peers to find an honest node in order to reach consensus, allowing an incompatible peer to occupy one of those slots is undesirable, particularly if it is possible for all such slots to be occupied by such peers. Protect against this by always checking to see if a peer's best known block has less work than our tip, and if so, set a 20 minute timeout -- if the peer is still not known to have caught up to a chain with as much work as ours after 20 minutes, then send a single getheaders message, wait 2 more minutes, and if a better header hasn't been received by then, disconnect that peer. Note: - we do not require that our peer sync to the same tip as ours, just an equal or greater work tip. (Doing otherwise would risk partitioning the network in the event of a chain split, and is also unnecessary.) - we pick 4 of our outbound peers and do not subject them to this logic, to be more conservative. We don't wish to permit temporary network issues (or an attacker) to excessively disrupt network topology. Github-Pull: #11490 Rebased-From: 5a6d00c6defc587e22c93e63029fdd538ce8858d --- src/net_processing.cpp | 113 ++++++++++++++++++++++++++++++++++++++++- src/net_processing.h | 8 +++ 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 87a36553072c..d81a90323f9f 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -116,6 +116,9 @@ namespace { /** Number of peers from which we're downloading blocks. */ int nPeersWithValidatedDownloads = 0; + /** Number of outbound peers with m_chain_sync.m_protect. */ + int g_outbound_peers_with_protect_from_disconnect = 0; + /** Relay map, protected by cs_main. */ typedef std::map MapRelay; MapRelay mapRelay; @@ -193,6 +196,33 @@ struct CNodeState { */ bool fSupportsDesiredCmpctVersion; + /** State used to enforce CHAIN_SYNC_TIMEOUT + * Only in effect for outbound, non-manual connections, with + * m_protect == false + * Algorithm: if a peer's best known block has less work than our tip, + * set a timeout CHAIN_SYNC_TIMEOUT seconds in the future: + * - If at timeout their best known block now has more work than our tip + * when the timeout was set, then either reset the timeout or clear it + * (after comparing against our current tip's work) + * - If at timeout their best known block still has less work than our + * tip did when the timeout was set, then send a getheaders message, + * and set a shorter timeout, HEADERS_RESPONSE_TIME seconds in future. + * If their best known block is still behind when that new timeout is + * reached, disconnect. + */ + struct ChainSyncTimeoutState { + //! A timeout used for checking whether our peer has sufficiently synced + int64_t m_timeout; + //! A header with the work we require on our peer's chain + const CBlockIndex * m_work_header; + //! After timeout is reached, set to true after sending getheaders + bool m_sent_getheaders; + //! Whether this peer is protected from disconnection due to a bad/slow chain + bool m_protect; + }; + + ChainSyncTimeoutState m_chain_sync; + CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) { fCurrentlyConnected = false; nMisbehavior = 0; @@ -215,6 +245,7 @@ struct CNodeState { fHaveWitness = false; fWantsCmpctWitness = false; fSupportsDesiredCmpctVersion = false; + m_chain_sync = { 0, nullptr, false, false }; } }; @@ -495,6 +526,13 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorfInbound || node->m_manual_connection || node->fFeeler || node->fOneShot); +} + void PeerLogicValidation::InitializeNode(CNode *pnode) { CAddress addr = pnode->addr; std::string addrName = pnode->GetAddrName(); @@ -527,6 +565,8 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim nPreferredDownload -= state->fPreferredDownload; nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); assert(nPeersWithValidatedDownloads >= 0); + g_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect; + assert(g_outbound_peers_with_protect_from_disconnect >= 0); mapNodeState.erase(nodeid); @@ -535,6 +575,7 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim assert(mapBlocksInFlight.empty()); assert(nPreferredDownload == 0); assert(nPeersWithValidatedDownloads == 0); + assert(g_outbound_peers_with_protect_from_disconnect == 0); } LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); } @@ -2315,6 +2356,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr assert(pindexLast); UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); + // From here, pindexBestKnownBlock should be guaranteed to be non-null, + // because it is set in UpdateBlockAvailability. Some nullptr checks + // are still present, however, as belt-and-suspenders. + if (nCount == MAX_HEADERS_RESULTS) { // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue @@ -2387,11 +2432,22 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // chainActive.Tip()) because we won't start block download // until we have a headers chain that has at least // nMinimumChainWork, even if a peer has a chain past our tip, - if (!(pfrom->fInbound || pfrom->fWhitelisted || pfrom->m_manual_connection)) { + // as an anti-DoS measure. + if (IsOutboundDisconnectionCandidate(pfrom)) { + LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId()); pfrom->fDisconnect = true; } } } + + if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) { + // If this is an outbound peer, check to see if we should protect + // it from the bad/lagging chain logic. + if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { + nodestate->m_chain_sync.m_protect = true; + ++g_outbound_peers_with_protect_from_disconnect; + } + } } } @@ -2790,6 +2846,58 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic& inter return fMoreWork; } +void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) +{ + AssertLockHeld(cs_main); + + CNodeState &state = *State(pto->GetId()); + const CNetMsgMaker msgMaker(pto->GetSendVersion()); + + if (!state.m_chain_sync.m_protect && IsOutboundDisconnectionCandidate(pto) && state.fSyncStarted) { + // This is an outbound peer subject to disconnection if they don't + // announce a block with as much work as the current tip within + // CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if + // their chain has more work than ours, we should sync to it, + // unless it's invalid, in which case we should find that out and + // disconnect from them elsewhere). + if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork) { + if (state.m_chain_sync.m_timeout != 0) { + state.m_chain_sync.m_timeout = 0; + state.m_chain_sync.m_work_header = nullptr; + state.m_chain_sync.m_sent_getheaders = false; + } + } else if (state.m_chain_sync.m_timeout == 0 || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) { + // Our best block known by this peer is behind our tip, and we're either noticing + // that for the first time, OR this peer was able to catch up to some earlier point + // where we checked against our tip. + // Either way, set a new timeout based on current tip. + state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT; + state.m_chain_sync.m_work_header = chainActive.Tip(); + state.m_chain_sync.m_sent_getheaders = false; + } else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) { + // No evidence yet that our peer has synced to a chain with work equal to that + // of our tip, when we first detected it was behind. Send a single getheaders + // message to give the peer a chance to update us. + if (state.m_chain_sync.m_sent_getheaders) { + // They've run out of time to catch up! + LogPrintf("Disconnecting outbound peer %d for old chain, best known block = %s\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : ""); + pto->fDisconnect = true; + } else { + LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); + state.m_chain_sync.m_sent_getheaders = true; + constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes + // Bump the timeout to allow a response, which could clear the timeout + // (if the response shows the peer has synced), reset the timeout (if + // the peer syncs to the required work but not to our tip), or result + // in disconnect (if we advance to the timeout and pindexBestKnownBlock + // has not sufficiently progressed) + state.m_chain_sync.m_timeout = time_in_seconds + HEADERS_RESPONSE_TIME; + } + } + } +} + class CompareInvMempoolOrder { CTxMemPool *mp; @@ -3256,6 +3364,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic& interruptM } } + // Check that outbound peers have reasonable chains + // GetTime() is used by this anti-DoS logic so we can test this using mocktime + ConsiderEviction(pto, GetTime()); // // Message: getdata (blocks) diff --git a/src/net_processing.h b/src/net_processing.h index 79745cdd42c9..656324bba0c4 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -21,6 +21,12 @@ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; * Timeout = base + per_header * (expected number of headers) */ static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header +/** Protect at least this many outbound peers from disconnection due to slow/ + * behind headers chain. + */ +static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4; +/** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */ +static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes class PeerLogicValidation : public CValidationInterface, public NetEventsInterface { private: @@ -47,6 +53,8 @@ class PeerLogicValidation : public CValidationInterface, public NetEventsInterfa * @return True if there is more work to be done */ bool SendMessages(CNode* pto, std::atomic& interrupt) override; + + void ConsiderEviction(CNode *pto, int64_t time_in_seconds); }; struct CNodeStateStats { From e3272242e25a3b8a4a2bc4ebec85b26ab989b959 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 19 Oct 2017 11:42:47 -0400 Subject: [PATCH 124/196] Add unit test for outbound peer eviction Github-Pull: #11490 Rebased-From: e065249c014a070a8799b2ff947af5b8f012c5c1 --- src/test/DoS_tests.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index b88ad5ed1b8a..7bcf304833f1 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -42,6 +42,51 @@ static NodeId id = 0; BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) +// Test eviction of an outbound peer whose chain never advances +// Mock a node connection, and use mocktime to simulate a peer +// which never sends any headers messages. PeerLogic should +// decide to evict that outbound peer, after the appropriate timeouts. +// Note that we protect 4 outbound nodes from being subject to +// this logic; this test takes advantage of that protection only +// being applied to nodes which send headers with sufficient +// work. +BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) +{ + std::atomic interruptDummy(false); + + // Mock an outbound peer + CAddress addr1(ip(0xa0b0c001), NODE_NONE); + CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", /*fInboundIn=*/ false); + dummyNode1.SetSendVersion(PROTOCOL_VERSION); + + peerLogic->InitializeNode(&dummyNode1); + dummyNode1.nVersion = 1; + dummyNode1.fSuccessfullyConnected = true; + + // This test requires that we have a chain with non-zero work. + BOOST_CHECK(chainActive.Tip() != nullptr); + BOOST_CHECK(chainActive.Tip()->nChainWork > 0); + + // Test starts here + peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders + BOOST_CHECK(dummyNode1.vSendMsg.size() > 0); + dummyNode1.vSendMsg.clear(); + + int64_t nStartTime = GetTime(); + // Wait 21 minutes + SetMockTime(nStartTime+21*60); + peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders + BOOST_CHECK(dummyNode1.vSendMsg.size() > 0); + // Wait 3 more minutes + SetMockTime(nStartTime+24*60); + peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in disconnect + BOOST_CHECK(dummyNode1.fDisconnect == true); + SetMockTime(0); + + bool dummy; + peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); +} + BOOST_AUTO_TEST_CASE(DoS_banning) { std::atomic interruptDummy(false); @@ -71,6 +116,10 @@ BOOST_AUTO_TEST_CASE(DoS_banning) Misbehaving(dummyNode2.GetId(), 50); peerLogic->SendMessages(&dummyNode2, interruptDummy); BOOST_CHECK(connman->IsBanned(addr2)); + + bool dummy; + peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); + peerLogic->FinalizeNode(dummyNode2.GetId(), dummy); } BOOST_AUTO_TEST_CASE(DoS_banscore) @@ -95,6 +144,9 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) peerLogic->SendMessages(&dummyNode1, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); + + bool dummy; + peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); } BOOST_AUTO_TEST_CASE(DoS_bantime) @@ -121,6 +173,9 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime+60*60*24+1); BOOST_CHECK(!connman->IsBanned(addr)); + + bool dummy; + peerLogic->FinalizeNode(dummyNode.GetId(), dummy); } CTransactionRef RandomOrphan() From fc966bbd2b6596f8ac68ef3c345d47fbb5d7e0c9 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 26 Oct 2017 14:46:17 -0400 Subject: [PATCH 125/196] moveonly: factor out headers processing into separate function ProcessMessages will now return earlier when processing headers messages, rather than continuing on (and do nothing). Github-Pull: #11568 Rebased-From: 4637f18522429473e68f6f512a03040e121a446d --- src/net_processing.cpp | 336 +++++++++++++++++++++-------------------- 1 file changed, 173 insertions(+), 163 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d81a90323f9f..eac2853cd7e1 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1193,6 +1193,178 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); } +bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector& headers, const CChainParams& chainparams) +{ + const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + size_t nCount = headers.size(); + + if (nCount == 0) { + // Nothing interesting. Stop asking this peers for more headers. + return true; + } + + const CBlockIndex *pindexLast = nullptr; + { + LOCK(cs_main); + CNodeState *nodestate = State(pfrom->GetId()); + + // If this looks like it could be a block announcement (nCount < + // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that + // don't connect: + // - Send a getheaders message in response to try to connect the chain. + // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that + // don't connect before giving DoS points + // - Once a headers message is received that is valid and does connect, + // nUnconnectingHeaders gets reset back to 0. + if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { + nodestate->nUnconnectingHeaders++; + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", + headers[0].GetHash().ToString(), + headers[0].hashPrevBlock.ToString(), + pindexBestHeader->nHeight, + pfrom->GetId(), nodestate->nUnconnectingHeaders); + // Set hashLastUnknownBlock for this peer, so that if we + // eventually get the headers - even from a different peer - + // we can use this peer to download. + UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); + + if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) { + Misbehaving(pfrom->GetId(), 20); + } + return true; + } + + uint256 hashLastBlock; + for (const CBlockHeader& header : headers) { + if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) { + Misbehaving(pfrom->GetId(), 20); + return error("non-continuous headers sequence"); + } + hashLastBlock = header.GetHash(); + } + } + + CValidationState state; + if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) { + int nDoS; + if (state.IsInvalid(nDoS)) { + if (nDoS > 0) { + LOCK(cs_main); + Misbehaving(pfrom->GetId(), nDoS); + } + return error("invalid header received"); + } + } + + { + LOCK(cs_main); + CNodeState *nodestate = State(pfrom->GetId()); + if (nodestate->nUnconnectingHeaders > 0) { + LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders); + } + nodestate->nUnconnectingHeaders = 0; + + assert(pindexLast); + UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); + + // From here, pindexBestKnownBlock should be guaranteed to be non-null, + // because it is set in UpdateBlockAvailability. Some nullptr checks + // are still present, however, as belt-and-suspenders. + + if (nCount == MAX_HEADERS_RESULTS) { + // Headers message had its maximum size; the peer may have more headers. + // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue + // from there instead. + LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); + } + + bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); + // If this set of headers is valid and ends in a block with at least as + // much work as our tip, download as much as possible. + if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { + std::vector vToFetch; + const CBlockIndex *pindexWalk = pindexLast; + // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. + while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && + !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) && + (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { + // We don't have this block, and it's not yet in flight. + vToFetch.push_back(pindexWalk); + } + pindexWalk = pindexWalk->pprev; + } + // If pindexWalk still isn't on our main chain, we're looking at a + // very large reorg at a time we think we're close to caught up to + // the main chain -- this shouldn't really happen. Bail out on the + // direct fetch and rely on parallel download instead. + if (!chainActive.Contains(pindexWalk)) { + LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", + pindexLast->GetBlockHash().ToString(), + pindexLast->nHeight); + } else { + std::vector vGetData; + // Download as much as possible, from earliest to latest. + for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { + if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + // Can't download any more from this peer + break; + } + uint32_t nFetchFlags = GetFetchFlags(pfrom); + vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); + MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex); + LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", + pindex->GetBlockHash().ToString(), pfrom->GetId()); + } + if (vGetData.size() > 1) { + LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", + pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); + } + if (vGetData.size() > 0) { + if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) { + // In any case, we want to download using a compact block, not a regular one + vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); + } + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + } + } + } + // If we're in IBD, we want outbound peers that will serve us a useful + // chain. Disconnect peers that are on chains with insufficient work. + if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) { + // When nCount < MAX_HEADERS_RESULTS, we know we have no more + // headers to fetch from this peer. + if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { + // This peer has too little work on their headers chain to help + // us sync -- disconnect if using an outbound slot (unless + // whitelisted or addnode). + // Note: We compare their tip to nMinimumChainWork (rather than + // chainActive.Tip()) because we won't start block download + // until we have a headers chain that has at least + // nMinimumChainWork, even if a peer has a chain past our tip, + // as an anti-DoS measure. + if (IsOutboundDisconnectionCandidate(pfrom)) { + LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId()); + pfrom->fDisconnect = true; + } + } + } + + if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) { + // If this is an outbound peer, check to see if we should protect + // it from the bad/lagging chain logic. + if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { + nodestate->m_chain_sync.m_protect = true; + ++g_outbound_peers_with_protect_from_disconnect; + } + } + } + + return true; +} + bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic& interruptMsgProc) { LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId()); @@ -2286,169 +2458,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr ReadCompactSize(vRecv); // ignore tx count; assume it is 0. } - if (nCount == 0) { - // Nothing interesting. Stop asking this peers for more headers. - return true; - } - - const CBlockIndex *pindexLast = nullptr; - { - LOCK(cs_main); - CNodeState *nodestate = State(pfrom->GetId()); - - // If this looks like it could be a block announcement (nCount < - // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that - // don't connect: - // - Send a getheaders message in response to try to connect the chain. - // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that - // don't connect before giving DoS points - // - Once a headers message is received that is valid and does connect, - // nUnconnectingHeaders gets reset back to 0. - if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { - nodestate->nUnconnectingHeaders++; - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); - LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", - headers[0].GetHash().ToString(), - headers[0].hashPrevBlock.ToString(), - pindexBestHeader->nHeight, - pfrom->GetId(), nodestate->nUnconnectingHeaders); - // Set hashLastUnknownBlock for this peer, so that if we - // eventually get the headers - even from a different peer - - // we can use this peer to download. - UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); - - if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) { - Misbehaving(pfrom->GetId(), 20); - } - return true; - } - - uint256 hashLastBlock; - for (const CBlockHeader& header : headers) { - if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) { - Misbehaving(pfrom->GetId(), 20); - return error("non-continuous headers sequence"); - } - hashLastBlock = header.GetHash(); - } - } - - CValidationState state; - if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) { - int nDoS; - if (state.IsInvalid(nDoS)) { - if (nDoS > 0) { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), nDoS); - } - return error("invalid header received"); - } - } - - { - LOCK(cs_main); - CNodeState *nodestate = State(pfrom->GetId()); - if (nodestate->nUnconnectingHeaders > 0) { - LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders); - } - nodestate->nUnconnectingHeaders = 0; - - assert(pindexLast); - UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); - - // From here, pindexBestKnownBlock should be guaranteed to be non-null, - // because it is set in UpdateBlockAvailability. Some nullptr checks - // are still present, however, as belt-and-suspenders. - - if (nCount == MAX_HEADERS_RESULTS) { - // Headers message had its maximum size; the peer may have more headers. - // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue - // from there instead. - LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); - } - - bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); - // If this set of headers is valid and ends in a block with at least as - // much work as our tip, download as much as possible. - if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { - std::vector vToFetch; - const CBlockIndex *pindexWalk = pindexLast; - // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. - while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && - !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) && - (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { - // We don't have this block, and it's not yet in flight. - vToFetch.push_back(pindexWalk); - } - pindexWalk = pindexWalk->pprev; - } - // If pindexWalk still isn't on our main chain, we're looking at a - // very large reorg at a time we think we're close to caught up to - // the main chain -- this shouldn't really happen. Bail out on the - // direct fetch and rely on parallel download instead. - if (!chainActive.Contains(pindexWalk)) { - LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", - pindexLast->GetBlockHash().ToString(), - pindexLast->nHeight); - } else { - std::vector vGetData; - // Download as much as possible, from earliest to latest. - for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { - if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - // Can't download any more from this peer - break; - } - uint32_t nFetchFlags = GetFetchFlags(pfrom); - vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); - MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex); - LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", - pindex->GetBlockHash().ToString(), pfrom->GetId()); - } - if (vGetData.size() > 1) { - LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", - pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); - } - if (vGetData.size() > 0) { - if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) { - // In any case, we want to download using a compact block, not a regular one - vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); - } - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); - } - } - } - // If we're in IBD, we want outbound peers that will serve us a useful - // chain. Disconnect peers that are on chains with insufficient work. - if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) { - // When nCount < MAX_HEADERS_RESULTS, we know we have no more - // headers to fetch from this peer. - if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { - // This peer has too little work on their headers chain to help - // us sync -- disconnect if using an outbound slot (unless - // whitelisted or addnode). - // Note: We compare their tip to nMinimumChainWork (rather than - // chainActive.Tip()) because we won't start block download - // until we have a headers chain that has at least - // nMinimumChainWork, even if a peer has a chain past our tip, - // as an anti-DoS measure. - if (IsOutboundDisconnectionCandidate(pfrom)) { - LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId()); - pfrom->fDisconnect = true; - } - } - } - - if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) { - // If this is an outbound peer, check to see if we should protect - // it from the bad/lagging chain logic. - if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { - nodestate->m_chain_sync.m_protect = true; - ++g_outbound_peers_with_protect_from_disconnect; - } - } - } + return ProcessHeadersMessage(pfrom, connman, headers, chainparams); } else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing From 59b210d9a7fec79afba07d2ea90b190ce1d74209 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 26 Oct 2017 14:54:33 -0400 Subject: [PATCH 126/196] Disconnect outbound peers relaying invalid headers Github-Pull: #11568 Rebased-From: 37886d5e2f9992678dea4b1bd893f4f10d61d3ad --- src/net_processing.cpp | 61 +++++++++++++++++++++++++++++++++++------- src/validation.cpp | 4 ++- src/validation.h | 3 ++- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index eac2853cd7e1..f677915de12e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1193,7 +1193,7 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); } -bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector& headers, const CChainParams& chainparams) +bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector& headers, const CChainParams& chainparams, bool punish_duplicate_invalid) { const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); size_t nCount = headers.size(); @@ -1246,13 +1246,48 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve } CValidationState state; - if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) { + CBlockHeader first_invalid_header; + if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) { int nDoS; if (state.IsInvalid(nDoS)) { if (nDoS > 0) { LOCK(cs_main); Misbehaving(pfrom->GetId(), nDoS); } + if (punish_duplicate_invalid && mapBlockIndex.find(first_invalid_header.GetHash()) != mapBlockIndex.end()) { + // Goal: don't allow outbound peers to use up our outbound + // connection slots if they are on incompatible chains. + // + // We ask the caller to set punish_invalid appropriately based + // on the peer and the method of header delivery (compact + // blocks are allowed to be invalid in some circumstances, + // under BIP 152). + // Here, we try to detect the narrow situation that we have a + // valid block header (ie it was valid at the time the header + // was received, and hence stored in mapBlockIndex) but know the + // block is invalid, and that a peer has announced that same + // block as being on its active chain. + // Disconnect the peer in such a situation. + // + // Note: if the header that is invalid was not accepted to our + // mapBlockIndex at all, that may also be grounds for + // disconnecting the peer, as the chain they are on is likely + // to be incompatible. However, there is a circumstance where + // that does not hold: if the header's timestamp is more than + // 2 hours ahead of our current time. In that case, the header + // may become valid in the future, and we don't want to + // disconnect a peer merely for serving us one too-far-ahead + // block header, to prevent an attacker from splitting the + // network by mining a block right at the 2 hour boundary. + // + // TODO: update the DoS logic (or, rather, rewrite the + // DoS-interface between validation and net_processing) so that + // the interface is cleaner, and so that we disconnect on all the + // reasons that a peer's headers chain is incompatible + // with ours (eg block->nVersion softforks, MTP violations, + // etc), and not just the duplicate-invalid case. + pfrom->fDisconnect = true; + } return error("invalid header received"); } } @@ -2197,7 +2232,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // If we end up treating this as a plain headers message, call that as well // without cs_main. bool fRevertToHeaderProcessing = false; - CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION); // Keep a CBlock for "optimistic" compactblock reconstructions (see // below) @@ -2314,10 +2348,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } else { // If this was an announce-cmpctblock, we want the same treatment as a header message - // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions) - std::vector headers; - headers.push_back(cmpctblock.header); - vHeadersMsg << headers; fRevertToHeaderProcessing = true; } } @@ -2326,8 +2356,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (fProcessBLOCKTXN) return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc); - if (fRevertToHeaderProcessing) - return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman, interruptMsgProc); + if (fRevertToHeaderProcessing) { + // Headers received from HB compact block peers are permitted to be + // relayed before full validation (see BIP 152), so we don't want to disconnect + // the peer if the header turns out to be for an invalid block. + // Note that if a peer tries to build on an invalid chain, that + // will be detected and the peer will be banned. + return ProcessHeadersMessage(pfrom, connman, {cmpctblock.header}, chainparams, /*punish_duplicate_invalid=*/false); + } if (fBlockReconstructed) { // If we got here, we were able to optimistically reconstruct a @@ -2458,7 +2494,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr ReadCompactSize(vRecv); // ignore tx count; assume it is 0. } - return ProcessHeadersMessage(pfrom, connman, headers, chainparams); + // Headers received via a HEADERS message should be valid, and reflect + // the chain the peer is on. If we receive a known-invalid header, + // disconnect the peer if it is using one of our outbound connection + // slots. + bool should_punish = !pfrom->fInbound && !pfrom->m_manual_connection; + return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish); } else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing diff --git a/src/validation.cpp b/src/validation.cpp index 3bff2d822876..c52f8bf70b60 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3064,13 +3064,15 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state } // Exposed wrapper for AcceptBlockHeader -bool ProcessNewBlockHeaders(const std::vector& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex) +bool ProcessNewBlockHeaders(const std::vector& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid) { + if (first_invalid != nullptr) first_invalid->SetNull(); { LOCK(cs_main); for (const CBlockHeader& header : headers) { CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast if (!AcceptBlockHeader(header, state, chainparams, &pindex)) { + if (first_invalid) *first_invalid = header; return false; } if (ppindex) { diff --git a/src/validation.h b/src/validation.h index f3d88d318090..4acdac81c926 100644 --- a/src/validation.h +++ b/src/validation.h @@ -248,8 +248,9 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr); +bool ProcessNewBlockHeaders(const std::vector& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr, CBlockHeader *first_invalid=nullptr); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); From ec8dedff4683220cb30b69df7f987546536565ab Mon Sep 17 00:00:00 2001 From: practicalswift Date: Mon, 30 Oct 2017 14:28:19 +0100 Subject: [PATCH 127/196] net: Add missing lock in ProcessHeadersMessage(...) Reading the variable mapBlockIndex requires holding the mutex cs_main. The new "Disconnect outbound peers relaying invalid headers" code added in commit 37886d5e2f9992678dea4b1bd893f4f10d61d3ad and merged as part of #11568 two days ago did not lock cs_main prior to accessing mapBlockIndex. Github-Pull: #11578 Rebased-From: 2530bf27b72e53cc6ffec27de35f3b487984833d --- src/net_processing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f677915de12e..69db5d74283c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1250,8 +1250,8 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) { int nDoS; if (state.IsInvalid(nDoS)) { + LOCK(cs_main); if (nDoS > 0) { - LOCK(cs_main); Misbehaving(pfrom->GetId(), nDoS); } if (punish_duplicate_invalid && mapBlockIndex.find(first_invalid_header.GetHash()) != mapBlockIndex.end()) { From e976c36ddf183982d172da3127dc613111a25b42 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 11 Oct 2017 15:38:56 -0400 Subject: [PATCH 128/196] Rewrite p2p-acceptblock in preparation for slight behavior changes Removes checking whitelisted behavior (which will be removed, the difference in behavior here makes little sense) and no longer requires that blocks at the same work as our tip be dropped if not requested (in part because we *do* request those blocks). Github-Pull: #11531 Rebased-From: 3b4ac43bc371561b5fa559bccb17dc0702bd4b69 --- test/functional/p2p-acceptblock.py | 236 +++++++++++++++-------------- 1 file changed, 122 insertions(+), 114 deletions(-) diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 27ae0c27e196..9b2c1a73fc2f 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -4,42 +4,32 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test processing of unrequested blocks. -Since behavior differs when receiving unrequested blocks from whitelisted peers -versus non-whitelisted peers, this tests the behavior of both (effectively two -separate tests running in parallel). +Setup: two nodes, node0+node1, not connected to each other. Node1 will have +nMinimumChainWork set to 0x10, so it won't process low-work unrequested blocks. -Setup: three nodes, node0+node1+node2, not connected to each other. Node0 does not -whitelist localhost, but node1 does. They will each be on their own chain for -this test. Node2 will have nMinimumChainWork set to 0x10, so it won't process -low-work unrequested blocks. - -We have one NodeConn connection to each, test_node, white_node, and min_work_node, -respectively. +We have one NodeConn connection to node0 called test_node, and one to node1 +called min_work_node. The test: 1. Generate one block on each node, to leave IBD. 2. Mine a new block on each tip, and deliver to each node from node's peer. - The tip should advance for node0 and node1, but node2 should skip processing - due to nMinimumChainWork. + The tip should advance for node0, but node1 should skip processing due to + nMinimumChainWork. -Node2 is unused in tests 3-7: +Node1 is unused in tests 3-7: -3. Mine a block that forks the previous block, and deliver to each node from - corresponding peer. - Node0 should not process this block (just accept the header), because it is - unrequested and doesn't have more work than the tip. - Node1 should process because this is coming from a whitelisted peer. +3. Mine a block that forks from the genesis block, and deliver to test_node. + Node0 should not process this block (just accept the header), because it + is unrequested and doesn't have more or equal work to the tip. -4. Send another block that builds on the forking block. - Node0 should process this block but be stuck on the shorter chain, because - it's missing an intermediate block. - Node1 should reorg to this longer chain. +4a,b. Send another two blocks that build on the forking block. + Node0 should process the second block but be stuck on the shorter chain, + because it's missing an intermediate block. -4b.Send 288 more blocks on the longer chain. +4c.Send 288 more blocks on the longer chain (the number of blocks ahead + we currently store). Node0 should process all but the last block (too far ahead in height). - Send all headers to Node1, and then send the last block in that chain. - Node1 should accept the block because it's coming from a whitelisted peer. 5. Send a duplicate of the block in #3 to Node0. Node0 should not process the block because it is unrequested, and stay on @@ -52,7 +42,7 @@ 7. Send Node0 the missing block again. Node0 should process and the tip should advance. -8. Test Node2 is able to sync when connected to node0 (which should have sufficient +8. Test Node1 is able to sync when connected to node0 (which should have sufficient work on its chain). """ @@ -71,8 +61,8 @@ def add_options(self, parser): def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 3 - self.extra_args = [[], ["-whitelist=127.0.0.1"], ["-minimumchainwork=0x10"]] + self.num_nodes = 2 + self.extra_args = [[], ["-minimumchainwork=0x10"]] def setup_network(self): # Node0 will be used to test behavior of processing unrequested blocks @@ -84,132 +74,149 @@ def setup_network(self): def run_test(self): # Setup the p2p connections and start up the network thread. - test_node = NodeConnCB() # connects to node0 (not whitelisted) - white_node = NodeConnCB() # connects to node1 (whitelisted) - min_work_node = NodeConnCB() # connects to node2 (not whitelisted) + test_node = NodeConnCB() # connects to node0 + min_work_node = NodeConnCB() # connects to node1 connections = [] connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)) - connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node)) - connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], min_work_node)) + connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], min_work_node)) test_node.add_connection(connections[0]) - white_node.add_connection(connections[1]) - min_work_node.add_connection(connections[2]) + min_work_node.add_connection(connections[1]) NetworkThread().start() # Start up network handling in another thread # Test logic begins here test_node.wait_for_verack() - white_node.wait_for_verack() min_work_node.wait_for_verack() - # 1. Have nodes mine a block (nodes1/2 leave IBD) + # 1. Have nodes mine a block (leave IBD) [ n.generate(1) for n in self.nodes ] tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ] # 2. Send one block that builds on each tip. - # This should be accepted by nodes 1/2 + # This should be accepted by node0 blocks_h2 = [] # the height 2 blocks on each node's chain block_time = int(time.time()) + 1 - for i in range(3): + for i in range(2): blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time)) blocks_h2[i].solve() block_time += 1 test_node.send_message(msg_block(blocks_h2[0])) - white_node.send_message(msg_block(blocks_h2[1])) - min_work_node.send_message(msg_block(blocks_h2[2])) + min_work_node.send_message(msg_block(blocks_h2[1])) - for x in [test_node, white_node, min_work_node]: + for x in [test_node, min_work_node]: x.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) - assert_equal(self.nodes[1].getblockcount(), 2) - assert_equal(self.nodes[2].getblockcount(), 1) - self.log.info("First height 2 block accepted by node0/node1; correctly rejected by node2") + assert_equal(self.nodes[1].getblockcount(), 1) + self.log.info("First height 2 block accepted by node0; correctly rejected by node1") - # 3. Send another block that builds on the original tip. - blocks_h2f = [] # Blocks at height 2 that fork off the main chain - for i in range(2): - blocks_h2f.append(create_block(tips[i], create_coinbase(2), blocks_h2[i].nTime+1)) - blocks_h2f[i].solve() - test_node.send_message(msg_block(blocks_h2f[0])) - white_node.send_message(msg_block(blocks_h2f[1])) + # 3. Send another block that builds on genesis. + block_h1f = create_block(int("0x" + self.nodes[0].getblockhash(0), 0), create_coinbase(1), block_time) + block_time += 1 + block_h1f.solve() + test_node.send_message(msg_block(block_h1f)) - for x in [test_node, white_node]: - x.sync_with_ping() + test_node.sync_with_ping() + tip_entry_found = False for x in self.nodes[0].getchaintips(): - if x['hash'] == blocks_h2f[0].hash: + if x['hash'] == block_h1f.hash: assert_equal(x['status'], "headers-only") + tip_entry_found = True + assert(tip_entry_found) + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_h1f.hash) + + # 4. Send another two block that build on the fork. + block_h2f = create_block(block_h1f.sha256, create_coinbase(2), block_time) + block_time += 1 + block_h2f.solve() + test_node.send_message(msg_block(block_h2f)) - for x in self.nodes[1].getchaintips(): - if x['hash'] == blocks_h2f[1].hash: - assert_equal(x['status'], "valid-headers") + test_node.sync_with_ping() + # Since the earlier block was not processed by node, the new block + # can't be fully validated. + tip_entry_found = False + for x in self.nodes[0].getchaintips(): + if x['hash'] == block_h2f.hash: + assert_equal(x['status'], "headers-only") + tip_entry_found = True + assert(tip_entry_found) - self.log.info("Second height 2 block accepted only from whitelisted peer") + # But this block should be accepted by node since it has equal work. + # TODO: We currently drop this block but likely shouldn't + #self.nodes[0].getblock(block_h2f.hash) + self.log.info("Second height 2 block accepted, but not reorg'ed to") - # 4. Now send another block that builds on the forking chain. - blocks_h3 = [] - for i in range(2): - blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(3), blocks_h2f[i].nTime+1)) - blocks_h3[i].solve() - test_node.send_message(msg_block(blocks_h3[0])) - white_node.send_message(msg_block(blocks_h3[1])) + # 4b. Now send another block that builds on the forking chain. + block_h3 = create_block(block_h2f.sha256, create_coinbase(3), block_h2f.nTime+1) + block_h3.solve() + test_node.send_message(msg_block(block_h3)) - for x in [test_node, white_node]: - x.sync_with_ping() - # Since the earlier block was not processed by node0, the new block + test_node.sync_with_ping() + # Since the earlier block was not processed by node, the new block # can't be fully validated. + tip_entry_found = False for x in self.nodes[0].getchaintips(): - if x['hash'] == blocks_h3[0].hash: + if x['hash'] == block_h3.hash: assert_equal(x['status'], "headers-only") + tip_entry_found = True + assert(tip_entry_found) + self.nodes[0].getblock(block_h3.hash) + + # But this block should be accepted by node since it has more work. + self.nodes[0].getblock(block_h3.hash) + self.log.info("Unrequested more-work block accepted") + + # 4c. Now mine 288 more blocks and deliver; all should be processed but + # the last (height-too-high) on node (as long as its not missing any headers) + tip = block_h3 + all_blocks = [] + for i in range(288): + next_block = create_block(tip.sha256, create_coinbase(i + 4), tip.nTime+1) + next_block.solve() + all_blocks.append(next_block) + tip = next_block + + # Now send the block at height 5 and check that it wasn't accepted (missing header) + test_node.send_message(msg_block(all_blocks[1])) + test_node.sync_with_ping() + assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock, all_blocks[1].hash) + assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblockheader, all_blocks[1].hash) - # But this block should be accepted by node0 since it has more work. - self.nodes[0].getblock(blocks_h3[0].hash) - self.log.info("Unrequested more-work block accepted from non-whitelisted peer") + # The block at height 5 should be accepted if we provide the missing header, though + headers_message = msg_headers() + headers_message.headers.append(CBlockHeader(all_blocks[0])) + test_node.send_message(headers_message) + test_node.send_message(msg_block(all_blocks[1])) + test_node.sync_with_ping() + self.nodes[0].getblock(all_blocks[1].hash) - # Node1 should have accepted and reorged. - assert_equal(self.nodes[1].getblockcount(), 3) - self.log.info("Successfully reorged to length 3 chain from whitelisted peer") + # Now send the blocks in all_blocks + for i in range(288): + test_node.send_message(msg_block(all_blocks[i])) + test_node.sync_with_ping() - # 4b. Now mine 288 more blocks and deliver; all should be processed but - # the last (height-too-high) on node0. Node1 should process the tip if - # we give it the headers chain leading to the tip. - tips = blocks_h3 - headers_message = msg_headers() - all_blocks = [] # node0's blocks - for j in range(2): - for i in range(288): - next_block = create_block(tips[j].sha256, create_coinbase(i + 4), tips[j].nTime+1) - next_block.solve() - if j==0: - test_node.send_message(msg_block(next_block)) - all_blocks.append(next_block) - else: - headers_message.headers.append(CBlockHeader(next_block)) - tips[j] = next_block - - time.sleep(2) # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead for x in all_blocks[:-1]: self.nodes[0].getblock(x.hash) assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash) - headers_message.headers.pop() # Ensure the last block is unrequested - white_node.send_message(headers_message) # Send headers leading to tip - white_node.send_message(msg_block(tips[1])) # Now deliver the tip - white_node.sync_with_ping() - self.nodes[1].getblock(tips[1].hash) - self.log.info("Unrequested block far ahead of tip accepted from whitelisted peer") - # 5. Test handling of unrequested block on the node that didn't process # Should still not be processed (even though it has a child that has more # work). - test_node.send_message(msg_block(blocks_h2f[0])) - # Here, if the sleep is too short, the test could falsely succeed (if the - # node hasn't processed the block by the time the sleep returns, and then - # the node processes it and incorrectly advances the tip). - # But this would be caught later on, when we verify that an inv triggers - # a getdata request for this block. + # The node should have requested the blocks at some point, so + # disconnect/reconnect first + connections[0].disconnect_node() + test_node.wait_for_disconnect() + + test_node = NodeConnCB() # connects to node (not whitelisted) + connections[0] = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) + test_node.add_connection(connections[0]) + + test_node.wait_for_verack() + test_node.send_message(msg_block(block_h1f)) + test_node.send_message(msg_block(block_h2f)) # This should not be required + test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) self.log.info("Unrequested block that would complete more-work chain was ignored") @@ -220,27 +227,28 @@ def run_test(self): with mininode_lock: # Clear state so we can check the getdata request test_node.last_message.pop("getdata", None) - test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)])) + test_node.send_message(msg_inv([CInv(2, block_h3.sha256)])) test_node.sync_with_ping() with mininode_lock: getdata = test_node.last_message["getdata"] # Check that the getdata includes the right block - assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256) + assert_equal(getdata.inv[0].hash, block_h1f.sha256) self.log.info("Inv at tip triggered getdata for unprocessed block") # 7. Send the missing block for the third time (now it is requested) - test_node.send_message(msg_block(blocks_h2f[0])) + test_node.send_message(msg_block(block_h1f)) + test_node.send_message(msg_block(block_h2f)) # This should not be required test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 290) self.log.info("Successfully reorged to longer chain from non-whitelisted peer") - # 8. Connect node2 to node0 and ensure it is able to sync - connect_nodes(self.nodes[0], 2) - sync_blocks([self.nodes[0], self.nodes[2]]) - self.log.info("Successfully synced nodes 2 and 0") + # 8. Connect node1 to node0 and ensure it is able to sync + connect_nodes(self.nodes[0], 1) + sync_blocks([self.nodes[0], self.nodes[1]]) + self.log.info("Successfully synced nodes 1 and 0") [ c.disconnect_node() for c in connections ] From c6e4d0ce82cfd9fb775ba5ca5874af207585837b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 11 Oct 2017 16:01:51 -0400 Subject: [PATCH 129/196] Stop always storing blocks from whitelisted peers There is no reason to wish to store blocks on disk always just because a peer is whitelisted. This appears to be a historical quirk to avoid breaking things when the accept limits were added. Github-Pull: #11531 Rebased-From: 3d9c70ca0fd5d42f31114b689714af1825f0ed30 --- src/net_processing.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 69db5d74283c..0697c6bea57e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2509,11 +2509,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->GetId()); - // Process all blocks from whitelisted peers, even if not requested, - // unless we're still syncing with the network. - // Such an unrequested block may still be processed, subject to the - // conditions in AcceptBlock(). - bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); + bool forceProcessing = false; const uint256 hash(pblock->GetHash()); { LOCK(cs_main); From 51001d684b1b26ea5109986b7317ffe24bf71b43 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 11 Oct 2017 16:04:13 -0400 Subject: [PATCH 130/196] Accept unrequested blocks with work equal to our tip This is a simple change that makes our accept requirements the same as our request requirements, (ever so slightly) further decoupling our consensus logic from our FindNextBlocksToDownload logic in net_processing. Github-Pull: #11531 Rebased-From: 932f118e6a3779bb3d6c3cc83963cf34ac150e42 --- src/validation.cpp | 8 ++++---- test/functional/p2p-acceptblock.py | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index c52f8bf70b60..c641cae7e9b6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3102,7 +3102,7 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation // process an unrequested block if it's new and has enough work to // advance our tip, and isn't too many blocks ahead. bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; - bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true); + bool fHasMoreOrSameWork = (chainActive.Tip() ? pindex->nChainWork >= chainActive.Tip()->nChainWork : true); // Blocks that are too out-of-order needlessly limit the effectiveness of // pruning, because pruning will not delete block files that contain any // blocks which are too close in height to the tip. Apply this test @@ -3119,9 +3119,9 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation // and unrequested blocks. if (fAlreadyHave) return true; if (!fRequested) { // If we didn't ask for it: - if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned - if (!fHasMoreWork) return true; // Don't process less-work chains - if (fTooFarAhead) return true; // Block height is too high + if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned + if (!fHasMoreOrSameWork) return true; // Don't process less-work chains + if (fTooFarAhead) return true; // Block height is too high // Protect against DoS attacks from low-work chains. // If our tip is behind, a peer could try to send us diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 9b2c1a73fc2f..36e0bd9ec68c 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -142,8 +142,7 @@ def run_test(self): assert(tip_entry_found) # But this block should be accepted by node since it has equal work. - # TODO: We currently drop this block but likely shouldn't - #self.nodes[0].getblock(block_h2f.hash) + self.nodes[0].getblock(block_h2f.hash) self.log.info("Second height 2 block accepted, but not reorg'ed to") # 4b. Now send another block that builds on the forking chain. @@ -215,7 +214,6 @@ def run_test(self): test_node.wait_for_verack() test_node.send_message(msg_block(block_h1f)) - test_node.send_message(msg_block(block_h2f)) # This should not be required test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) @@ -239,7 +237,6 @@ def run_test(self): # 7. Send the missing block for the third time (now it is requested) test_node.send_message(msg_block(block_h1f)) - test_node.send_message(msg_block(block_h2f)) # This should not be required test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 290) From 92d6105c4e571e557348771bf39bf7bbacc81cd1 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 19 Oct 2017 16:55:31 -0400 Subject: [PATCH 131/196] Reject headers building on invalid chains by tracking invalidity This tracks the set of all known invalid-themselves blocks (ie blocks which we attempted to connect but which were found to be invalid). This is used to cheaply check if new headers build on an invalid chain. While we're at it we also resolve an edge-case in invalidateblock on pruned nodes which results in them needing a reindex if they fail to reorg. Github-Pull: #11531 Rebased-From: 015a5258adffb0cf394f387a95ac9c8afc34cfc3 --- src/validation.cpp | 74 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index c641cae7e9b6..8a92992dba77 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -153,6 +153,26 @@ namespace { /** chainwork for the last block that preciousblock has been applied to. */ arith_uint256 nLastPreciousChainwork = 0; + /** In order to efficiently track invalidity of headers, we keep the set of + * blocks which we tried to connect and found to be invalid here (ie which + * were set to BLOCK_FAILED_VALID since the last restart). We can then + * walk this set and check if a new header is a descendant of something in + * this set, preventing us from having to walk mapBlockIndex when we try + * to connect a bad block and fail. + * + * While this is more complicated than marking everything which descends + * from an invalid block as invalid at the time we discover it to be + * invalid, doing so would require walking all of mapBlockIndex to find all + * descendants. Since this case should be very rare, keeping track of all + * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as + * well. + * + * Because we alreardy walk mapBlockIndex in height-order at startup, we go + * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time, + * instead of putting things in this set. + */ + std::set g_failed_blocks; + /** Dirty block index entries. */ std::set setDirtyBlockIndex; @@ -1168,6 +1188,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew) void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { if (!state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; + g_failed_blocks.insert(pindex); setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); InvalidChainFound(pindex); @@ -2517,17 +2538,18 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C { AssertLockHeld(cs_main); - // Mark the block itself as invalid. - pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); - setBlockIndexCandidates.erase(pindex); + // We first disconnect backwards and then mark the blocks as invalid. + // This prevents a case where pruned nodes may fail to invalidateblock + // and be left unable to start as they have no tip candidates (as there + // are no blocks that meet the "have data and are not invalid per + // nStatus" criteria for inclusion in setBlockIndexCandidates). + + bool pindex_was_in_chain = false; + CBlockIndex *invalid_walk_tip = chainActive.Tip(); DisconnectedBlockTransactions disconnectpool; while (chainActive.Contains(pindex)) { - CBlockIndex *pindexWalk = chainActive.Tip(); - pindexWalk->nStatus |= BLOCK_FAILED_CHILD; - setDirtyBlockIndex.insert(pindexWalk); - setBlockIndexCandidates.erase(pindexWalk); + pindex_was_in_chain = true; // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. if (!DisconnectTip(state, chainparams, &disconnectpool)) { @@ -2538,6 +2560,21 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C } } + // Now mark the blocks we just disconnected as descendants invalid + // (note this may not be all descendants). + while (pindex_was_in_chain && invalid_walk_tip != pindex) { + invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD; + setDirtyBlockIndex.insert(invalid_walk_tip); + setBlockIndexCandidates.erase(invalid_walk_tip); + invalid_walk_tip = invalid_walk_tip->pprev; + } + + // Mark the block itself as invalid. + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + setBlockIndexCandidates.erase(pindex); + g_failed_blocks.insert(pindex); + // DisconnectTip will add transactions to disconnectpool; try to add these // back to the mempool. UpdateMempoolForReorg(disconnectpool, true); @@ -2575,6 +2612,7 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) { // Reset invalid block marker if it was pointing to one of those. pindexBestInvalid = nullptr; } + g_failed_blocks.erase(it->second); } it++; } @@ -3051,6 +3089,21 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime())) return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); + + if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) { + for (const CBlockIndex* failedit : g_failed_blocks) { + if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) { + assert(failedit->nStatus & BLOCK_FAILED_VALID); + CBlockIndex* invalid_walk = pindexPrev; + while (invalid_walk != failedit) { + invalid_walk->nStatus |= BLOCK_FAILED_CHILD; + setDirtyBlockIndex.insert(invalid_walk); + invalid_walk = invalid_walk->pprev; + } + return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + } + } + } } if (pindex == nullptr) pindex = AddToBlockIndex(block); @@ -3477,6 +3530,10 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) pindex->nChainTx = pindex->nTx; } } + if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) { + pindex->nStatus |= BLOCK_FAILED_CHILD; + setDirtyBlockIndex.insert(pindex); + } if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == nullptr)) setBlockIndexCandidates.insert(pindex); if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) @@ -3867,6 +3924,7 @@ void UnloadBlockIndex() nLastBlockFile = 0; nBlockSequenceId = 1; setDirtyBlockIndex.clear(); + g_failed_blocks.clear(); setDirtyFileInfo.clear(); versionbitscache.Clear(); for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { From 5bec7744d112141848e57d7f628dc17597f89dd5 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 11 Oct 2017 16:57:43 -0400 Subject: [PATCH 132/196] [qa] test that invalid blocks on an invalid chain get a disconnect Github-Pull: #11531 Rebased-From: 00dcda60f6ee63d35bec640f27efe2338dd71270 --- test/functional/p2p-acceptblock.py | 84 ++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 36e0bd9ec68c..220b7763694e 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -42,16 +42,20 @@ 7. Send Node0 the missing block again. Node0 should process and the tip should advance. -8. Test Node1 is able to sync when connected to node0 (which should have sufficient -work on its chain). +8. Create a fork which is invalid at a height longer than the current chain + (ie to which the node will try to reorg) but which has headers built on top + of the invalid block. Check that we get disconnected if we send more headers + on the chain the node now knows to be invalid. +9. Test Node1 is able to sync when connected to node0 (which should have sufficient + work on its chain). """ from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * import time -from test_framework.blocktools import create_block, create_coinbase +from test_framework.blocktools import create_block, create_coinbase, create_transaction class AcceptBlockTest(BitcoinTestFramework): def add_options(self, parser): @@ -240,9 +244,81 @@ def run_test(self): test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 290) + self.nodes[0].getblock(all_blocks[286].hash) + assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[287].hash) self.log.info("Successfully reorged to longer chain from non-whitelisted peer") - # 8. Connect node1 to node0 and ensure it is able to sync + # 8. Create a chain which is invalid at a height longer than the + # current chain, but which has more blocks on top of that + block_289f = create_block(all_blocks[284].sha256, create_coinbase(289), all_blocks[284].nTime+1) + block_289f.solve() + block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1) + block_290f.solve() + block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1) + # block_291 spends a coinbase below maturity! + block_291.vtx.append(create_transaction(block_290f.vtx[0], 0, b"42", 1)) + block_291.hashMerkleRoot = block_291.calc_merkle_root() + block_291.solve() + block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1) + block_292.solve() + + # Now send all the headers on the chain and enough blocks to trigger reorg + headers_message = msg_headers() + headers_message.headers.append(CBlockHeader(block_289f)) + headers_message.headers.append(CBlockHeader(block_290f)) + headers_message.headers.append(CBlockHeader(block_291)) + headers_message.headers.append(CBlockHeader(block_292)) + test_node.send_message(headers_message) + + test_node.sync_with_ping() + tip_entry_found = False + for x in self.nodes[0].getchaintips(): + if x['hash'] == block_292.hash: + assert_equal(x['status'], "headers-only") + tip_entry_found = True + assert(tip_entry_found) + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash) + + test_node.send_message(msg_block(block_289f)) + test_node.send_message(msg_block(block_290f)) + + test_node.sync_with_ping() + self.nodes[0].getblock(block_289f.hash) + self.nodes[0].getblock(block_290f.hash) + + test_node.send_message(msg_block(block_291)) + + # At this point we've sent an obviously-bogus block, wait for full processing + # without assuming whether we will be disconnected or not + try: + # Only wait a short while so the test doesn't take forever if we do get + # disconnected + test_node.sync_with_ping(timeout=1) + except AssertionError: + test_node.wait_for_disconnect() + + test_node = NodeConnCB() # connects to node (not whitelisted) + connections[0] = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) + test_node.add_connection(connections[0]) + + NetworkThread().start() # Start up network handling in another thread + test_node.wait_for_verack() + + # We should have failed reorg and switched back to 290 (but have block 291) + assert_equal(self.nodes[0].getblockcount(), 290) + assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) + assert_equal(self.nodes[0].getblock(block_291.hash)["confirmations"], -1) + + # Now send a new header on the invalid chain, indicating we're forked off, and expect to get disconnected + block_293 = create_block(block_292.sha256, create_coinbase(293), block_292.nTime+1) + block_293.solve() + headers_message = msg_headers() + headers_message.headers.append(CBlockHeader(block_293)) + test_node.send_message(headers_message) + test_node.wait_for_disconnect() + + # 9. Connect node1 to node0 and ensure it is able to sync connect_nodes(self.nodes[0], 1) sync_blocks([self.nodes[0], self.nodes[1]]) self.log.info("Successfully synced nodes 1 and 0") From 55b7abfa8a7dd1400f4399f734a1b2b6b439d52a Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 30 Oct 2017 21:28:42 -0400 Subject: [PATCH 133/196] Make p2p-acceptablock not an extended test Github-Pull: #11531 Rebased-From: f3d4adfa6ff5db180ec09d93f78cdc8bfda26f96 --- test/functional/test_runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 714a907ee8da..ca74bb68da7d 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -122,6 +122,7 @@ 'uptime.py', 'resendwallettransactions.py', 'minchainwork.py', + 'p2p-acceptblock.py', ] EXTENDED_SCRIPTS = [ @@ -149,7 +150,6 @@ 'txn_clone.py --mineblock', 'forknotify.py', 'invalidateblock.py', - 'p2p-acceptblock.py', 'replace-by-fee.py', ] From 6baa317b5fa615d463cdf0a2095533f6c10c84de Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 2 Nov 2017 15:02:48 -0400 Subject: [PATCH 134/196] Fix minchainwork test for 0.15 backport --- test/functional/minchainwork.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/functional/minchainwork.py b/test/functional/minchainwork.py index 35cd7ad14180..e136dc2b7c00 100755 --- a/test/functional/minchainwork.py +++ b/test/functional/minchainwork.py @@ -81,6 +81,10 @@ def run_test(self): # we'd expect node1 to have disconnected node0 for serving an # insufficient work chain, in which case we'd need to reconnect them to # continue the test. + # NOTE: before commit 44407100ff9b478d6131a1c38ee993b50b1830df, regtest + # connections were not manual, so the reconnect is necessary. + if (len(self.nodes[0].getpeerinfo()) == 0): + connect_nodes(self.nodes[1], 0) self.sync_all() self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes]) From 7871a7d3be4b89e1605ca29c2269c08f3ae68472 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 24 Aug 2017 11:36:07 -0400 Subject: [PATCH 135/196] Deprecate confusing blockmaxsize, fix getmininginfo output * This removes block-size-limiting code in favor of GBT clients doing the limiting themselves (if at all). * -blockmaxsize is deprecated and only used to calculate an implied blockmaxweight, addressing confusion from multiple users. * getmininginfo's currentblocksize return value was returning garbage values, and has been removed, also removing a GetSerializeSize call in some block generation inner loops and potentially addressing some performance edge cases. Github-Pull: #11100 Rebased-From: ba206d2c63a8d3cbd4a8dd47e9ef126af1bb3bb9 --- src/init.cpp | 11 ++++++++++- src/miner.cpp | 38 ++------------------------------------ src/miner.h | 4 +--- src/policy/policy.h | 2 -- src/rpc/mining.cpp | 2 -- src/validation.h | 1 - test/functional/mining.py | 1 - 7 files changed, 13 insertions(+), 46 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4efc06a4be9b..4282b0911dad 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -500,7 +500,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Block creation options:")); strUsage += HelpMessageOpt("-blockmaxweight=", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); - strUsage += HelpMessageOpt("-blockmaxsize=", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); + strUsage += HelpMessageOpt("-blockmaxsize=", _("Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight")); strUsage += HelpMessageOpt("-blockmintxfee=", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); if (showDebug) strUsage += HelpMessageOpt("-blockversion=", "Override block version to test forking scenarios"); @@ -802,6 +802,15 @@ void InitParameterInteraction() if (gArgs.SoftSetBoolArg("-whitelistrelay", true)) LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); } + + if (gArgs.IsArgSet("-blockmaxsize")) { + unsigned int max_size = gArgs.GetArg("-blockmaxsize", 0); + if (gArgs.SoftSetArg("blockmaxweight", strprintf("%d", max_size * WITNESS_SCALE_FACTOR))) { + LogPrintf("%s: parameter interaction: -blockmaxsize=%d -> setting -blockmaxweight=%d (-blockmaxsize is deprecated!)\n", __func__, max_size, max_size * WITNESS_SCALE_FACTOR); + } else { + LogPrintf("%s: Ignoring blockmaxsize setting which is overridden by blockmaxweight", __func__); + } + } } static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) diff --git a/src/miner.cpp b/src/miner.cpp index 403d3d4e4a9f..9d571a2eb022 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -43,7 +43,6 @@ // its ancestors. uint64_t nLastBlockTx = 0; -uint64_t nLastBlockSize = 0; uint64_t nLastBlockWeight = 0; int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) @@ -64,7 +63,6 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam BlockAssembler::Options::Options() { blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; - nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; } BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params) @@ -72,10 +70,6 @@ BlockAssembler::BlockAssembler(const CChainParams& params, const Options& option blockMinFeeRate = options.blockMinFeeRate; // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity: nBlockMaxWeight = std::max(4000, std::min(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight)); - // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity: - nBlockMaxSize = std::max(1000, std::min(MAX_BLOCK_SERIALIZED_SIZE - 1000, options.nBlockMaxSize)); - // Whether we need to account for byte usage (in addition to weight usage) - fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000); } static BlockAssembler::Options DefaultOptions(const CChainParams& params) @@ -85,20 +79,7 @@ static BlockAssembler::Options DefaultOptions(const CChainParams& params) // If only one is given, only restrict the specified resource. // If both are given, restrict both. BlockAssembler::Options options; - options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; - options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; - bool fWeightSet = false; - if (gArgs.IsArgSet("-blockmaxweight")) { - options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); - options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE; - fWeightSet = true; - } - if (gArgs.IsArgSet("-blockmaxsize")) { - options.nBlockMaxSize = gArgs.GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); - if (!fWeightSet) { - options.nBlockMaxWeight = options.nBlockMaxSize * WITNESS_SCALE_FACTOR; - } - } + options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); if (gArgs.IsArgSet("-blockmintxfee")) { CAmount n = 0; ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n); @@ -116,7 +97,6 @@ void BlockAssembler::resetBlock() inBlock.clear(); // Reserve space for coinbase tx - nBlockSize = 1000; nBlockWeight = 4000; nBlockSigOpsCost = 400; fIncludeWitness = false; @@ -175,7 +155,6 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc int64_t nTime1 = GetTimeMicros(); nLastBlockTx = nBlockTx; - nLastBlockSize = nBlockSize; nLastBlockWeight = nBlockWeight; // Create coinbase transaction. @@ -190,8 +169,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc 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); + LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); @@ -238,22 +216,13 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost // - transaction finality (locktime) // - premature witness (in case segwit transactions are added to mempool before // segwit activation) -// - serialized size (in case -blockmaxsize is in use) bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) { - uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting for (const CTxMemPool::txiter it : package) { if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff)) return false; if (!fIncludeWitness && it->GetTx().HasWitness()) return false; - if (fNeedSizeAccounting) { - uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); - if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) { - return false; - } - nPotentialBlockSize += nTxSize; - } } return true; } @@ -263,9 +232,6 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) pblock->vtx.emplace_back(iter->GetSharedTx()); pblocktemplate->vTxFees.push_back(iter->GetFee()); pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost()); - if (fNeedSizeAccounting) { - nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION); - } nBlockWeight += iter->GetTxWeight(); ++nBlockTx; nBlockSigOpsCost += iter->GetSigOpCost(); diff --git a/src/miner.h b/src/miner.h index 5c9cfd78f044..f68f77c0bacc 100644 --- a/src/miner.h +++ b/src/miner.h @@ -139,13 +139,11 @@ class BlockAssembler // Configuration parameters for the block size bool fIncludeWitness; - unsigned int nBlockMaxWeight, nBlockMaxSize; - bool fNeedSizeAccounting; + unsigned int nBlockMaxWeight; CFeeRate blockMinFeeRate; // Information on the current status of the block uint64_t nBlockWeight; - uint64_t nBlockSize; uint64_t nBlockTx; uint64_t nBlockSigOpsCost; CAmount nFees; diff --git a/src/policy/policy.h b/src/policy/policy.h index c06820f84e6d..702471383426 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -16,8 +16,6 @@ class CCoinsViewCache; class CTxOut; -/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000; /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index f498b5c8ea87..441cd1e8f4d4 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -195,7 +195,6 @@ UniValue getmininginfo(const JSONRPCRequest& request) "\nResult:\n" "{\n" " \"blocks\": nnn, (numeric) The current block\n" - " \"currentblocksize\": nnn, (numeric) The last block size\n" " \"currentblockweight\": nnn, (numeric) The last block weight\n" " \"currentblocktx\": nnn, (numeric) The last block transaction\n" " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" @@ -214,7 +213,6 @@ UniValue getmininginfo(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); diff --git a/src/validation.h b/src/validation.h index 4acdac81c926..804fb644d994 100644 --- a/src/validation.h +++ b/src/validation.h @@ -161,7 +161,6 @@ extern CTxMemPool mempool; typedef std::unordered_map BlockMap; extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; -extern uint64_t nLastBlockSize; extern uint64_t nLastBlockWeight; extern const std::string strMessageMagic; extern CWaitableCriticalSection csBestBlock; diff --git a/test/functional/mining.py b/test/functional/mining.py index 085bdb568bdc..9aee06864efc 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -38,7 +38,6 @@ def run_test(self): mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['chain'], 'regtest') - assert_equal(mining_info['currentblocksize'], 0) assert_equal(mining_info['currentblocktx'], 0) assert_equal(mining_info['currentblockweight'], 0) assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10')) From 4c82cea99b514193672d8145c7777f3e715694ec Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 25 Aug 2017 12:06:13 -0400 Subject: [PATCH 136/196] Use a sensible default for blockmaxweight No sensible user will ever keep the default settings here, so not having sensible defaults only serves to screw users who are paying less attention, which makes for terrible defaults. Github-Pull: #11100 Rebased-From: 3dc263c9b9068ee9793b6c7a0023eff16d70fb8f --- src/policy/policy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/policy/policy.h b/src/policy/policy.h index 702471383426..ef71dd73bcd5 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -17,7 +17,7 @@ class CCoinsViewCache; class CTxOut; /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000; +static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000; /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000; /** The maximum weight for transactions we're willing to relay/mine */ From bb83fe19026b4d86a6514e6f3ed5f4d71f1bc4bc Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 25 Aug 2017 11:27:03 -0400 Subject: [PATCH 137/196] Add release notes describing blockmaxweight deprecation Github-Pull: #11100 Rebased-From: 6f703e9bf11c5f2fcb0fca0e4243fce6b4b9d35a --- doc/release-notes.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index 1bb02e376148..6e4bd03cd5ae 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -72,6 +72,22 @@ Notable changes value is passed, instead of returning a list of all wallet transactions since the genesis block. +Miner block size limiting deprecated +------------------------------------ + +Though blockmaxweight has been preferred for limiting the size of blocks returned by +getblocktemplate since 0.13.0, blockmaxsize remained as an option for those who wished +to limit their block size directly. Using this option resulted in a few UI issues as +well as non-optimal fee selection and ever-so-slightly worse performance, and has thus +now been deprecated. Further, the blockmaxsize option is now used only to calculate an +implied blockmaxweight, instead of limiting block size directly. Any miners who wish +to limit their blocks by size, instead of by weight, will have to do so manually by +removing transactions from their block template directly. + +Low-level RPC changes +---------------------- +- The "currentblocksize" value in getmininginfo has been removed. + Credits ======= From 49bf090185ad7f6aa4d86bae8aeedfcaf396771c Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 23 Oct 2017 13:36:15 -0400 Subject: [PATCH 138/196] net: Allow connecting to extra outbound peers Github-Pull: #11560 Rebased-From: 2d4327db1973a354e9e4153de6958d49120fcde8 --- src/net.cpp | 34 +++++++++++++++++++++++++++++++++- src/net.h | 18 ++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/net.cpp b/src/net.cpp index a07b22bf5d81..1687900ed762 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1670,6 +1670,36 @@ void CConnman::ProcessOneShot() } } +bool CConnman::GetTryNewOutboundPeer() +{ + return m_try_another_outbound_peer; +} + +void CConnman::SetTryNewOutboundPeer(bool flag) +{ + m_try_another_outbound_peer = flag; +} + +// Return the number of peers we have over our outbound connection limit +// Exclude peers that are marked for disconnect, or are going to be +// disconnected soon (eg one-shots and feelers) +// Also exclude peers that haven't finished initial connection handshake yet +// (so that we don't decide we're over our desired connection limit, and then +// evict some peer that has finished the handshake) +int CConnman::GetExtraOutboundCount() +{ + int nOutbound = 0; + { + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) { + if (!pnode->fInbound && !pnode->m_manual_connection && !pnode->fFeeler && !pnode->fDisconnect && !pnode->fOneShot && pnode->fSuccessfullyConnected) { + ++nOutbound; + } + } + } + return std::max(nOutbound - nMaxOutbound, 0); +} + void CConnman::ThreadOpenConnections() { // Connect to specific addresses @@ -1764,7 +1794,8 @@ void CConnman::ThreadOpenConnections() // * Only make a feeler connection once every few minutes. // bool fFeeler = false; - if (nOutbound >= nMaxOutbound) { + + if (nOutbound >= nMaxOutbound && !GetTryNewOutboundPeer()) { int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds). if (nTime > nNextFeeler) { nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); @@ -2207,6 +2238,7 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe semOutbound = nullptr; semAddnode = nullptr; flagInterruptMsgProc = false; + SetTryNewOutboundPeer(false); Options connOptions; Init(connOptions); diff --git a/src/net.h b/src/net.h index 9bb1d3c39b08..83f2d967624d 100644 --- a/src/net.h +++ b/src/net.h @@ -251,6 +251,19 @@ class CConnman void GetBanned(banmap_t &banmap); void SetBanned(const banmap_t &banmap); + // This allows temporarily exceeding nMaxOutbound, with the goal of finding + // a peer that is better than all our current peers. + void SetTryNewOutboundPeer(bool flag); + bool GetTryNewOutboundPeer(); + + // Return the number of outbound peers we have in excess of our target (eg, + // if we previously called SetTryNewOutboundPeer(true), and have since set + // to false, we may have extra peers that we wish to disconnect). This may + // return a value less than (num_outbound_connections - num_outbound_slots) + // in cases where some outbound connections are not yet fully connected, or + // not yet fully disconnected. + int GetExtraOutboundCount(); + bool AddNode(const std::string& node); bool RemoveAddedNode(const std::string& node); std::vector GetAddedNodeInfo(); @@ -416,6 +429,11 @@ class CConnman std::thread threadOpenAddedConnections; std::thread threadOpenConnections; std::thread threadMessageHandler; + + /** flag for deciding to connect to an extra outbound peer, + * in excess of nMaxOutbound + * This takes the place of a feeler connection */ + std::atomic_bool m_try_another_outbound_peer; }; extern std::unique_ptr g_connman; void Discover(boost::thread_group& threadGroup); From 459f2db425eaa3257819d496b37430558653289a Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 23 Oct 2017 13:59:07 -0400 Subject: [PATCH 139/196] Track tip update time and last new block announcement from each peer Github-Pull: #11560 Rebased-From: db32a6589720e5b15931cef82e477118dfd92669 --- src/net_processing.cpp | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0697c6bea57e..92c88477c92d 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -119,6 +119,10 @@ namespace { /** Number of outbound peers with m_chain_sync.m_protect. */ int g_outbound_peers_with_protect_from_disconnect = 0; + + /** When our tip was last updated. */ + int64_t g_last_tip_update = 0; + /** Relay map, protected by cs_main. */ typedef std::map MapRelay; MapRelay mapRelay; @@ -223,6 +227,9 @@ struct CNodeState { ChainSyncTimeoutState m_chain_sync; + //! Time of last new block announcement + int64_t m_last_block_announcement; + CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) { fCurrentlyConnected = false; nMisbehavior = 0; @@ -246,6 +253,7 @@ struct CNodeState { fWantsCmpctWitness = false; fSupportsDesiredCmpctVersion = false; m_chain_sync = { 0, nullptr, false, false }; + m_last_block_announcement = 0; } }; @@ -779,6 +787,8 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr& pb } LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased); } + + g_last_tip_update = GetTime(); } // All of the following cache a recent block, and are protected by cs_most_recent_block @@ -1203,6 +1213,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve return true; } + bool received_new_header = false; const CBlockIndex *pindexLast = nullptr; { LOCK(cs_main); @@ -1243,6 +1254,12 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve } hashLastBlock = header.GetHash(); } + + // If we don't have the last header, then they'll have given us + // something new (if these headers are valid). + if (mapBlockIndex.find(hashLastBlock) == mapBlockIndex.end()) { + received_new_header = true; + } } CValidationState state; @@ -1307,6 +1324,10 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve // because it is set in UpdateBlockAvailability. Some nullptr checks // are still present, however, as belt-and-suspenders. + if (received_new_header && pindexLast->nChainWork > chainActive.Tip()->nChainWork) { + nodestate->m_last_block_announcement = GetTime(); + } + if (nCount == MAX_HEADERS_RESULTS) { // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue @@ -2197,6 +2218,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr CBlockHeaderAndShortTxIDs cmpctblock; vRecv >> cmpctblock; + bool received_new_header = false; + { LOCK(cs_main); @@ -2206,6 +2229,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); return true; } + + if (mapBlockIndex.find(cmpctblock.header.GetHash()) == mapBlockIndex.end()) { + received_new_header = true; + } } const CBlockIndex *pindex = nullptr; @@ -2244,6 +2271,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr assert(pindex); UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash()); + CNodeState *nodestate = State(pfrom->GetId()); + + // If this was a new header with more work than our tip, update the + // peer's last block announcement time + if (received_new_header && pindex->nChainWork > chainActive.Tip()->nChainWork) { + nodestate->m_last_block_announcement = GetTime(); + } + std::map::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash()); bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end(); @@ -2266,8 +2301,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus())) return true; - CNodeState *nodestate = State(pfrom->GetId()); - if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) { // Don't bother trying to process compact blocks from v1 peers // after segwit activates. From a607a95d8185b2b8d5a4de6f1bd9054308ebf60a Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 24 Oct 2017 16:56:07 -0400 Subject: [PATCH 140/196] Connect to an extra outbound peer if our tip is stale If our tip hasn't updated in a while, that may be because our peers are not relaying blocks to us that we would consider valid. Allow connection to an additional outbound peer in that circumstance. Also, periodically check to see if we are exceeding our target number of outbound peers, and disconnect the one which has least recently announced a new block to us (choosing the newest such peer in the case of tie). Github-Pull: #11560 Rebased-From: ac7b37cd2bd612a64a4009ba82f1cd1d57f37434 --- src/init.cpp | 2 +- src/net.cpp | 1 + src/net_processing.cpp | 99 ++++++++++++++++++++++++++++++++++++++- src/net_processing.h | 16 ++++++- src/test/test_bitcoin.cpp | 2 +- 5 files changed, 114 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4282b0911dad..5196eee9535f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1287,7 +1287,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) g_connman = std::unique_ptr(new CConnman(GetRand(std::numeric_limits::max()), GetRand(std::numeric_limits::max()))); CConnman& connman = *g_connman; - peerLogic.reset(new PeerLogicValidation(&connman)); + peerLogic.reset(new PeerLogicValidation(&connman, scheduler)); RegisterValidationInterface(peerLogic.get()); // sanitize comments per BIP-0014, format user agent and check total size diff --git a/src/net.cpp b/src/net.cpp index 1687900ed762..b3bc8292fc6f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1678,6 +1678,7 @@ bool CConnman::GetTryNewOutboundPeer() void CConnman::SetTryNewOutboundPeer(bool flag) { m_try_another_outbound_peer = flag; + LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false"); } // Return the number of peers we have over our outbound connection limit diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 92c88477c92d..0eb01f36b2eb 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -23,6 +23,7 @@ #include "primitives/transaction.h" #include "random.h" #include "reverse_iterator.h" +#include "scheduler.h" #include "tinyformat.h" #include "txmempool.h" #include "ui_interface.h" @@ -119,7 +120,6 @@ namespace { /** Number of outbound peers with m_chain_sync.m_protect. */ int g_outbound_peers_with_protect_from_disconnect = 0; - /** When our tip was last updated. */ int64_t g_last_tip_update = 0; @@ -428,6 +428,15 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) { } } +bool TipMayBeStale(const Consensus::Params &consensusParams) +{ + AssertLockHeld(cs_main); + if (g_last_tip_update == 0) { + g_last_tip_update = GetTime(); + } + return g_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty(); +} + // Requires cs_main bool CanDirectFetch(const Consensus::Params &consensusParams) { @@ -754,9 +763,17 @@ void Misbehaving(NodeId pnode, int howmuch) // blockchain -> download logic notification // -PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) { +PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler) : connman(connmanIn), m_stale_tip_check_time(0) { // Initialize global variables that cannot be constructed at startup. recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); + + const Consensus::Params& consensusParams = Params().GetConsensus(); + // Stale tip checking and peer eviction are on two different timers, but we + // don't want them to get out of sync due to drift in the scheduler, so we + // combine them in one function and schedule at the quicker (peer-eviction) + // timer. + static_assert(EXTRA_PEER_CHECK_INTERVAL < STALE_CHECK_INTERVAL, "peer eviction timer should be less than stale tip check timer"); + scheduler.scheduleEvery(std::bind(&PeerLogicValidation::CheckForStaleTipAndEvictPeers, this, consensusParams), EXTRA_PEER_CHECK_INTERVAL * 1000); } void PeerLogicValidation::BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex, const std::vector& vtxConflicted) { @@ -1412,6 +1429,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve // If this is an outbound peer, check to see if we should protect // it from the bad/lagging chain logic. if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { + LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId()); nodestate->m_chain_sync.m_protect = true; ++g_outbound_peers_with_protect_from_disconnect; } @@ -2978,6 +2996,83 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) } } +void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) +{ + // Check whether we have too many outbound peers + int extra_peers = connman->GetExtraOutboundCount(); + if (extra_peers > 0) { + // If we have more outbound peers than we target, disconnect one. + // Pick the outbound peer that least recently announced + // us a new block, with ties broken by choosing the more recent + // connection (higher node id) + NodeId worst_peer = -1; + int64_t oldest_block_announcement = std::numeric_limits::max(); + + LOCK(cs_main); + + connman->ForEachNode([&](CNode* pnode) { + // Ignore non-outbound peers, or nodes marked for disconnect already + if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) return; + CNodeState *state = State(pnode->GetId()); + if (state == nullptr) return; // shouldn't be possible, but just in case + // Don't evict our protected peers + if (state->m_chain_sync.m_protect) return; + if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) { + worst_peer = pnode->GetId(); + oldest_block_announcement = state->m_last_block_announcement; + } + }); + if (worst_peer != -1) { + bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) { + // Only disconnect a peer that has been connected to us for + // some reasonable fraction of our check-frequency, to give + // it time for new information to have arrived. + // Also don't disconnect any peer we're trying to download a + // block from. + CNodeState &state = *State(pnode->GetId()); + if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && state.nBlocksInFlight == 0) { + LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement); + pnode->fDisconnect = true; + return true; + } else { + LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", pnode->GetId(), pnode->nTimeConnected, state.nBlocksInFlight); + return false; + } + }); + if (disconnected) { + // If we disconnected an extra peer, that means we successfully + // connected to at least one peer after the last time we + // detected a stale tip. Don't try any more extra peers until + // we next detect a stale tip, to limit the load we put on the + // network from these extra connections. + connman->SetTryNewOutboundPeer(false); + } + } + } +} + +void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams) +{ + if (connman == nullptr) return; + + int64_t time_in_seconds = GetTime(); + + EvictExtraOutboundPeers(time_in_seconds); + + if (time_in_seconds > m_stale_tip_check_time) { + LOCK(cs_main); + // Check whether our tip is stale, and if so, allow using an extra + // outbound peer + if (TipMayBeStale(consensusParams)) { + LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update); + connman->SetTryNewOutboundPeer(true); + } else if (connman->GetTryNewOutboundPeer()) { + connman->SetTryNewOutboundPeer(false); + } + m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL; + } +} + class CompareInvMempoolOrder { CTxMemPool *mp; diff --git a/src/net_processing.h b/src/net_processing.h index 656324bba0c4..0a49972eed14 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -8,6 +8,7 @@ #include "net.h" #include "validationinterface.h" +#include "consensus/params.h" /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; @@ -27,13 +28,19 @@ static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/head static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4; /** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */ static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes +/** How frequently to check for stale tips, in seconds */ +static constexpr int64_t STALE_CHECK_INTERVAL = 10 * 60; // 10 minutes +/** How frequently to check for extra outbound peers and disconnect, in seconds */ +static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45; +/** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict, in seconds */ +static constexpr int64_t MINIMUM_CONNECT_TIME = 30; class PeerLogicValidation : public CValidationInterface, public NetEventsInterface { private: - CConnman* connman; + CConnman* const connman; public: - explicit PeerLogicValidation(CConnman* connman); + explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler); void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected, const std::vector& vtxConflicted) override; void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; @@ -55,6 +62,11 @@ class PeerLogicValidation : public CValidationInterface, public NetEventsInterfa bool SendMessages(CNode* pto, std::atomic& interrupt) override; void ConsiderEviction(CNode *pto, int64_t time_in_seconds); + void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams); + void EvictExtraOutboundPeers(int64_t time_in_seconds); + +private: + int64_t m_stale_tip_check_time; //! Next time to check for stale tip }; struct CNodeStateStats { diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 045655983c66..10959adea0da 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -85,7 +85,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha threadGroup.create_thread(&ThreadScriptCheck); g_connman = std::unique_ptr(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. connman = g_connman.get(); - peerLogic.reset(new PeerLogicValidation(connman)); + peerLogic.reset(new PeerLogicValidation(connman, scheduler)); } TestingSetup::~TestingSetup() From 2ed0647ac1d6c14ff1be11f8d5284c0dc645fc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Tue, 24 Oct 2017 09:26:05 +0100 Subject: [PATCH 141/196] Add CConnmanTest to mutate g_connman in tests Github-Pull: #11560 Rebased-From: 83df25736ebaa23777e965d265ed677a8d79f23f --- src/net.h | 2 ++ src/test/test_bitcoin.cpp | 12 ++++++++++++ src/test/test_bitcoin.h | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/src/net.h b/src/net.h index 83f2d967624d..6b57d5cf79d0 100644 --- a/src/net.h +++ b/src/net.h @@ -434,6 +434,8 @@ class CConnman * in excess of nMaxOutbound * This takes the place of a feeler connection */ std::atomic_bool m_try_another_outbound_peer; + + friend struct CConnmanTest; }; extern std::unique_ptr g_connman; void Discover(boost::thread_group& threadGroup); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 10959adea0da..01e2a555e60e 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -24,6 +24,18 @@ #include +void CConnmanTest::AddNode(CNode& node) +{ + LOCK(g_connman->cs_vNodes); + g_connman->vNodes.push_back(&node); +} + +void CConnmanTest::ClearNodes() +{ + LOCK(g_connman->cs_vNodes); + g_connman->vNodes.clear(); +} + uint256 insecure_rand_seed = GetRandHash(); FastRandomContext insecure_rand_ctx(insecure_rand_seed); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 5a39f8ab821c..642be476a648 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -49,6 +49,12 @@ struct BasicTestingSetup { * Included are data directory, coins database, script check threads setup. */ class CConnman; +class CNode; +struct CConnmanTest { + static void AddNode(CNode& node); + static void ClearNodes(); +}; + class PeerLogicValidation; struct TestingSetup: public BasicTestingSetup { CCoinsViewDB *pcoinsdbview; From fc308a6cdb6c6d481b8721fa498e26c630210bf1 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 26 Oct 2017 10:32:46 -0400 Subject: [PATCH 142/196] Add unit test for stale tip checking Github-Pull: #11560 Rebased-From: 626291508c433488439b662f2e88882048fb59fb --- src/net_processing.cpp | 9 +++++ src/test/DoS_tests.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0eb01f36b2eb..dea4b042e610 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -543,6 +543,15 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorm_last_block_announcement = time_in_seconds; +} + // Returns true for outbound peers, excluding manual connections, feelers, and // one-shots bool IsOutboundDisconnectionCandidate(const CNode *node) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 7bcf304833f1..d1f9e63ecf55 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -40,6 +40,8 @@ CService ip(uint32_t i) static NodeId id = 0; +void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds); + BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) // Test eviction of an outbound peer whose chain never advances @@ -87,6 +89,89 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); } +void AddRandomOutboundPeer(std::vector &vNodes, PeerLogicValidation &peerLogic) +{ + CAddress addr(ip(GetRandInt(0xffffffff)), NODE_NONE); + vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false)); + CNode &node = *vNodes.back(); + node.SetSendVersion(PROTOCOL_VERSION); + + peerLogic.InitializeNode(&node); + node.nVersion = 1; + node.fSuccessfullyConnected = true; + + CConnmanTest::AddNode(node); +} + +BOOST_AUTO_TEST_CASE(stale_tip_peer_management) +{ + const Consensus::Params& consensusParams = Params().GetConsensus(); + constexpr int nMaxOutbound = 8; + CConnman::Options options; + options.nMaxConnections = 125; + options.nMaxOutbound = nMaxOutbound; + options.nMaxFeeler = 1; + + connman->Init(options); + std::vector vNodes; + + // Mock some outbound peers + for (int i=0; iCheckForStaleTipAndEvictPeers(consensusParams); + + // No nodes should be marked for disconnection while we have no extra peers + for (const CNode *node : vNodes) { + BOOST_CHECK(node->fDisconnect == false); + } + + SetMockTime(GetTime() + 3*consensusParams.nPowTargetSpacing + 1); + + // Now tip should definitely be stale, and we should look for an extra + // outbound peer + peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); + BOOST_CHECK(connman->GetTryNewOutboundPeer()); + + // Still no peers should be marked for disconnection + for (const CNode *node : vNodes) { + BOOST_CHECK(node->fDisconnect == false); + } + + // If we add one more peer, something should get marked for eviction + // on the next check (since we're mocking the time to be in the future, the + // required time connected check should be satisfied). + AddRandomOutboundPeer(vNodes, *peerLogic); + + peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); + for (int i=0; ifDisconnect == false); + } + // Last added node should get marked for eviction + BOOST_CHECK(vNodes.back()->fDisconnect == true); + + vNodes.back()->fDisconnect = false; + + // Update the last announced block time for the last + // peer, and check that the next newest node gets evicted. + UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime()); + + peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); + for (int i=0; ifDisconnect == false); + } + BOOST_CHECK(vNodes[nMaxOutbound-1]->fDisconnect == true); + BOOST_CHECK(vNodes.back()->fDisconnect == false); + + bool dummy; + for (const CNode *node : vNodes) { + peerLogic->FinalizeNode(node->GetId(), dummy); + } + + CConnmanTest::ClearNodes(); +} + BOOST_AUTO_TEST_CASE(DoS_banning) { std::atomic interruptDummy(false); From f224cbc3d8f4478d30e121126658c2ab22c6fb90 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 2 Nov 2017 20:20:13 +0100 Subject: [PATCH 143/196] build: Bump version to 0.15.1 Tree-SHA512: d998b31250208078414a27431d21b847592bdb1e4bd7eb1df6bee7f67671a4124dcaa2971ebef52304528080ab2d2ff6553b7d7138d948a364e64fc4e37dacd3 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index e8aa7d5ae121..4766e0431d3a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 15) -define(_CLIENT_VERSION_REVISION, 0) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_REVISION, 1) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2017) define(_COPYRIGHT_HOLDERS,[The %s developers]) From 34153a7e4a52be30582d96426e77a7a04e9721fb Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Nov 2017 12:02:57 -0400 Subject: [PATCH 144/196] rpc: work-around an upstream libevent bug A rare race condition may trigger while awaiting the body of a message, see upsteam commit 5ff8eb26371c4dc56f384b2de35bea2d87814779 for details. This may fix some reported rpc hangs/crashes. Github-Pull: #11593 Rebased-From: 6b58360f9b64eb0b680a662fdfd590e47f115f44 --- src/httpserver.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 86b37f79bb46..a3a90080ebe0 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -239,6 +240,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m) /** HTTP request callback */ static void http_request_cb(struct evhttp_request* req, void* arg) { + // Disable reading to work around a libevent bug, fixed in 2.2.0. + if (event_get_version_number() < 0x02020001) { + evhttp_connection* conn = evhttp_request_get_connection(req); + if (conn) { + bufferevent* bev = evhttp_connection_get_bufferevent(conn); + if (bev) { + bufferevent_disable(bev, EV_READ); + } + } + } std::unique_ptr hreq(new HTTPRequest(req)); LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n", @@ -599,11 +610,24 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) struct evbuffer* evb = evhttp_request_get_output_buffer(req); assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); - HTTPEvent* ev = new HTTPEvent(eventBase, true, - std::bind(evhttp_send_reply, req, nStatus, (const char*)nullptr, (struct evbuffer *)nullptr)); - ev->trigger(0); + auto req_copy = req; + HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ + evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); + // Re-enable reading from the socket. This is the second part of the libevent + // workaround above. + if (event_get_version_number() < 0x02020001) { + evhttp_connection* conn = evhttp_request_get_connection(req_copy); + if (conn) { + bufferevent* bev = evhttp_connection_get_bufferevent(conn); + if (bev) { + bufferevent_enable(bev, EV_READ | EV_WRITE); + } + } + } + }); + ev->trigger(nullptr); replySent = true; - req = 0; // transferred back to main thread + req = nullptr; // transferred back to main thread } CService HTTPRequest::GetPeer() From 8195cb0d7fc4f8699b35aff7a43ed2fb3013608c Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 2 Nov 2017 14:37:33 -0400 Subject: [PATCH 145/196] rpc: further constrain the libevent workaround The bug was introduced in 2.1.6-beta, versions before that don't need the workaround. Github-Pull: #11593 Rebased-From: 97932cd2689659addfbb58dc6148928b73af3bd0 --- src/httpserver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index a3a90080ebe0..dc7016b85ba9 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -241,7 +241,7 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m) static void http_request_cb(struct evhttp_request* req, void* arg) { // Disable reading to work around a libevent bug, fixed in 2.2.0. - if (event_get_version_number() < 0x02020001) { + if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { evhttp_connection* conn = evhttp_request_get_connection(req); if (conn) { bufferevent* bev = evhttp_connection_get_bufferevent(conn); @@ -615,7 +615,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); // Re-enable reading from the socket. This is the second part of the libevent // workaround above. - if (event_get_version_number() < 0x02020001) { + if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { evhttp_connection* conn = evhttp_request_get_connection(req_copy); if (conn) { bufferevent* bev = evhttp_connection_get_bufferevent(conn); From 2ce9e586d5b11e1f61af4db27b7326687d5e5124 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 5 Nov 2017 14:58:21 +0100 Subject: [PATCH 146/196] doc: Fill in 0.15.1 changelog and authors in release notes Tree-SHA512: 569816ca62319650d803b2dd4bc3a8791aaea1f573cd52a9e2cf220dc1ec08180a66fbb0ac44441f6b9f48cb9041ce08f56ff2e864b58510308b9a4b6898f8e8 --- doc/release-notes.md | 150 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 134 insertions(+), 16 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 6e4bd03cd5ae..edac364d8511 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,8 +1,9 @@ -(note: this is a temporary file, to be added-to by anybody, and moved to -release-notes at release time) - Bitcoin Core version *0.15.1* is now available from: + + +or + This is a new minor version release, including various bugfixes and @@ -60,18 +61,6 @@ frequently tested on them. Notable changes =============== - - -0.15.1 Change log -================= - -- `dumpwallet` no longer allows overwriting files. This is a security measure - as well as prevents dangerous user mistakes. - -- `listsinceblock` will now throw an error if an unknown `blockhash` argument - value is passed, instead of returning a list of all wallet transactions since - the genesis block. - Miner block size limiting deprecated ------------------------------------ @@ -88,11 +77,140 @@ Low-level RPC changes ---------------------- - The "currentblocksize" value in getmininginfo has been removed. +- `dumpwallet` no longer allows overwriting files. This is a security measure + as well as prevents dangerous user mistakes. + +- `listsinceblock` will now throw an error if an unknown `blockhash` argument + value is passed, instead of returning a list of all wallet transactions since + the genesis block. + +0.15.1 Change log +================= + +### Mining +- #11100 `7871a7d` Fix confusing blockmax{size,weight} options, dont default to throwing away money (TheBlueMatt) + +### RPC and other APIs +- #10859 `2a5d099` gettxout: Slightly improve doc and tests (jtimon) +- #11267 `b1a6c94` update cli for estimate\*fee argument rename (laanwj) +- #11483 `20cdc2b` Fix importmulti bug when importing an already imported key (pedrobranco) +- #9937 `a43be5b` Prevent `dumpwallet` from overwriting files (laanwj) +- #11465 `405e069` Update named args documentation for importprivkey (dusty-wil) +- #11131 `b278a43` Write authcookie atomically (laanwj) +- #11565 `7d4546f` Make listsinceblock refuse unknown block hash (ryanofsky) +- #11593 `8195cb0` Work-around an upstream libevent bug (theuni) + +### P2P protocol and network code +- #11397 `27e861a` Improve and document SOCKS code (laanwj) +- #11252 `0fe2a9a` When clearing addrman clear mapInfo and mapAddr (instagibbs) +- #11527 `a2bd86a` Remove my testnet DNS seed (schildbach) +- #10756 `0a5477c` net processing: swap out signals for an interface class (theuni) +- #11531 `55b7abf` Check that new headers are not a descendant of an invalid block (more effeciently) (TheBlueMatt) +- #11560 `49bf090` Connect to a new outbound peer if our tip is stale (sdaftuar) +- #11568 `fc966bb` Disconnect outbound peers on invalid chains (sdaftuar) +- #11578 `ec8dedf` Add missing lock in ProcessHeadersMessage(...) (practicalswift) +- #11456 `6f27965` Replace relevant services logic with a function suite (TheBlueMatt) +- #11490 `bf191a7` Disconnect from outbound peers with bad headers chains (sdaftuar) + +### Validation +- #10357 `da4908c` Allow setting nMinimumChainWork on command line (sdaftuar) +- #11458 `2df65ee` Don't process unrequested, low-work blocks (sdaftuar) + +### Build system +- #11440 `b6c0209` Fix validationinterface build on super old boost/clang (TheBlueMatt) +- #11530 `265bb21` Add share/rpcuser to dist. source code archive (MarcoFalke) + +### GUI +- #11334 `19d63e8` Remove custom fee radio group and remove nCustomFeeRadio setting (achow101) +- #11198 `7310f1f` Fix display of package name on 'open config file' tooltip (esotericnonsense) +- #11015 `6642558` Add delay before filtering transactions (lclc) +- #11338 `6a62c74` Backup former GUI settings on `-resetguisettings` (laanwj) +- #11335 `8d13b42` Replace save|restoreWindowGeometry with Qt functions (MeshCollider) +- #11237 `2e31b1d` Fixing division by zero in time remaining (MeshCollider) +- #11247 `47c02a8` Use IsMine to validate custom change address (MarcoFalke) + +### Wallet +- #11017 `9e8aae3` Close DB on error (kallewoof) +- #11225 `6b4d9f2` Update stored witness in AddToWallet (sdaftuar) +- #11126 `2cb720a` Acquire cs_main lock before cs_wallet during wallet initialization (ryanofsky) +- #11476 `9c8006d` Avoid opening copied wallet databases simultaneously (ryanofsky) +- #11492 `de7053f` Fix leak in CDB constructor (promag) +- #11376 `fd79ed6` Ensure backupwallet fails when attempting to backup to source file (tomasvdw) +- #11326 `d570aa4` Fix crash on shutdown with invalid wallet (MeshCollider) + +### Tests and QA +- #11399 `a825d4a` Fix bip68-sequence rpc test (jl2012) +- #11150 `847c75e` Add getmininginfo test (mess110) +- #11407 `806c78f` add functional test for mempoolreplacement command line arg (instagibbs) +- #11433 `e169349` Restore bitcoin-util-test py2 compatibility (MarcoFalke) +- #11308 `2e1ac70` zapwallettxes: Wait up to 3s for mempool reload (MarcoFalke) +- #10798 `716066d` test bitcoin-cli (jnewbery) +- #11443 `019c492` Allow "make cov" out-of-tree; Fix rpc mapping check (MarcoFalke) +- #11445 `51bad91` 0.15.1 Backports (MarcoFalke) +- #11319 `2f0b30a` Fix error introduced into p2p-segwit.py, and prevent future similar errors (sdaftuar) +- #10552 `e4605d9` Tests for zmqpubrawtx and zmqpubrawblock (achow101) +- #11067 `eeb24a3` TestNode: Add wait_until_stopped helper method (MarcoFalke) +- #11068 `5398f20` Move wait_until to util (MarcoFalke) +- #11125 `812c870` Add bitcoin-cli -stdin and -stdinrpcpass functional tests (promag) +- #11077 `1d80d1e` fix timeout issues from TestNode (jnewbery) +- #11078 `f1ced0d` Make p2p-leaktests.py more robust (jnewbery) +- #11210 `f3f7891` Stop test_bitcoin-qt touching ~/.bitcoin (MeshCollider) +- #11234 `f0b6795` Remove redundant testutil.cpp|h files (MeshCollider) +- #11215 `cef0319` fixups from set_test_params() (jnewbery) +- #11345 `f9cf7b5` Check connectivity before sending in assumevalid.py (jnewbery) +- #11091 `c276c1e` Increase initial RPC timeout to 60 seconds (laanwj) +- #10711 `fc2aa09` Introduce TestNode (jnewbery) +- #11230 `d8dd8e7` Fixup dbcrash interaction with add_nodes() (jnewbery) +- #11241 `4424176` Improve signmessages functional test (mess110) +- #11116 `2c4ff35` Unit tests for script/standard and IsMine functions (jimpo) +- #11422 `a36f332` Verify DBWrapper iterators are taking snapshots (TheBlueMatt) +- #11121 `bb5e7cb` TestNode tidyups (jnewbery) +- #11521 `ca0f3f7` travis: move back to the minimal image (theuni) +- #11538 `adbc9d1` Fix race condition failures in replace-by-fee.py, sendheaders.py (sdaftuar) +- #11472 `4108879` Make tmpdir option an absolute path, misc cleanup (MarcoFalke) +- #10853 `5b728c8` Fix RPC failure testing (again) (jnewbery) +- #11310 `b6468d3` Test listwallets RPC (mess110) + +### Miscellaneous +- #11377 `75997c3` Disallow uncompressed pubkeys in bitcoin-tx [multisig] output adds (TheBlueMatt) +- #11437 `dea3b87` [Docs] Update Windows build instructions for using WSL and Ubuntu 17.04 (fanquake) +- #11318 `8b61aee` Put back inadvertently removed copyright notices (gmaxwell) +- #11442 `cf18f42` [Docs] Update OpenBSD Build Instructions for OpenBSD 6.2 (fanquake) +- #10957 `50bd3f6` Avoid returning a BIP9Stats object with uninitialized values (practicalswift) +- #11539 `01223a0` [verify-commits] Allow revoked keys to expire (TheBlueMatt) + Credits ======= Thanks to everyone who directly contributed to this release: -(fill this in) +- Andreas Schildbach +- Andrew Chow +- Chris Moore +- Cory Fields +- Cristian Mircea Messel +- Daniel Edgecumbe +- Donal OConnor +- Dusty Williams +- fanquake +- Gregory Sanders +- Jim Posen +- John Newbery +- Johnson Lau +- João Barbosa +- Jorge Timón +- Karl-Johan Alm +- Lucas Betschart +- MarcoFalke +- Matt Corallo +- MeshCollider +- Paul Berg +- Pedro Branco +- Pieter Wuille +- practicalswift +- Russell Yanofsky +- Suhas Daftuar +- Tomas van der Wansem +- Wladimir J. van der Laan As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From 4fcb915944b27759dafb188566bfd14dbcd95cff Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Sun, 5 Nov 2017 17:19:58 +1300 Subject: [PATCH 147/196] Update release notes for 0.15.1 --- doc/release-notes.md | 67 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index edac364d8511..75d2e0971424 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -30,7 +30,7 @@ be converted to a new format, which will take anywhere from a few minutes to half an hour, depending on the speed of your machine. The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a -downgrade from version 0.15.0 or upgrade to version 0.15.0 will cause all fee +downgrade from version 0.15 or upgrade to version 0.15 will cause all fee estimates to be discarded. Note that the block database format also changed in version 0.8.0 and there is no @@ -58,9 +58,42 @@ the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not su Bitcoin Core should also work on most other Unix-like systems but is not frequently tested on them. + Notable changes =============== +Network fork safety enhancements +-------------------------------- + +A number of changes to the way Bitcoin Core deals with peer connections and invalid blocks +have been made, as a safety precaution against blockchain forks and misbehaving peers. + +- Unrequested blocks with less work than the minimum-chain-work are now no longer processed even +if they have more work than the tip (a potential issue during IBD where the tip may have low-work). +This prevents peers wasting the resources of a node. + +- Peers which provide a chain with less work than the minimum-chain-work during IBD will now be disconnected. + +- For a given outbound peer, we now check whether their best known block has at least as much work as our tip. If it +doesn't, and if we still haven't heard about a block with sufficient work after a 20 minute timeout, then we send +a single getheaders message, and wait 2 more minutes. If after two minutes their best known block has insufficient +work, we disconnect that peer. We protect 4 of our outbound peers from being disconnected by this logic to prevent +excessive network topology changes as a result of this algorithm, while still ensuring that we have a reasonable +number of nodes not known to be on bogus chains. + +- Outbound (non-manual) peers that serve us block headers that are already known to be invalid (other than compact +block announcements, because BIP 152 explicitly permits nodes to relay compact blocks before fully validating them) +will now be disconnected. + +- If the chain tip has not been advanced for over 30 minutes, we now assume the tip may be stale and will try to connect +to an additional outbound peer. A periodic check ensures that if this extra peer connection is in use, we will disconnect +the peer that least recently announced a new block. + +- The set of all known invalid-themselves blocks (i.e. blocks which we attempted to connect but which were found to be +invalid) are now tracked and used to check if new headers build on an invalid chain. This ensures that everything that +descends from an invalid block is marked as such. + + Miner block size limiting deprecated ------------------------------------ @@ -73,16 +106,43 @@ implied blockmaxweight, instead of limiting block size directly. Any miners who to limit their blocks by size, instead of by weight, will have to do so manually by removing transactions from their block template directly. + +GUI settings backed up on reset +------------------------------- + +The GUI settings will now be written to `guisettings.ini.bak` in the data directory before wiping them when +the `-resetguisettings` argument is used. This can be used to retroactively troubleshoot issues due to the +GUI settings. + + +Duplicate wallets disallowed +---------------------------- + +Previously, it was possible to open the same wallet twice by manually copying the wallet file, causing +issues when both were opened simultaneously. It is no longer possible to open copies of the same wallet. + + +Debug `-minimumchainwork` argument added +---------------------------------------- + +A hidden debug argument `-minimumchainwork` has been added to allow a custom minimum work value to be used +when validating a chain. + + Low-level RPC changes ---------------------- + - The "currentblocksize" value in getmininginfo has been removed. - `dumpwallet` no longer allows overwriting files. This is a security measure as well as prevents dangerous user mistakes. +- `backupwallet` will now fail when attempting to backup to source file, rather than + destroying the wallet. + - `listsinceblock` will now throw an error if an unknown `blockhash` argument value is passed, instead of returning a list of all wallet transactions since - the genesis block. + the genesis block. The behaviour is unchanged when an empty string is provided. 0.15.1 Change log ================= @@ -179,6 +239,7 @@ Low-level RPC changes - #10957 `50bd3f6` Avoid returning a BIP9Stats object with uninitialized values (practicalswift) - #11539 `01223a0` [verify-commits] Allow revoked keys to expire (TheBlueMatt) + Credits ======= @@ -203,12 +264,12 @@ Thanks to everyone who directly contributed to this release: - Lucas Betschart - MarcoFalke - Matt Corallo -- MeshCollider - Paul Berg - Pedro Branco - Pieter Wuille - practicalswift - Russell Yanofsky +- Samuel Dobson - Suhas Daftuar - Tomas van der Wansem - Wladimir J. van der Laan From 4905522b3b628e459bf4bca934a04dccca1b9453 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Thu, 27 Oct 2016 15:00:02 -0700 Subject: [PATCH 148/196] Litecoin: Update README.md --- README.md | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 5db9fc99282a..ad95a1d58626 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,42 @@ -Bitcoin Core integration/staging tree +Litecoin Core integration/staging tree ===================================== -[![Build Status](https://travis-ci.org/bitcoin/bitcoin.svg?branch=master)](https://travis-ci.org/bitcoin/bitcoin) +[![Build Status](https://travis-ci.org/litecoin-project/litecoin.svg?branch=master)](https://travis-ci.org/litecoin-project/litecoin) -https://bitcoincore.org +https://litecoin.org -What is Bitcoin? +What is Litecoin? ---------------- -Bitcoin is an experimental digital currency that enables instant payments to -anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate +Litecoin is an experimental digital currency that enables instant payments to +anyone, anywhere in the world. Litecoin uses peer-to-peer technology to operate with no central authority: managing transactions and issuing money are carried -out collectively by the network. Bitcoin Core is the name of open source +out collectively by the network. Litecoin Core is the name of open source software which enables the use of this currency. For more information, as well as an immediately useable, binary version of -the Bitcoin Core software, see https://bitcoin.org/en/download, or read the -[original whitepaper](https://bitcoincore.org/bitcoin.pdf). +the Litecoin Core software, see [https://litecoin.org](https://litecoin.org). License ------- -Bitcoin Core is released under the terms of the MIT license. See [COPYING](COPYING) for more +Litecoin Core is released under the terms of the MIT license. See [COPYING](COPYING) for more information or see https://opensource.org/licenses/MIT. Development Process ------------------- The `master` branch is regularly built and tested, but is not guaranteed to be -completely stable. [Tags](https://github.com/bitcoin/bitcoin/tags) are created -regularly to indicate new official, stable release versions of Bitcoin Core. +completely stable. [Tags](https://github.com/litecoin-project/litecoin/tags) are created +regularly to indicate new official, stable release versions of Litecoin Core. The contribution workflow is described in [CONTRIBUTING.md](CONTRIBUTING.md). -The developer [mailing list](https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev) +The developer [mailing list](https://groups.google.com/forum/#!forum/litecoin-dev) should be used to discuss complicated or controversial changes before working on a patch set. -Developer IRC can be found on Freenode at #bitcoin-core-dev. +Developer IRC can be found on Freenode at #litecoin-dev. Testing ------- @@ -70,13 +69,11 @@ not straightforward. Translations ------------ -Changes to translations as well as new translations can be submitted to -[Bitcoin Core's Transifex page](https://www.transifex.com/projects/p/bitcoin/). +We only accept translation fixes that are submitted through [Bitcoin Core's Transifex page](https://www.transifex.com/projects/p/bitcoin/). +Translations are converted to Litecoin periodically. Translations are periodically pulled from Transifex and merged into the git repository. See the [translation process](doc/translation_process.md) for details on how this works. **Important**: We do not accept translation changes as GitHub pull requests because the next pull from Transifex would automatically overwrite them again. - -Translators should also subscribe to the [mailing list](https://groups.google.com/forum/#!forum/bitcoin-translators). From fec11b7e9c1b0430b8513e9295258b50d06f823a Mon Sep 17 00:00:00 2001 From: shaolinfry Date: Sat, 18 Feb 2017 13:38:09 +0000 Subject: [PATCH 149/196] Litecoin: Move 0.13.2 release notes --- .../release-notes-0.13.2.md | 993 ++++++++++++++++++ doc/release-notes-litecoin.md | 48 + 2 files changed, 1041 insertions(+) create mode 100644 doc/litecoin-release-notes/release-notes-0.13.2.md create mode 100644 doc/release-notes-litecoin.md diff --git a/doc/litecoin-release-notes/release-notes-0.13.2.md b/doc/litecoin-release-notes/release-notes-0.13.2.md new file mode 100644 index 000000000000..619183a3a385 --- /dev/null +++ b/doc/litecoin-release-notes/release-notes-0.13.2.md @@ -0,0 +1,993 @@ +Litecoin Core version 0.13.2 is now available from: + + + +This is a new major version release, including new features, various bugfixes and performance improvements, as well as updated translations. +It is recommended to upgrade to this version. + +Please report bugs using the issue tracker at github: + + + +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 litecoin +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 +=============== + +Signature validation using libsecp256k1 +--------------------------------------- + +ECDSA signatures inside Litecoin transactions now use validation using +[libsecp256k1](https://github.com/bitcoin-core/secp256k1) instead of OpenSSL. + +Depending on the platform, this means a significant speedup for raw signature +validation speed. The advantage is largest on x86_64, where validation is over +five times faster. In practice, this translates to a raw reindexing and new +block validation times that are less than half of what it was before. + +Libsecp256k1 has undergone very extensive testing and validation. + +A side effect of this change is that libconsensus no longer depends on OpenSSL. + +Reduce upload traffic +--------------------- + +A major part of the outbound traffic is caused by serving historic blocks to +other nodes in initial block download state. + +It is now possible to reduce the total upload traffic via the `-maxuploadtarget` +parameter. This is *not* a hard limit but a threshold to minimize the outbound +traffic. When the limit is about to be reached, the uploaded data is cut by not +serving historic blocks (blocks older than one week). +Moreover, any SPV peer is disconnected when they request a filtered block. + +This option can be specified in MiB per day and is turned off by default +(`-maxuploadtarget=0`). +The recommended minimum is 144 * MAX_BLOCK_SIZE (currently 144MB) per day. + +Whitelisted peers will never be disconnected, although their traffic counts for +calculating the target. + +A more detailed documentation about keeping traffic low can be found in +[/doc/reduce-traffic.md](/doc/reduce-traffic.md). + +Direct headers announcement (BIP 130) +------------------------------------- + +Between compatible peers, [BIP 130] +(https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki) +direct headers announcement is used. This means that blocks are advertised by +announcing their headers directly, instead of just announcing the hash. In a +reorganization, all new headers are sent, instead of just the new tip. This +can often prevent an extra roundtrip before the actual block is downloaded. + +Memory pool limiting +-------------------- + +Previous versions of Litecoin Core had their mempool limited by checking +a transaction's fees against the node's minimum relay fee. There was no +upper bound on the size of the mempool and attackers could send a large +number of transactions paying just slighly more than the default minimum +relay fee to crash nodes with relatively low RAM. A temporary workaround +for previous versions of Litecoin Core was to raise the default minimum +relay fee. + +Litecoin Core 0.13.2 will have a strict maximum size on the mempool. The +default value is 300 MB and can be configured with the `-maxmempool` +parameter. Whenever a transaction would cause the mempool to exceed +its maximum size, the transaction that (along with in-mempool descendants) has +the lowest total feerate (as a package) will be evicted and the node's effective +minimum relay feerate will be increased to match this feerate plus the initial +minimum relay feerate. The initial minimum relay feerate is set to +1000 satoshis per kB. + +Litecoin Core 0.13.2 also introduces new default policy limits on the length and +size of unconfirmed transaction chains that are allowed in the mempool +(generally limiting the length of unconfirmed chains to 25 transactions, with a +total size of 101 KB). These limits can be overriden using command line +arguments; see the extended help (`--help -help-debug`) for more information. + +RPC: Random-cookie RPC authentication +------------------------------------- + +When no `-rpcpassword` is specified, the daemon now uses a special 'cookie' +file for authentication. This file is generated with random content when the +daemon starts, and deleted when it exits. Its contents are used as +authentication token. Read access to this file controls who can access through +RPC. By default it is stored in the data directory but its location can be +overridden with the option `-rpccookiefile`. + +This is similar to Tor's CookieAuthentication: see +https://www.torproject.org/docs/tor-manual.html.en + +This allows running litecoind without having to do any manual configuration. + +Relay: Any sequence of pushdatas in OP_RETURN outputs now allowed +----------------------------------------------------------------- + +Previously OP_RETURN outputs with a payload were only relayed and mined if they +had a single pushdata. This restriction has been lifted to allow any +combination of data pushes and numeric constant opcodes (OP_1 to OP_16) after +the OP_RETURN. The limit on OP_RETURN output size is now applied to the entire +serialized scriptPubKey, 83 bytes by default. (the previous 80 byte default plus +three bytes overhead) + +Relay: New and only new blocks relayed when pruning +--------------------------------------------------- + +When running in pruned mode, the client will now relay new blocks. When +responding to the `getblocks` message, only hashes of blocks that are on disk +and are likely to remain there for some reasonable time window (1 hour) will be +returned (previously all relevant hashes were returned). + +Relay and Mining: Priority transactions +--------------------------------------- + +Litecoin Core has a heuristic 'priority' based on coin value and age. This +calculation is used for relaying of transactions which do not pay the +minimum relay fee, and can be used as an alternative way of sorting +transactions for mined blocks. Litecoin Core will relay transactions with +insufficient fees depending on the setting of `-limitfreerelay=` (default: +`r=15` kB per minute) and `-blockprioritysize=`. + +In Bitcoin Core 0.12, when mempool limit has been reached a higher minimum +relay fee takes effect to limit memory usage. Transactions which do not meet +this higher effective minimum relay fee will not be relayed or mined even if +they rank highly according to the priority heuristic. + +The mining of transactions based on their priority is also now disabled by +default. To re-enable it, simply set `-blockprioritysize=` where is the size +in bytes of your blocks to reserve for these transactions. The old default was +50k, so to retain approximately the same policy, you would set +`-blockprioritysize=50000`. + +Additionally, as a result of computational simplifications, the priority value +used for transactions received with unconfirmed inputs is lower than in prior +versions due to avoiding recomputing the amounts as input transactions confirm. + +External miner policy set via the `prioritisetransaction` RPC to rank +transactions already in the mempool continues to work as it has previously. +Note, however, that if mining priority transactions is left disabled, the +priority delta will be ignored and only the fee metric will be effective. + +This internal automatic prioritization handling is being considered for removal +entirely in Litecoin Core 0.13, and it is at this time undecided whether the +more accurate priority calculation for chained unconfirmed transactions will be +restored. Community direction on this topic is particularly requested to help +set project priorities. + +Automatically use Tor hidden services +------------------------------------- + +Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket +API, to create and destroy 'ephemeral' hidden services programmatically. +Litecoin Core has been updated to make use of this. + +This means that if Tor is running (and proper authorization is available), +Litecoin Core automatically creates a hidden service to listen on, without +manual configuration. Litecoin Core will also use Tor automatically to connect +to other .onion nodes if the control socket can be successfully opened. This +will positively affect the number of available .onion nodes and their usage. + +This new feature is enabled by default if Litecoin Core is listening, and +a connection to Tor can be made. It can be configured with the `-listenonion`, +`-torcontrol` and `-torpassword` settings. To show verbose debugging +information, pass `-debug=tor`. + +Notifications through ZMQ +------------------------- + +Litecoind can now (optionally) asynchronously notify clients through a +ZMQ-based PUB socket of the arrival of new transactions and blocks. +This feature requires installation of the ZMQ C API library 4.x and +configuring its use through the command line or configuration file. +Please see [docs/zmq.md](/doc/zmq.md) for details of operation. + +Wallet: Transaction fees +------------------------ + +Various improvements have been made to how the wallet calculates +transaction fees. + +Users can decide to pay a predefined fee rate by setting `-paytxfee=` +(or `settxfee ` rpc during runtime). A value of `n=0` signals Litecoin +Core to use floating fees. By default, Litecoin Core will use floating +fees. + +Based on past transaction data, floating fees approximate the fees +required to get into the `m`th block from now. This is configurable +with `-txconfirmtarget=` (default: `2`). + +Sometimes, it is not possible to give good estimates, or an estimate +at all. Therefore, a fallback value can be set with `-fallbackfee=` +(default: `0.0002` LTC/kB). + +At all times, Litecoin Core will cap fees at `-maxtxfee=` (default: +0.10) LTC. +Furthermore, Litecoin Core will never create transactions paying less than +the current minimum relay fee. +Finally, a user can set the minimum fee rate for all transactions with +`-mintxfee=`, which defaults to 1000 satoshis per kB. + +Wallet: Negative confirmations and conflict detection +----------------------------------------------------- + +The wallet will now report a negative number for confirmations that indicates +how deep in the block chain the conflict is found. For example, if a transaction +A has 5 confirmations and spends the same input as a wallet transaction B, B +will be reported as having -5 confirmations. If another wallet transaction C +spends an output from B, it will also be reported as having -5 confirmations. +To detect conflicts with historical transactions in the chain a one-time +`-rescan` may be needed. + +Unlike earlier versions, unconfirmed but non-conflicting transactions will never +get a negative confirmation count. They are not treated as spendable unless +they're coming from ourself (change) and accepted into our local mempool, +however. The new "trusted" field in the `listtransactions` RPC output +indicates whether outputs of an unconfirmed transaction are considered +spendable. + +Wallet: Merkle branches removed +------------------------------- + +Previously, every wallet transaction stored a Merkle branch to prove its +presence in blocks. This wasn't being used for more than an expensive +sanity check. Since 0.13.2, these are no longer stored. When loading a +0.13.2 wallet into an older version, it will automatically rescan to avoid +failed checks. + +Wallet: Pruning +--------------- + +With 0.13.2 it is possible to use wallet functionality in pruned mode. +This can reduce the disk usage from currently around 6 GB to +around 0.2 GB. + +However, rescans as well as the RPCs `importwallet`, `importaddress`, +`importprivkey` are disabled. + +To enable block pruning set `prune=` on the command line or in +`litecoin.conf`, where `N` is the number of MiB to allot for +raw block & undo data. + +A value of 0 disables pruning. The minimal value above 0 is 550. Your +wallet is as secure with high values as it is with low ones. Higher +values merely ensure that your node will not shut down upon blockchain +reorganizations of more than 2 days - which are unlikely to happen in +practice. In future releases, a higher value may also help the network +as a whole: stored blocks could be served to other nodes. + +For further information about pruning, you may also consult the [release +notes of Bitcoin Core v0.11.0](https://github.com/bitcoin/bitcoin/blob/v0.11.0/doc/release-notes.md#block-file-pruning). + +`NODE_BLOOM` service bit +------------------------ + +Support for the `NODE_BLOOM` service bit, as described in [BIP +111](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki), has been +added to the P2P protocol code. + +BIP 111 defines a service bit to allow peers to advertise that they support +bloom filters (such as used by SPV clients) explicitly. It also bumps the protocol +version to allow peers to identify old nodes which allow bloom filtering of the +connection despite lacking the new service bit. + +In this version, it is only enforced for peers that send protocol versions +`>=70011`. For the next major version it is planned that this restriction will be +removed. It is recommended to update SPV clients to check for the `NODE_BLOOM` +service bit for nodes that report versions newer than 70011. + +Option parsing behavior +----------------------- + +Command line options are now parsed strictly in the order in which they are +specified. It used to be the case that `-X -noX` ends up, unintuitively, with X +set, as `-X` had precedence over `-noX`. This is no longer the case. Like for +other software, the last specified value for an option will hold. + +RPC: Low-level API changes +-------------------------- + +- Monetary amounts can be provided as strings. This means that for example the + argument to sendtoaddress can be "0.0001" instead of 0.0001. This can be an + advantage if a JSON library insists on using a lossy floating point type for + numbers, which would be dangerous for monetary amounts. + +* The `asm` property of each scriptSig now contains the decoded signature hash + type for each signature that provides a valid defined hash type. + +* OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP 65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) + +The following items contain assembly representations of scriptSig signatures +and are affected by this change: + +- RPC `getrawtransaction` +- RPC `decoderawtransaction` +- RPC `decodescript` +- REST `/rest/tx/` (JSON format) +- REST `/rest/block/` (JSON format when including extended tx details) +- `litecoin-tx -json` + +For example, the `scriptSig.asm` property of a transaction input that +previously showed an assembly representation of: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 400000 OP_NOP2 + +now shows as: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] 400000 OP_CHECKLOCKTIMEVERIFY + +Note that the output of the RPC `decodescript` did not change because it is +configured specifically to process scriptPubKey and not scriptSig scripts. + +RPC: SSL support dropped +------------------------ + +SSL support for RPC, previously enabled by the option `rpcssl` has been dropped +from both the client and the server. This was done in preparation for removing +the dependency on OpenSSL for the daemon completely. + +Trying to use `rpcssl` will result in an error: + + Error: SSL mode for RPC (-rpcssl) is no longer supported. + +If you are one of the few people that relies on this feature, a flexible +migration path is to use `stunnel`. This is an utility that can tunnel +arbitrary TCP connections inside SSL. On e.g. Ubuntu it can be installed with: + + sudo apt-get install stunnel4 + +Then, to tunnel a SSL connection on 29332 to a RPC server bound on localhost on port 19334 do: + + stunnel -d 29332 -r 127.0.0.1:19334 -p stunnel.pem -P '' + +It can also be set up system-wide in inetd style. + +Another way to re-attain SSL would be to setup a httpd reverse proxy. This solution +would allow the use of different authentication, loadbalancing, on-the-fly compression and +caching. A sample config for apache2 could look like: + + Listen 443 + + NameVirtualHost *:443 + + + SSLEngine On + SSLCertificateFile /etc/apache2/ssl/server.crt + SSLCertificateKeyFile /etc/apache2/ssl/server.key + + + ProxyPass http://127.0.0.1:9332/ + ProxyPassReverse http://127.0.0.1:9332/ + # optional enable digest auth + # AuthType Digest + # ... + + # optional bypass litecoind rpc basic auth + # RequestHeader set Authorization "Basic " + # get the from the shell with: base64 <<< litecoinrpc: + + + # Or, balance the load: + # ProxyPass / balancer://balancer_cluster_name + + + +Other P2P Changes +----------------- + +The list of banned peers is now stored on disk rather than in memory. +Restarting litecoind will no longer clear out the list of banned peers; instead +a new RPC call (`clearbanned`) can be used to manually clear the list. The new +`setban` RPC call can also be used to manually ban or unban a peer. + +Database cache memory increased +-------------------------------- + +As a result of growth of the UTXO set, performance with the prior default +database cache of 100 MiB has suffered. +For this reason the default was changed to 300 MiB in this release. + +For nodes on low-memory systems, the database cache can be changed back to +100 MiB (or to another value) by either: + +- Adding `dbcache=100` in litecoin.conf +- Changing it in the GUI under `Options → Size of database cache` + +Note that the database cache setting has the most performance impact +during initial sync of a node, and when catching up after downtime. + + +litecoin-cli: arguments privacy +------------------------------ + +The RPC command line client gained a new argument, `-stdin` +to read extra arguments from standard input, one per line until EOF/Ctrl-D. +For example: + + $ src/litecoin-cli -stdin walletpassphrase + mysecretcode + 120 + ..... press Ctrl-D here to end input + $ + +It is recommended to use this for sensitive information such as wallet +passphrases, as command-line arguments can usually be read from the process +table by any user on the system. + + +C++11 and Python 3 +------------------ + +Various code modernizations have been done. The Litecoin Core code base has +started using C++11. This means that a C++11-capable compiler is now needed for +building. Effectively this means GCC 4.7 or higher, or Clang 3.3 or higher. + +When cross-compiling for a target that doesn't have C++11 libraries, configure with +`./configure --enable-glibc-back-compat ... LDFLAGS=-static-libstdc++`. + +For running the functional tests in `qa/rpc-tests`, Python3.4 or higher is now +required. + + +Linux ARM builds +---------------- + +Due to popular request, Linux ARM builds have been added to the uploaded +executables. + +The following extra files can be found in the download directory or torrent: + +- `litecoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries for the most + common 32-bit ARM architecture. +- `litecoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries for the most + common 64-bit ARM 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 Android is not considered ARM Linux in this context. The executables +are not expected to work out of the box on Android. + +BIP68 soft fork to enforce sequence locks for relative locktime +--------------------------------------------------------------- + +[BIP68][] introduces relative lock-time consensus-enforced semantics of +the sequence number field to enable a signed transaction input to remain +invalid for a defined period of time after confirmation of its corresponding +outpoint. + +For more information about the implementation, see + + +BIP112 soft fork to enforce OP_CHECKSEQUENCEVERIFY +-------------------------------------------------- + +[BIP112][] redefines the existing OP_NOP3 as OP_CHECKSEQUENCEVERIFY (CSV) +for a new opcode in the Litecoin scripting system that in combination with +[BIP68][] allows execution pathways of a script to be restricted based +on the age of the output being spent. + +For more information about the implementation, see + + +BIP113 locktime enforcement soft fork +------------------------------------- + +This release seeks to make mempool-only locktime enforcement using GetMedianTimePast() +a consensus rule. + +Litecoin transactions currently may specify a locktime indicating when +they may be added to a valid block. Current consensus rules require +that blocks have a block header time greater than the locktime specified +in any transaction in that block. + +Miners get to choose what time they use for their header time, with the +consensus rule being that no node will accept a block whose time is more +than two hours in the future. This creates a incentive for miners to +set their header times to future values in order to include locktimed +transactions which weren't supposed to be included for up to two more +hours. + +The consensus rules also specify that valid blocks may have a header +time greater than that of the median of the 11 previous blocks. This +GetMedianTimePast() time has a key feature we generally associate with +time: it can't go backwards. + +[BIP113][] specifies a soft fork enforced in this release that +weakens this perverse incentive for individual miners to use a future +time by requiring that valid blocks have a computed GetMedianTimePast() +greater than the locktime specified in any transaction in that block. + +Mempool inclusion rules currently require transactions to be valid for +immediate inclusion in a block in order to be accepted into the mempool. +This release begins applying the BIP113 rule to received transactions, +so transaction whose time is greater than the GetMedianTimePast() will +no longer be accepted into the mempool. + +**Implication for miners:** you will begin rejecting transactions that +would not be valid under BIP113, which will prevent you from producing +invalid blocks when BIP113 is enforced on the network. Any +transactions which are valid under the current rules but not yet valid +under the BIP113 rules will either be mined by other miners or delayed +until they are valid under BIP113. Note, however, that time-based +locktime transactions are more or less unseen on the network currently. + +**Implication for users:** GetMedianTimePast() always trails behind the +current time, so a transaction locktime set to the present time will be +rejected by nodes running this release until the median time moves +forward. To compensate, subtract one hour (3,600 seconds) from your +locktimes to allow those transactions to be included in mempools at +approximately the expected time. + +For more information about the implementation, see + + + +Compact Block support (BIP 152) +------------------------------- + +Support for block relay using the Compact Blocks protocol has been implemented +in PR 8068. + +The primary goal is reducing the bandwidth spikes at relay time, though in many +cases it also reduces propagation delay. It is automatically enabled between +compatible peers. +[BIP 152](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki) + +As a side-effect, ordinary non-mining nodes will download and upload blocks +faster if those blocks were produced by miners using similar transaction +filtering policies. This means that a miner who produces a block with many +transactions discouraged by your node will be relayed slower than one with +only transactions already in your memory pool. The overall effect of such +relay differences on the network may result in blocks which include widely- +discouraged transactions losing a stale block race, and therefore miners may +wish to configure their node to take common relay policies into consideration. + + +Hierarchical Deterministic Key Generation +----------------------------------------- +Newly created wallets will use hierarchical deterministic key generation +according to BIP32 (keypath m/0'/0'/k'). +Existing wallets will still use traditional key generation. + +Backups of HD wallets, regardless of when they have been created, can +therefore be used to re-generate all possible private keys, even the +ones which haven't already been generated during the time of the backup. +**Attention:** Encrypting the wallet will create a new seed which requires +a new backup! + +Wallet dumps (created using the `dumpwallet` RPC) will contain the deterministic +seed. This is expected to allow future versions to import the seed and all +associated funds, but this is not yet implemented. + +HD key generation for new wallets can be disabled by `-usehd=0`. Keep in +mind that this flag only has affect on newly created wallets. +You can't disable HD key generation once you have created a HD wallet. + +There is no distinction between internal (change) and external keys. + +HD wallets are incompatible with older versions of Litecoin Core. + +[Pull request](https://github.com/bitcoin/bitcoin/pull/8035/files), [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) + + +Mining transaction selection ("Child Pays For Parent") +------------------------------------------------------ + +The mining transaction selection algorithm has been replaced with an algorithm +that selects transactions based on their feerate inclusive of unconfirmed +ancestor transactions. This means that a low-fee transaction can become more +likely to be selected if a high-fee transaction that spends its outputs is +relayed. + +With this change, the `-blockminsize` command line option has been removed. + +The command line option `-blockmaxsize` remains an option to specify the +maximum number of serialized bytes in a generated block. In addition, the new +command line option `-blockmaxweight` has been added, which specifies the +maximum "block weight" of a generated block, as defined by [BIP 141 (Segregated +Witness)] (https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki). + +In preparation for Segregated Witness, the mining algorithm has been modified +to optimize transaction selection for a given block weight, rather than a given +number of serialized bytes in a block. In this release, transaction selection +is unaffected by this distinction (as BIP 141 activation is not supported on +mainnet in this release, see above), but in future releases and after BIP 141 +activation, these calculations would be expected to differ. + +For optimal runtime performance, miners using this release should specify +`-blockmaxweight` on the command line, and not specify `-blockmaxsize`. +Additionally (or only) specifying `-blockmaxsize`, or relying on default +settings for both, may result in performance degradation, as the logic to +support `-blockmaxsize` performs additional computation to ensure that +constraint is met. (Note that for mainnet, in this release, the equivalent +parameter for `-blockmaxweight` would be four times the desired +`-blockmaxsize`. See [BIP 141] +(https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) for additional +details.) + +In the future, the `-blockmaxsize` option may be removed, as block creation is +no longer optimized for this metric. Feedback is requested on whether to +deprecate or keep this command line option in future releases. + + +Reindexing changes +------------------ + +In earlier versions, reindexing did validation while reading through the block +files on disk. These two have now been split up, so that all blocks are known +before validation starts. This was necessary to make certain optimizations that +are available during normal synchronizations also available during reindexing. + +The two phases are distinct in the Litecoin-Qt GUI. During the first one, +"Reindexing blocks on disk" is shown. During the second (slower) one, +"Processing blocks on disk" is shown. + +It is possible to only redo validation now, without rebuilding the block index, +using the command line option `-reindex-chainstate` (in addition to +`-reindex` which does both). This new option is useful when the blocks on disk +are assumed to be fine, but the chainstate is still corrupted. It is also +useful for benchmarks. + + +Removal of internal miner +-------------------------- + +As CPU mining has been useless for a long time, the internal miner has been +removed in this release, and replaced with a simpler implementation for the +test framework. + +The overall result of this is that `setgenerate` RPC call has been removed, as +well as the `-gen` and `-genproclimit` command-line options. + +For testing, the `generate` call can still be used to mine a block, and a new +RPC call `generatetoaddress` has been added to mine to a specific address. This +works with wallet disabled. + + +New bytespersigop implementation +-------------------------------- + +The former implementation of the bytespersigop filter accidentally broke bare +multisig (which is meant to be controlled by the `permitbaremultisig` option), +since the consensus protocol always counts these older transaction forms as 20 +sigops for backwards compatibility. Simply fixing this bug by counting more +accurately would have reintroduced a vulnerability. It has therefore been +replaced with a new implementation that rather than filter such transactions, +instead treats them (for fee purposes only) as if they were in fact the size +of a transaction actually using all 20 sigops. + + +Low-level P2P changes +---------------------- + +- The optional new p2p message "feefilter" is implemented and the protocol + version is bumped to 70013. Upon receiving a feefilter message from a peer, + a node will not send invs for any transactions which do not meet the filter + feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki) + +- The P2P alert system has been removed in PR #7692 and the `alert` P2P message + is no longer supported. + +- The transaction relay mechanism used to relay one quarter of all transactions + instantly, while queueing up the rest and sending them out in batch. As + this resulted in chains of dependent transactions being reordered, it + systematically hurt transaction relay. The relay code was redesigned in PRs + \#7840 and #8082, and now always batches transactions announcements while also + sorting them according to dependency order. This significantly reduces orphan + transactions. To compensate for the removal of instant relay, the frequency of + batch sending was doubled for outgoing peers. + +- Since PR #7840 the BIP35 `mempool` command is also subject to batch processing. + Also the `mempool` message is no longer handled for non-whitelisted peers when + `NODE_BLOOM` is disabled through `-peerbloomfilters=0`. + +- The maximum size of orphan transactions that are kept in memory until their + ancestors arrive has been raised in PR #8179 from 5000 to 99999 bytes. They + are now also removed from memory when they are included in a block, conflict + with a block, and time out after 20 minutes. + +- We respond at most once to a getaddr request during the lifetime of a + connection since PR #7856. + +- Connections to peers who have recently been the first one to give us a valid + new block or transaction are protected from disconnections since PR #8084. + + +Low-level RPC changes +---------------------- + +- RPC calls have been added to output detailed statistics for individual mempool + entries, as well as to calculate the in-mempool ancestors or descendants of a + transaction: see `getmempoolentry`, `getmempoolancestors`, `getmempooldescendants`. + +- `gettxoutsetinfo` UTXO hash (`hash_serialized`) has changed. There was a divergence between + 32-bit and 64-bit platforms, and the txids were missing in the hashed data. This has been + fixed, but this means that the output will be different than from previous versions. + +- Full UTF-8 support in the RPC API. Non-ASCII characters in, for example, + wallet labels have always been malformed because they weren't taken into account + properly in JSON RPC processing. This is no longer the case. This also affects + the GUI debug console. + +- Asm script outputs replacements for OP_NOP2 and OP_NOP3 + + - OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP +65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) + + - OP_NOP3 has been renamed to OP_CHECKSEQUENCEVERIFY by [BIP +112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) + + - The following outputs are affected by this change: + + - RPC `getrawtransaction` (in verbose mode) + - RPC `decoderawtransaction` + - RPC `decodescript` + - REST `/rest/tx/` (JSON format) + - REST `/rest/block/` (JSON format when including extended tx details) + - `litecoin-tx -json` + +- The sorting of the output of the `getrawmempool` output has changed. + +- New RPC commands: `generatetoaddress`, `importprunedfunds`, `removeprunedfunds`, `signmessagewithprivkey`, + `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry`, + `createwitnessaddress`, `addwitnessaddress`. + +- Removed RPC commands: `setgenerate`, `getgenerate`. + +- New options were added to `fundrawtransaction`: `includeWatching`, `changeAddress`, `changePosition` and `feeRate`. + + +Low-level ZMQ changes +---------------------- + +- Each ZMQ notification now contains an up-counting sequence number that allows + listeners to detect lost notifications. + The sequence number is always the last element in a multi-part ZMQ notification and + therefore backward compatible. Each message type has its own counter. + PR [#7762](https://github.com/bitcoin/bitcoin/pull/7762). + +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 Litecoin wallet + software more difficult and which seriously complicates the design of smart + contracts for Litecoin. + +- **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 Litecoin 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 litecoins they think they are spending, and by having full nodes refuse to + accept those signatures unless the amount of litecoins 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:** Litecoin addresses (both P2PKH addresses + that start with a '1' and P2SH addresses that start with a '3' or 'M') 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 Litecoin'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 Litecoin'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 Litecoin Core does not provide an option to use this capability as + of this 0.13.2 release. + +- **Script versioning:** Segwit makes it easy for future soft forks to allow + Litecoin users to individually opt-in to almost any change in the Litecoin + Script language when those users receive new transactions. Features + currently being researched by Bitcoin and Litecoin 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. At the beginning of the first retarget period after +segwit's start date of 1 January 2017 miners can update the Litecoin +client to Litecoin Core 0.13.2 to signal for segwit support. When a +super-majority of 75% is reached segwit is activated by optional, and +if 75% of blocks within a 8,064-block retarget period (about 3.5 days) +signal support for segwit, after another 8,064 blocks, segwit will +be required. + +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]. + +[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 + + +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 Litecoin 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 +---------------- + +Pre-built Linux ARM binaries have been 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: + +- `litecoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries targeting + the 32-bit ARMv7-A architecture. +- `litecoin-${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. + + +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). + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- [The Bitcoin Core Developers](/doc/release-notes) +- Charles Lee +- Adrian Gallagher +- shaolinfry +- Xinxi Wang +- Xinrong Guo +- Fan Yang +- Peng Sun +- Loshan T diff --git a/doc/release-notes-litecoin.md b/doc/release-notes-litecoin.md new file mode 100644 index 000000000000..5d7b21c78427 --- /dev/null +++ b/doc/release-notes-litecoin.md @@ -0,0 +1,48 @@ +Litecoin Core version 0.14.0 is now available from: + + + +This is a new major version release, including new features, various bugfixes and performance improvements, as well as updated translations. +It is recommended to upgrade to this version. + +Please report bugs using the issue tracker at github: + + + +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 litecoin +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 +=============== + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- [The Bitcoin Core Developers](/doc/release-notes) +- Adrian Gallagher +- shaolinfry From 5c06f19e31a0fbffc3d63fd9ce0b4e1442ab2f83 Mon Sep 17 00:00:00 2001 From: shaolinfry Date: Sat, 18 Feb 2017 12:21:43 +0000 Subject: [PATCH 150/196] Litecoin: Adjust chain parameters --- contrib/seeds/makeseeds.py | 2 +- contrib/seeds/nodes_main.txt | 1511 ++------------------------------- contrib/seeds/nodes_test.txt | 12 +- src/chainparams.cpp | 190 ++--- src/chainparams.h | 1 + src/chainparamsbase.cpp | 8 +- src/chainparamsseeds.h | 1523 ++-------------------------------- 7 files changed, 232 insertions(+), 3015 deletions(-) diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 877a7836ef74..e0c67ec21113 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -30,7 +30,7 @@ PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$") -PATTERN_AGENT = re.compile(r"^(/Satoshi:0.13.(1|2|99)/|/Satoshi:0.14.(0|1|2|99)/)$") +PATTERN_AGENT = re.compile(r"^(/Satoshi:0.13.(0|1|2|99)/|/LitecoinCore:0.13.(0|1|2|99)/|/LitecoinCore:0.14.(0|1|2|99)/)$") def parseline(line): sline = line.split() diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index 60b34216cd63..d9e1b0fcd5d0 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -1,1450 +1,61 @@ -2.228.70.198:8333 -4.15.180.29:8333 -4.15.180.30:8333 -5.2.67.110:8333 -5.39.224.103:8333 -5.43.124.154:8333 -5.189.165.102:8333 -5.226.149.145:8333 -5.228.7.146:8333 -5.228.64.71:8333 -5.249.152.101:8333 -5.254.124.55:8333 -5.255.64.231:8333 -5.255.90.234:8333 -14.192.8.27:21301 -18.62.3.86:8333 -18.85.35.80:8333 -23.28.128.65:8333 -23.108.83.12:8333 -23.233.2.238:8333 -24.27.65.168:8333 -24.56.241.219:8333 -24.64.75.132:8333 -24.73.70.26:8333 -24.121.154.140:8333 -24.203.96.72:8333 -24.225.34.62:8333 -24.227.69.146:8333 -24.232.136.119:8333 -31.16.123.235:8333 -31.19.205.53:8333 -31.132.136.35:8333 -31.184.234.85:8333 -31.211.102.161:8333 -37.48.64.140:8333 -37.97.141.116:8333 -37.120.160.12:8333 -37.120.164.16:8333 -37.134.226.181:8333 -37.147.110.43:8333 -37.194.10.30:8333 -37.247.22.53:8333 -38.27.65.158:8333 -38.133.141.34:8333 -43.248.160.151:8333 -45.32.130.19:8333 -45.32.193.157:8333 -45.46.161.121:8333 -45.56.97.63:8333 -45.116.178.79:8188 -46.16.240.98:8333 -46.20.246.100:8333 -46.21.97.135:8333 -46.59.10.237:8333 -46.59.13.59:8333 -46.148.16.210:8333 -46.166.160.96:8333 -46.188.44.20:8333 -46.229.238.187:8333 -46.231.16.149:8333 -47.88.35.181:8333 -47.88.100.130:8333 -47.184.129.94:8333 -47.199.68.204:8333 -50.30.38.203:8333 -50.63.162.242:8333 -50.97.133.208:8333 -50.114.227.224:8333 -51.15.0.17:8333 -51.174.69.239:8333 -52.7.135.69:8333 -52.14.64.82:8333 -52.204.105.25:8333 -54.255.160.87:8333 -61.47.2.20:8333 -61.125.131.55:8333 -62.43.130.178:8333 -62.106.16.111:8333 -62.107.200.30:8333 -62.109.20.99:8333 -62.133.194.2:8333 -62.133.194.156:8333 -62.176.6.94:8333 -62.182.169.222:8333 -62.205.132.245:8333 -62.216.238.133:8333 -63.231.239.212:8333 -64.34.231.140:8333 -64.203.102.86:8333 -64.233.245.39:8333 -65.183.76.73:8333 -66.96.199.166:8333 -66.194.38.250:8333 -66.194.38.253:8333 -66.196.12.63:8333 -67.215.6.34:8333 -67.221.193.55:8333 -68.66.193.192:8333 -68.69.235.230:8333 -68.111.10.219:8333 -68.119.138.175:8333 -68.132.193.222:8333 -68.194.42.76:8333 -68.235.41.204:8333 -69.11.97.43:8333 -69.41.3.212:8333 -69.41.171.35:8333 -69.41.171.36:8333 -69.55.64.216:8333 -69.84.42.56:8333 -70.48.48.250:8333 -70.112.32.29:8333 -70.250.74.20:8333 -71.93.161.162:8333 -71.198.0.126:8333 -72.5.167.41:8333 -72.224.11.103:8333 -73.72.160.213:8333 -74.122.237.124:8333 -75.86.137.34:8333 -75.165.99.144:8333 -76.64.74.193:8333 -76.76.227.136:8333 -76.173.161.44:8333 -76.178.22.44:8333 -77.47.137.27:8333 -77.77.46.250:8333 -77.91.193.152:8333 -77.95.226.194:8333 -77.120.246.254:8333 -77.163.136.136:8333 -77.203.13.57:8333 -77.236.37.214:8333 -77.239.37.12:8333 -77.247.179.44:8333 -78.34.14.52:8333 -78.109.163.153:8333 -78.196.172.45:8333 -79.132.230.144:8333 -79.160.2.105:8333 -80.82.77.138:8333 -80.100.203.151:8333 -80.147.68.237:8333 -80.237.240.102:8333 -81.2.246.127:8333 -81.7.7.86:8333 -81.7.10.238:8333 -81.27.96.37:8333 -81.83.96.5:8333 -81.228.194.187:8333 -82.45.69.216:8333 -82.69.44.183:8333 -82.72.198.68:8333 -82.95.204.10:8333 -82.118.236.127:8333 -82.118.242.4:8333 -82.134.66.146:8333 -82.193.109.199:8333 -82.197.210.65:8333 -82.199.102.10:8333 -82.200.205.30:8333 -82.221.108.27:8333 -82.221.128.81:8333 -82.221.139.97:8333 -82.232.202.246:8333 -83.60.64.252:8333 -83.61.8.228:8333 -83.128.41.48:8333 -83.128.111.69:8333 -83.137.41.10:8333 -83.150.43.17:8333 -83.169.2.43:8333 -83.174.209.87:8333 -83.255.43.163:8333 -84.42.193.6:8333 -84.52.145.231:8333 -84.52.234.70:8333 -84.85.102.113:8333 -84.92.92.247:8333 -84.146.35.123:8333 -84.212.198.222:8333 -84.217.163.135:8333 -84.245.27.185:8333 -84.251.203.5:8333 -85.21.144.226:8333 -85.25.194.12:8333 -85.25.194.28:8333 -85.144.119.222:8333 -85.183.140.62:8333 -85.214.228.203:8333 -85.214.234.254:8333 -85.218.150.1:8333 -85.228.196.10:8333 -86.15.2.235:8333 -86.61.6.210:8333 -87.92.115.194:8333 -87.120.8.5:8333 -87.120.37.230:8333 -87.233.181.146:8333 -87.239.101.102:8333 -88.87.78.126:8333 -88.98.198.130:8333 -88.98.225.214:8333 -88.99.58.194:8333 -88.150.192.17:8333 -88.196.136.31:17556 -88.208.58.193:8333 -88.208.58.194:8333 -89.22.96.132:8333 -89.22.104.48:8333 -89.25.80.98:8333 -89.34.99.41:8333 -89.142.195.112:8333 -89.163.224.187:8333 -89.163.224.195:8333 -89.238.79.235:8333 -90.46.240.214:8333 -90.65.232.129:8333 -90.71.117.90:8333 -90.149.38.172:8333 -90.156.97.145:8333 -90.177.48.104:8333 -91.106.194.97:8333 -91.135.0.187:8333 -91.150.189.155:8333 -91.185.198.216:8333 -91.196.11.45:8333 -91.197.44.133:8333 -91.224.0.227:8333 -91.226.10.90:8333 -91.228.45.130:8333 -91.229.77.239:8333 -91.238.100.249:8333 -91.240.141.169:8333 -92.27.7.209:8333 -92.54.16.135:8333 -93.89.84.93:8333 -93.100.51.48:8333 -93.100.76.151:8333 -93.104.214.235:8333 -93.115.86.246:8333 -93.123.80.47:8333 -93.174.88.211:8333 -93.188.224.253:8333 -93.190.69.242:8333 -94.74.81.93:8333 -94.156.35.8:8333 -94.176.237.241:8333 -94.181.44.104:8333 -94.227.43.171:8333 -95.79.102.208:8333 -95.79.102.209:8333 -95.154.237.24:8333 -95.183.48.62:8333 -95.183.48.71:8333 -95.213.161.2:8333 -95.213.201.94:8333 -96.20.227.39:8333 -96.28.41.91:8333 -98.127.130.17:8333 -100.36.48.101:8333 -101.0.81.42:8333 -101.0.81.43:8333 -103.11.64.46:8333 -103.24.244.69:8333 -103.47.210.50:8333 -103.76.41.169:8333 -103.80.168.57:8333 -103.203.51.186:8333 -103.224.118.79:8333 -103.250.4.74:8333 -104.192.170.202:8333 -104.196.0.99:8333 -104.199.192.85:8333 -104.219.251.46:8333 -104.223.108.33:8333 -104.237.2.189:8333 -104.247.230.28:8333 -107.150.45.210:8333 -107.174.34.77:8333 -107.174.34.78:8333 -107.180.71.47:8333 -108.59.12.163:8333 -108.168.37.13:8333 -108.175.3.18:8333 -108.234.193.106:8333 -109.9.173.13:8333 -109.101.220.151:8333 -109.172.104.119:8333 -109.195.193.138:8333 -109.206.177.21:8333 -109.226.35.28:8333 -109.255.0.107:8333 -113.29.183.143:8333 -114.145.97.73:8333 -115.66.205.171:8333 -118.67.201.40:8333 -118.194.226.168:8333 -119.28.70.144:8333 -120.24.166.73:9998 -120.76.244.201:10022 -121.82.4.232:8333 -121.254.173.40:8333 -123.203.163.128:8333 -124.171.70.45:8333 -125.63.57.7:8333 -125.128.35.41:8333 -128.208.244.124:8333 -128.230.208.73:8333 -131.114.10.233:8333 -131.114.10.235:8333 -132.239.36.105:8333 -134.213.214.233:8333 -136.61.238.121:8333 -136.62.86.140:8333 -136.144.128.49:8333 -137.48.144.52:8333 -137.116.160.176:8333 -137.117.193.113:8333 -138.19.79.208:8333 -138.68.64.19:8333 -139.59.96.16:8333 -139.162.160.232:8333 -141.136.115.230:8333 -142.59.232.111:8333 -142.111.2.74:8333 -142.162.128.23:8333 -143.107.116.5:8333 -143.229.22.74:8333 -143.229.36.71:8333 -144.2.105.60:8333 -144.76.224.214:8333 -146.185.19.30:8333 -147.32.30.25:8333 -147.229.13.210:8333 -148.103.7.119:8333 -150.101.114.194:8333 -150.229.0.143:8333 -154.66.207.126:8333 -158.129.212.236:8333 -158.129.212.251:8333 -160.16.206.31:8333 -162.209.1.233:8333 -162.209.4.125:8333 -162.220.246.225:8333 -163.172.218.186:8333 -166.230.70.145:8333 -168.235.74.45:8333 -169.44.34.88:8333 -170.75.195.168:8333 -172.112.2.67:8333 -173.94.164.38:8333 -173.183.232.109:8333 -173.208.176.122:8333 -173.212.194.114:8333 -173.232.228.146:8333 -175.126.124.92:8333 -175.145.109.51:8333 -176.24.198.205:8333 -176.36.37.62:8333 -176.36.99.222:8333 -176.106.144.183:8333 -177.33.1.40:8333 -178.162.214.225:8333 -178.164.109.83:8333 -178.170.138.202:8333 -178.175.136.122:8333 -178.218.209.162:8333 -178.254.2.64:8333 -178.254.34.144:8333 -178.255.41.21:8333 -178.255.144.163:8333 -180.181.208.42:8333 -180.200.128.58:8333 -180.235.50.14:8333 -181.215.148.154:8333 -184.64.13.43:8333 -184.94.164.170:8333 -184.152.107.251:8333 -184.182.233.206:8333 -185.4.24.199:8333 -185.20.99.49:8333 -185.24.97.11:8333 -185.25.48.27:8333 -185.25.48.71:8333 -185.26.196.249:8333 -185.28.76.179:8333 -185.35.139.250:8333 -185.41.113.69:8333 -185.50.213.123:8333 -185.50.213.124:8333 -185.50.232.114:8333 -185.51.192.40:8333 -185.53.129.244:8333 -185.71.177.100:8333 -185.77.129.176:8333 -185.82.201.51:8333 -185.121.173.223:8333 -185.140.252.253:8333 -185.145.129.184:8333 -185.145.130.163:8333 -185.154.156.50:8333 -185.162.124.69:8333 -185.170.42.2:8333 -186.149.197.96:8333 -188.65.212.138:8333 -188.65.213.48:8333 -188.93.209.192:8333 -188.113.79.45:8333 -188.113.84.116:8333 -188.113.164.231:8333 -188.122.16.153:8333 -188.165.224.28:8333 -188.175.239.227:8333 -188.214.128.18:8333 -188.227.64.19:8333 -188.253.2.125:8333 -189.45.203.166:8333 -190.184.198.34:8333 -192.151.145.250:8333 -192.206.202.6:8333 -192.228.101.157:8333 -193.2.76.41:8333 -193.27.209.100:8333 -193.33.237.187:8333 -193.46.83.17:8333 -193.49.43.219:8333 -194.24.182.27:8333 -194.28.206.201:8333 -194.63.143.197:8333 -194.71.109.91:8333 -194.79.8.36:8333 -194.135.93.38:8333 -194.186.160.253:8333 -195.9.140.134:8333 -195.39.206.29:8333 -195.67.36.89:8333 -195.169.99.82:8333 -195.214.214.253:8333 -195.223.71.147:8333 -198.37.118.11:8333 -198.54.113.125:8333 -198.101.12.139:8333 -198.143.12.105:8333 -198.251.83.19:8333 -199.127.224.50:8333 -200.12.138.146:8333 -200.116.98.185:8333 -200.122.128.130:8333 -202.29.6.48:8333 -202.133.115.115:8333 -203.59.17.160:8333 -204.15.11.4:8333 -204.111.241.195:8333 -205.251.85.151:8333 -207.244.70.40:8333 -207.254.50.72:8333 -208.76.93.83:8333 -208.107.97.242:8333 -208.110.73.107:8333 -208.118.235.190:8333 -209.73.142.226:8333 -209.81.9.223:8333 -209.126.107.166:8333 -209.177.86.19:8333 -209.250.6.190:8333 -210.1.219.155:8333 -210.211.109.165:8333 -210.223.3.44:8333 -211.21.129.69:8333 -212.50.98.161:8333 -212.51.140.183:8333 -212.56.108.81:8333 -212.83.35.173:8333 -212.90.179.206:8333 -212.93.226.90:8333 -212.110.171.118:8333 -213.5.36.58:8333 -213.5.181.205:8333 -213.17.16.251:8333 -213.91.205.134:8333 -213.91.211.17:8333 -213.155.3.216:8333 -213.168.13.151:8333 -213.186.170.109:8334 -213.222.208.150:8333 -216.32.213.112:8333 -216.59.4.212:8333 -216.126.193.163:8333 -216.197.79.74:8333 -216.218.147.140:8333 -216.227.39.84:8333 -216.245.206.181:8333 -216.249.92.230:8333 -217.12.199.207:8333 -217.23.2.177:8333 -217.23.5.68:8333 -217.28.194.2:8333 -217.35.130.42:8333 -217.64.47.138:8333 -217.101.72.242:8333 -217.145.81.229:8333 -217.168.143.169:8333 -217.169.7.111:8333 -217.182.192.7:8333 -219.88.232.229:8333 -219.113.244.52:8333 -220.130.128.58:8333 -220.244.225.239:8333 -221.141.3.12:8333 -222.166.176.99:8333 -223.252.173.147:8333 -[2001:0:4137:9e76:1025:4e5:acb0:22cd]:8333 -[2001:0:4137:9e76:1078:18a6:5d2c:2461]:8333 -[2001:0:4137:9e76:10ec:236a:bd3b:f3c0]:8333 -[2001:0:4137:9e76:186d:3f17:b7ad:95cf]:8333 -[2001:0:4137:9e76:1870:242:ac03:aaf9]:8333 -[2001:0:4137:9e76:18a6:1102:2abf:eb70]:8333 -[2001:0:4137:9e76:1ce5:248c:4ff5:2b1d]:8333 -[2001:0:4137:9e76:200f:156a:bc77:3acd]:8333 -[2001:0:4137:9e76:2418:19d1:cddc:b1af]:8333 -[2001:0:4137:9e76:2857:3d78:aaf8:eb28]:8333 -[2001:0:4137:9e76:28b2:1b84:64fb:2d6a]:8333 -[2001:0:4137:9e76:2c70:d51:d046:1209]:8333 -[2001:0:4137:9e76:2cac:2fcf:46bb:be0d]:8333 -[2001:0:4137:9e76:305e:20ee:a94f:6f69]:8333 -[2001:0:4137:9e76:30cd:849:adfe:6e67]:8333 -[2001:0:4137:9e76:345b:f12:ae1e:2948]:8333 -[2001:0:4137:9e76:3c40:146e:9741:5a3a]:8333 -[2001:0:4137:9e76:3c9e:3c3e:9d6e:7340]:8333 -[2001:0:4137:9e76:499:29a8:d047:7ea1]:8333 -[2001:0:4137:9e76:51:24:81b2:59e3]:8333 -[2001:0:4137:9e76:889:2d7c:b61b:bf0d]:8333 -[2001:0:4137:9e76:c9f:379c:add2:c938]:8333 -[2001:0:4137:9e76:cd6:2eb4:b82b:addb]:8333 -[2001:0:4137:9e76:cf0:2e3a:b29d:6207]:8333 -[2001:0:53aa:64c:1485:fbf9:a798:1ffe]:8333 -[2001:0:53aa:64c:59:617f:a10d:e0]:8333 -[2001:0:5ef5:79fb:1020:2cd0:4750:eb12]:8333 -[2001:0:5ef5:79fb:1036:1d50:3881:6930]:8333 -[2001:0:5ef5:79fb:10a4:27d8:9c0a:cfa9]:8333 -[2001:0:5ef5:79fb:10ae:5a8:524b:dcc4]:8333 -[2001:0:5ef5:79fb:1892:3e3a:3f74:affa]:8333 -[2001:0:5ef5:79fb:1c95:1a60:d1f5:215b]:8333 -[2001:0:5ef5:79fb:200b:16ef:b9cf:9860]:8333 -[2001:0:5ef5:79fb:28e4:fbff:3237:992]:8333 -[2001:0:5ef5:79fb:2ce8:1d9e:b3bf:b53e]:8333 -[2001:0:5ef5:79fb:300a:2e20:4750:eb12]:8333 -[2001:0:5ef5:79fb:30a2:1ad9:5324:836a]:8333 -[2001:0:5ef5:79fb:3409:1996:bcac:241f]:8333 -[2001:0:5ef5:79fb:344b:2bd4:bb3e:e26]:8333 -[2001:0:5ef5:79fb:34b3:11db:e7da:d461]:8333 -[2001:0:5ef5:79fb:3839:2e0c:ba30:288e]:8333 -[2001:0:5ef5:79fb:3880:ef4:b5f0:ee4d]:8333 -[2001:0:5ef5:79fb:389f:52:9c0c:1f41]:8333 -[2001:0:5ef5:79fb:3c73:304a:9d8b:99d5]:8333 -[2001:0:5ef5:79fb:3cac:33e4:39ca:38c]:8333 -[2001:0:5ef5:79fb:6f:3667:5398:538f]:8333 -[2001:0:5ef5:79fb:88c:3e6:9454:3331]:8333 -[2001:0:5ef5:79fb:89:3b55:9fcc:8e66]:8333 -[2001:0:5ef5:79fb:c9b:3d65:bdf4:5d58]:8333 -[2001:0:5ef5:79fb:cb7:8cc:b8ee:6806]:8333 -[2001:0:5ef5:79fd:24f6:37b5:b9d2:2aa7]:8333 -[2001:0:5ef5:79fd:3c63:82e:aabc:bd39]:8333 -[2001:0:5ef5:79fd:3cf5:2eb7:c966:561d]:8333 -[2001:0:5ef5:79fd:cf4:28e2:aabd:b766]:8333 -[2001:0:9d38:6ab8:10f6:453:3ca4:1a8e]:8333 -[2001:0:9d38:6ab8:14dd:298b:431c:bfec]:8333 -[2001:0:9d38:6ab8:3051:1561:b62d:73a5]:8333 -[2001:0:9d38:6ab8:3467:ffa:b612:e9c6]:8333 -[2001:0:9d38:6ab8:8e8:1e26:e8e3:eed7]:8333 -[2001:0:9d38:6ab8:c82:37b3:47ee:3ae2]:8333 -[2001:0:9d38:6abd:1052:3cd8:a89b:e67]:8333 -[2001:0:9d38:6abd:144d:23f3:abcb:8bcb]:8333 -[2001:0:9d38:6abd:1c2e:31df:adf1:e616]:8333 -[2001:0:9d38:6abd:1c41:213b:facc:9c6b]:8333 -[2001:0:9d38:6abd:2093:12b5:8cbf:4f57]:8333 -[2001:0:9d38:6abd:243a:2394:fd91:712c]:8333 -[2001:0:9d38:6abd:2833:9f8:c94c:6881]:8333 -[2001:0:9d38:6abd:2c84:29d3:ae5a:f6f0]:8333 -[2001:0:9d38:6abd:2ce4:d50:cb22:3672]:8333 -[2001:0:9d38:6abd:3824:816:c30d:e9d4]:8333 -[2001:0:9d38:6abd:389a:24e9:cb5c:a1cd]:8333 -[2001:0:9d38:6abd:38bd:88f:2193:4932]:8333 -[2001:0:9d38:6abd:3c4f:cb1:d65b:d775]:8333 -[2001:0:9d38:6abd:3c51:280b:b1e9:ffd]:8333 -[2001:0:9d38:6abd:3c5a:2e2:2193:4932]:8333 -[2001:0:9d38:6abd:3c5e:3ebf:3dc0:703a]:8333 -[2001:0:9d38:6abd:4c9:12fc:d1d9:dc21]:8333 -[2001:0:9d38:6abd:6e:34e7:d0a7:6772]:8333 -[2001:0:9d38:6abd:8de:1f29:2aea:f96f]:8333 -[2001:0:9d38:6abd:c5f:2674:a467:787c]:8333 -[2001:0:9d38:6abd:cc0:23a4:ad7c:c998]:8333 -[2001:0:9d38:78cf:20c0:2097:d188:9c3b]:8333 -[2001:0:9d38:78cf:2420:dda:4ff6:8794]:8333 -[2001:0:9d38:78cf:2892:fcb:26b2:22ac]:8333 -[2001:0:9d38:78cf:3020:1ad7:26b2:22ac]:8333 -[2001:0:9d38:78cf:30ae:211b:e717:7788]:8333 -[2001:0:9d38:78cf:30d0:6edd:a418:a9e9]:8333 -[2001:0:9d38:78cf:30d9:3278:b004:65a7]:8333 -[2001:0:9d38:78cf:387a:17d5:dacb:bdf1]:8333 -[2001:0:9d38:78cf:3c38:c41:433c:7b87]:8333 -[2001:0:9d38:78cf:467:193:a8b0:a122]:8333 -[2001:0:9d38:78cf:c65:fb96:97d2:a9b0]:8333 -[2001:0:9d38:78cf:c9f:2633:d169:9999]:8333 -[2001:0:9d38:78cf:ce2:aba:d120:90db]:8333 -[2001:0:9d38:90d7:105d:26f2:a241:7339]:8333 -[2001:0:9d38:90d7:1062:3f95:e065:fc21]:8333 -[2001:0:9d38:90d7:10a6:19f6:ab95:ebcb]:8333 -[2001:0:9d38:90d7:14e2:22cb:738f:9489]:8333 -[2001:0:9d38:90d7:18fb:3da9:893d:1d57]:8333 -[2001:0:9d38:90d7:1cc3:2534:e020:53fa]:8333 -[2001:0:9d38:90d7:206d:2b34:d0cb:9de8]:8333 -[2001:0:9d38:90d7:20cb:2cb:b9a7:ca5e]:8333 -[2001:0:9d38:90d7:245c:2753:4382:704b]:8333 -[2001:0:9d38:90d7:24d6:225f:793b:bf5]:8333 -[2001:0:9d38:90d7:24da:8f0:bbf9:9c93]:8333 -[2001:0:9d38:90d7:28a2:107b:438e:b08d]:8333 -[2001:0:9d38:90d7:2c16:d58:b381:b61]:8333 -[2001:0:9d38:90d7:2c68:3068:cb59:3be7]:8333 -[2001:0:9d38:90d7:2c90:3855:b94f:c926]:8333 -[2001:0:9d38:90d7:2ca2:3592:c111:dd82]:8333 -[2001:0:9d38:90d7:2cce:1f6e:b381:8605]:8333 -[2001:0:9d38:90d7:3435:3915:2bcc:6cc7]:8333 -[2001:0:9d38:90d7:3438:2b9f:ad57:a721]:8333 -[2001:0:9d38:90d7:3474:1df1:e732:e5e3]:8333 -[2001:0:9d38:90d7:38c4:37af:ab0a:f5ef]:8333 -[2001:0:9d38:90d7:3a:39fd:a43b:5591]:8333 -[2001:0:9d38:90d7:3c9d:2a45:d537:3bd6]:8333 -[2001:0:9d38:90d7:3cfb:2cf5:5254:4d1e]:8333 -[2001:0:9d38:90d7:43f:337:adb4:6310]:8333 -[2001:0:9d38:90d7:493:995:d2e9:39be]:8333 -[2001:0:9d38:90d7:5b:ce3:b275:92ab]:8333 -[2001:0:9d38:90d7:8a8:59d:d0cb:d585]:8333 -[2001:0:9d38:90d7:c8e:1ba0:c5a9:dace]:8333 -[2001:0:9d38:90d7:cdb:365f:2302:f729]:8333 -[2001:0:9d38:90d7:cf5:222e:893e:716c]:8333 -[2001:0:9d38:90d7:d6:1085:b8dd:41c2]:8333 -[2001:0:9d38:953c:101a:23b3:6b98:f888]:8333 -[2001:0:9d38:953c:1805:f38:3eb2:2121]:8333 -[2001:0:9d38:953c:1858:16f9:3833:da19]:8333 -[2001:0:9d38:953c:18ea:2735:e73d:adc5]:8333 -[2001:0:9d38:953c:1c44:2b70:9de7:a7cc]:8333 -[2001:0:9d38:953c:200a:3f95:bb7c:c09f]:8333 -[2001:0:9d38:953c:200c:3473:b85d:ddd]:8333 -[2001:0:9d38:953c:200f:5a0:47c6:5507]:8333 -[2001:0:9d38:953c:2097:204a:47c5:5881]:8333 -[2001:0:9d38:953c:248f:24cd:aaf5:dee3]:8333 -[2001:0:9d38:953c:287d:168e:3caf:47af]:8333 -[2001:0:9d38:953c:28c1:58d:b721:94c1]:8333 -[2001:0:9d38:953c:2c31:30a3:39d3:528]:8188 -[2001:0:9d38:953c:2c3d:309b:d2db:8288]:8333 -[2001:0:9d38:953c:2c47:1b36:52c1:3c73]:8333 -[2001:0:9d38:953c:304a:10e1:b739:822a]:8333 -[2001:0:9d38:953c:30a3:29fd:33f6:eaab]:8333 -[2001:0:9d38:953c:3427:859b:b525:1069]:8333 -[2001:0:9d38:953c:3459:2541:3651:d675]:8333 -[2001:0:9d38:953c:4f5:9c88:af91:d3d3]:8333 -[2001:0:9d38:953c:cd1:1d54:b80a:42f4]:8333 -[2001:0:9d38:953c:cfa:37e6:9d8e:7474]:8333 -[2001:13d8:1c01:2000:2470::1]:8333 -[2001:1470:fffd:202c:225:90ff:fe8f:5f62]:8333 -[2001:14ba:200:0:543c:42ce:a48b:b0d0]:8333 -[2001:14ba:2fc:700:41b2:df51:efd8:f581]:8333 -[2001:19f0:5000:8c8b:5400:ff:fe1f:c023]:8333 -[2001:19f0:5:749:5400:ff:fe71:c3fc]:8333 -[2001:19f0:5:bc:5400:ff:fe3b:9339]:8333 -[2001:19f0:7402:42c:5400:ff:fe6c:b9b8]:8333 -[2001:1af8:4010:a08f:f811:e5f0:3f63:e753]:8333 -[2001:1af8:4010:a094:3333::8c38]:8333 -[2001:1af8:4070:a016:3333::5afb]:8333 -[2001:1af8:4700:a071:4444::e26e]:8333 -[2001:1bc8:1a0:590e:2e0:f4ff:fe16:3a39]:8333 -[2001:2040:77::89]:8333 -[2001:288:1001:107:294e:5581:74bd:42f9]:8333 -[2001:3c8:c103:a001::48]:8333 -[2001:4128:6135:10:20c:29ff:fe69:9e81]:8333 -[2001:4128:6135:2010:21e:bff:fee8:a3c0]:8333 -[2001:4128:6135:e001:5054:ff:fe37:e9eb]:8333 -[2001:4178:6:1427:62:116:188:85]:8333 -[2001:41d0:1004:20f0::]:8333 -[2001:41d0:1008:2752::]:8333 -[2001:41d0:1:4722::1]:8333 -[2001:41d0:1:6f57::1]:8333 -[2001:41d0:1:7353::1]:8333 -[2001:41d0:1:7469::1]:8333 -[2001:41d0:1:7d09::1]:8333 -[2001:41d0:1:8b26::1]:8333 -[2001:41d0:1:c129::1]:8333 -[2001:41d0:1:d227::]:8333 -[2001:41d0:1:e13b::1]:8333 -[2001:41d0:1:e623::1]:8333 -[2001:41d0:2:16be::1]:8333 -[2001:41d0:2:203c::1]:8333 -[2001:41d0:2:3242::]:8333 -[2001:41d0:2:8a0f::]:8333 -[2001:41d0:2:8c65::]:8333 -[2001:41d0:2:8d13::]:8333 -[2001:41d0:2:9459::]:8333 -[2001:41d0:2:950a:ffff:ffff:0:3]:8333 -[2001:41d0:2:9c94::1]:8333 -[2001:41d0:2:a212::]:8333 -[2001:41d0:2:a232::]:8333 -[2001:41d0:2:ab1c::]:8333 -[2001:41d0:2:bf2a::]:8333 -[2001:41d0:2:c793::]:8333 -[2001:41d0:302:1000::fa25]:8333 -[2001:41d0:303:1907::]:8333 -[2001:41d0:52:d00::6e2]:8333 -[2001:41d0:52:d00::6e3]:8333 -[2001:41d0:8:1b29::]:8333 -[2001:41d0:8:3d4b::1]:8333 -[2001:41d0:8:4d4d::1]:8333 -[2001:41d0:8:7a38::1]:8333 -[2001:41d0:8:8f46::1]:8333 -[2001:41d0:8:ba87::1]:8333 -[2001:41d0:8:bd45::1]:8333 -[2001:41d0:8:bed3::]:8333 -[2001:41d0:8:c67c::]:8333 -[2001:41d0:8:d844:1337::1017]:8333 -[2001:41d0:8:ddb::1]:8333 -[2001:41d0:8:ddf::1]:8333 -[2001:41d0:8:de3d::1]:8333 -[2001:41d0:8:e3e4::1]:8333 -[2001:41d0:a:4e3f::1c7d:6b01]:8333 -[2001:41d0:a:635b::1]:8333 -[2001:41d0:a:6810::1]:8333 -[2001:41d0:a:6c29::1]:8333 -[2001:41d0:a:6fd0::]:8333 -[2001:41d0:a:fac7::1]:8333 -[2001:41d0:d:111c::]:8333 -[2001:41d0:d:2ac8::]:8333 -[2001:41d0:e:1388::1]:8333 -[2001:41f0:61:0:72f3:95ff:fe09:7521]:8333 -[2001:41f0:61::7]:8333 -[2001:470:1f07:151c:baac:6fff:feb7:3ba9]:8333 -[2001:470:1f0b:8c4::5]:8333 -[2001:470:1f0b:967::11]:8333 -[2001:470:1f15:11f8::10]:8333 -[2001:470:1f15:1b95:2c3e:8a9a:24e1:7084]:8333 -[2001:470:1f15:f28::3]:8333 -[2001:470:1f1a:172::2]:8333 -[2001:470:1f1c:b07::2]:8333 -[2001:470:1f1d:3a9::10]:8333 -[2001:470:25:482::2]:8333 -[2001:470:28:365::4]:8333 -[2001:470:754f:42::17a]:8333 -[2001:470:7:b74::2]:8333 -[2001:470:7dda:1::1]:8333 -[2001:470:8:c70:20c:29ff:fe6a:8fdc]:8333 -[2001:470:8:c70::54]:8333 -[2001:470:a:c13::2]:8333 -[2001:470:d00d:0:3664:a9ff:fe9a:5150]:8333 -[2001:470:dbf2:aaaa::b17:c01c]:8333 -[2001:470:f457:8000::a6]:8333 -[2001:4801:7819:74:b745:b9d5:ff10:a61a]:8333 -[2001:4801:7819:74:b745:b9d5:ff10:aaec]:8333 -[2001:4801:7828:104:be76:4eff:fe10:1325]:8333 -[2001:4ba0:cafe:13c0::1]:8333 -[2001:4ba0:cafe:418::1]:8333 -[2001:558:6045:23:1830:896c:d901:190d]:8333 -[2001:67c:1220:80c::93e5:dd2]:8333 -[2001:67c:2128:ffff:6062:36ff:fe30:6532]:8333 -[2001:8d8:923:8400::87:ebd]:8333 -[2001:981:4452:1::100]:8333 -[2001:981:46:1:ba27:ebff:fe5b:edee]:8333 -[2001:981:bdbd:1:c506:7d38:4b47:da15]:8333 -[2001:985:79af:20::35]:8333 -[2001:bc8:225f:10e:505:6573:7573:d0a]:8333 -[2001:bc8:323c:100::53]:8333 -[2001:bc8:323c:100::80:4]:8333 -[2001:bc8:323c:100::cafe]:8333 -[2001:bc8:3680:4242::1]:8333 -[2001:bc8:399f:f000::1]:8333 -[2002:1e2:5587::1e2:5587]:8333 -[2002:1e2:5588::1e2:5588]:8333 -[2002:2a33:21c4::2a33:21c4]:8333 -[2002:2e04:784b::2e04:784b]:8333 -[2002:2ebc:2c14::16]:8333 -[2002:2f5a:3c1c::2f5a:3c1c]:10011 -[2002:2f5a:562a::2f5a:562a]:8333 -[2002:2f5b:a5f9::2f5b:a5f9]:8333 -[2002:3141:28c::3141:28c]:8333 -[2002:323f:a2f2::323f:a2f2]:8333 -[2002:323f:fbd::323f:fbd]:8333 -[2002:33ff:69a0::1]:8333 -[2002:3e6a:106f::3e6a:106f]:8333 -[2002:3e70:bbc::3e70:bbc]:8333 -[2002:3e7a:6727::3e7a:6727]:8333 -[2002:3f62:e6bb::3f62:e6bb]:8333 -[2002:4540:4b30::4540:4b30]:8333 -[2002:4e6b:c745::1]:8333 -[2002:5052:4d8a::5052:4d8a]:8333 -[2002:51a9:9cc9::51a9:9cc9]:8333 -[2002:54fb:cb05::1]:8333 -[2002:5bc2:5428::5bc2:5428]:8333 -[2002:5bce:1253::5bce:1253]:8333 -[2002:5bdb:19e8::5bdb:19e8]:8333 -[2002:5c3f:3912::5c3f:3912]:8333 -[2002:5dbd:91a9::5dbd:91a9]:8333 -[2002:5dbe:8cc6::5dbe:8cc6]:8333 -[2002:5fd3:8944::5fd3:8944]:8333 -[2002:65c8:a018::65c8:a018]:8333 -[2002:6750:a839::6750:a839]:8333 -[2002:67fa:44b::67fa:44b]:8333 -[2002:6a0e:3ea8::6a0e:3ea8]:10011 -[2002:6a0f:2497::6a0f:2497]:8333 -[2002:6dec:5ac7::6dec:5ac7]:8333 -[2002:704a:d6d4::704a:d6d4]:9997 -[2002:7237:fcf6::7237:fcf6]:20188 -[2002:76b2:7f40::76b2:7f40]:8333 -[2002:7819:7e80::7819:7e80]:7743 -[2002:781b:8db8::781b:8db8]:8333 -[2002:7b38:cd00::7b38:cd00]:8333 -[2002:ac52:b854::ac52:b854]:8333 -[2002:b610:1ca3::b610:1ca3]:8333 -[2002:b946:694a::b946:694a]:8339 -[2002:b994:9167::b994:9167]:8333 -[2002:bc28:6b92::bc28:6b92]:8333 -[2002:c23f:8fc5::c23f:8fc5]:8333 -[2002:c338:3f0a::c338:3f0a]:8333 -[2002:d1b1:5615::d1b1:5615]:8333 -[2002:d2d3:6da5::d2d3:6da5]:8333 -[2002:d917:2b1::d917:2b1]:8333 -[2002:db71:f434::db71:f434]:8333 -[2003:a:36f:4f01::1]:8333 -[2003:a:37f:ef4f:dead:babe:b00b:beef]:8333 -[2400:8901::f03c:91ff:fe2c:63d8]:8333 -[2400:8902::f03c:91ff:fed5:9d8d]:8333 -[2401:2500:203:10:153:120:156:83]:8333 -[2401:a400:3200:5600:14ee:f361:4bdc:1f7c]:8333 -[2402:1f00:8100:36::]:8333 -[2403:4200:403:2::ff]:8333 -[2405:9800:b440:947f:59a5:f379:1876:858c]:8333 -[2405:aa00:2::40]:8333 -[2406:da14:445:5201::4]:8333 -[2406:da18:f7c:4351:1a58:81fe:6ed0:1103]:8333 -[2406:da18:f7c:4351:22aa:2585:fe88:7d58]:8333 -[2406:da18:f7c:4351:2674:33bb:25d6:cbba]:8333 -[2406:da18:f7c:4351:2e19:a8c7:a36a:bde0]:8333 -[2406:da18:f7c:4351:3cc8:43d:fbcc:5067]:8333 -[2406:da18:f7c:4351:5228:2b53:bb9a:edf5]:8333 -[2406:da18:f7c:4351:5729:102:998c:d41a]:8333 -[2406:da18:f7c:4351:591b:4881:3986:3703]:8333 -[2406:da18:f7c:4351:59b9:b50:f47f:b560]:8333 -[2406:da18:f7c:4351:61f2:cfb0:8c45:5fdd]:8333 -[2406:da18:f7c:4351:6356:68e0:73fc:ac0b]:8333 -[2406:da18:f7c:4351:660e:f6bc:3563:ba8e]:8333 -[2406:da18:f7c:4351:691:9e:f2df:227d]:8333 -[2406:da18:f7c:4351:721c:83d2:6765:4300]:8333 -[2406:da18:f7c:4351:7237:9be:4601:bc15]:8333 -[2406:da18:f7c:4351:7a3b:c203:fd11:6c7d]:8333 -[2406:da18:f7c:4351:7a74:a80e:889a:ba42]:8333 -[2406:da18:f7c:4351:7ee3:a181:f25c:fa79]:8333 -[2406:da18:f7c:4351:8a25:9084:140:4549]:8333 -[2406:da18:f7c:4351:8bc0:c6fd:ecfb:f074]:8333 -[2406:da18:f7c:4351:91ce:d0ba:1b9e:c27b]:8333 -[2406:da18:f7c:4351:9336:44e7:84b4:85b9]:8333 -[2406:da18:f7c:4351:936c:c3b9:a1d0:848]:8333 -[2406:da18:f7c:4351:93ef:1eef:65c8:766d]:8333 -[2406:da18:f7c:4351:94e0:5b27:78c2:5111]:8333 -[2406:da18:f7c:4351:9815:a202:18a3:2a36]:8333 -[2406:da18:f7c:4351:9e1b:135c:7472:9d9]:8333 -[2406:da18:f7c:4351:9f84:278:68f5:b8ea]:8333 -[2406:da18:f7c:4351:a062:493f:a6f8:ca75]:8333 -[2406:da18:f7c:4351:a192:b98:3066:8f11]:8333 -[2406:da18:f7c:4351:a1cb:2f19:4a54:38c9]:8333 -[2406:da18:f7c:4351:a4a2:4c9:c43a:98ae]:8333 -[2406:da18:f7c:4351:a7e9:cd48:fa90:46d3]:8333 -[2406:da18:f7c:4351:a88:99:6671:fce4]:8333 -[2406:da18:f7c:4351:abe1:2e48:eb97:2ab5]:8333 -[2406:da18:f7c:4351:acf5:2b21:5d2a:6b31]:8333 -[2406:da18:f7c:4351:b51f:8966:74a5:6c53]:8333 -[2406:da18:f7c:4351:b8e3:f3ca:e412:daa5]:8333 -[2406:da18:f7c:4351:ba7c:6da8:da59:b1b6]:8333 -[2406:da18:f7c:4351:be04:6f8e:8f93:c555]:8333 -[2406:da18:f7c:4351:c82d:2a0b:31a5:e28d]:8333 -[2406:da18:f7c:4351:c993:eb06:bd2c:1e65]:8333 -[2406:da18:f7c:4351:d4b9:bff8:c4d4:1e05]:8333 -[2406:da18:f7c:4351:d70d:a73d:1ddd:439e]:8333 -[2406:da18:f7c:4351:e103:f456:b296:9f29]:8333 -[2406:da18:f7c:4351:ea3b:27ec:7c2:aebc]:8333 -[2406:da18:f7c:4351:f62c:5013:379b:363e]:8333 -[240b:10:ca20:f0:224:e8ff:fe1f:60d9]:8333 -[240b:250:1e0:2400:b9ef:8fe3:a69a:7378]:8333 -[2600:1f14:34a:fe00:13f4:ceb6:a9db:4f47]:8333 -[2600:1f14:34a:fe00:2550:9366:a5d9:78a5]:8333 -[2600:1f14:34a:fe00:27d:6ed:7c8d:7bee]:8333 -[2600:1f14:34a:fe00:2ed6:8a19:4eb:36c1]:8333 -[2600:1f14:34a:fe00:34c7:2e9e:e60e:f823]:8333 -[2600:1f14:34a:fe00:38de:442:72df:6346]:8333 -[2600:1f14:34a:fe00:3a1e:878f:991a:9582]:8333 -[2600:1f14:34a:fe00:3d88:1805:54e3:f4c8]:8333 -[2600:1f14:34a:fe00:3f3e:58bd:ec82:5dac]:8333 -[2600:1f14:34a:fe00:449a:9515:8436:f407]:8333 -[2600:1f14:34a:fe00:4f84:277f:e64d:1f06]:8333 -[2600:1f14:34a:fe00:5229:de84:8226:7257]:8333 -[2600:1f14:34a:fe00:5743:42c3:951b:e97a]:8333 -[2600:1f14:34a:fe00:5a29:85b:86b5:fa0e]:8333 -[2600:1f14:34a:fe00:5de8:81e:6d79:330b]:8333 -[2600:1f14:34a:fe00:5fca:ad1e:5b9c:5265]:8333 -[2600:1f14:34a:fe00:68c4:ca1b:813e:1bce]:8333 -[2600:1f14:34a:fe00:6:de9e:7b5e:a558]:8333 -[2600:1f14:34a:fe00:6c72:1fcd:433:dc97]:8333 -[2600:1f14:34a:fe00:77ee:629f:bc13:fb4f]:8333 -[2600:1f14:34a:fe00:79d0:85d6:516f:3293]:8333 -[2600:1f14:34a:fe00:81:422f:9ef3:4579]:8333 -[2600:1f14:34a:fe00:822b:5f05:ec8d:48c6]:8333 -[2600:1f14:34a:fe00:82a:76a2:fdc9:845e]:8333 -[2600:1f14:34a:fe00:83ca:cef6:e04c:50c0]:8333 -[2600:1f14:34a:fe00:8ba2:a36c:8687:d5aa]:8333 -[2600:1f14:34a:fe00:8c80:5c67:3b47:90b3]:8333 -[2600:1f14:34a:fe00:8eb8:f47f:6d53:e3ae]:8333 -[2600:1f14:34a:fe00:989c:f8f8:a922:1b9a]:8333 -[2600:1f14:34a:fe00:98c9:1eb3:ea12:a8f0]:8333 -[2600:1f14:34a:fe00:9ee5:a8f6:6b2a:866e]:8333 -[2600:1f14:34a:fe00:a46b:7bd5:629f:f75c]:8333 -[2600:1f14:34a:fe00:a627:8299:8784:d439]:8333 -[2600:1f14:34a:fe00:ad0b:955e:b4e5:d97d]:8333 -[2600:1f14:34a:fe00:ae82:7117:9d69:7c86]:8333 -[2600:1f14:34a:fe00:ccee:365a:43f8:b871]:8333 -[2600:1f14:34a:fe00:d5ee:a3e2:2f85:e593]:8333 -[2600:1f14:34a:fe00:d5f0:1fe0:6bd5:18a8]:8333 -[2600:1f14:34a:fe00:e4a7:5aba:af87:4cdb]:8333 -[2600:1f14:34a:fe00:e8e5:2d0:fb6f:2f5]:8333 -[2600:1f14:34a:fe00:e9ef:4690:a5ac:92be]:8333 -[2600:1f14:34a:fe00:efba:2260:6997:fcf7]:8333 -[2600:1f14:34a:fe00:f107:2d08:c67:e5dd]:8333 -[2600:1f14:34a:fe00:f1b9:88fb:f3db:a86e]:8333 -[2600:1f14:34a:fe00:f79c:17b7:6f75:95b7]:8333 -[2600:1f14:6ae:d900:6550:3fc5:e074:a72c]:8333 -[2600:1f16:625:e00:1243:38b3:caa:d62e]:8333 -[2600:1f16:625:e00:166d:a956:1041:f97d]:8333 -[2600:1f16:625:e00:35f2:2428:fc57:d638]:8333 -[2600:1f16:625:e00:3c75:333e:b7f:8cc0]:8333 -[2600:1f16:625:e00:3fbf:31f:1b57:8b18]:8333 -[2600:1f16:625:e00:5617:7575:379:a8cc]:8333 -[2600:1f16:625:e00:58fa:fce6:30:a5dc]:8333 -[2600:1f16:625:e00:5e74:70dc:af78:6b77]:8333 -[2600:1f16:625:e00:7036:f651:2ee:39cd]:8333 -[2600:1f16:625:e00:7fc:9004:e7be:ffe2]:8333 -[2600:1f16:625:e00:814a:23f6:e996:5e64]:8333 -[2600:1f16:625:e00:822c:a88b:f9c:57e3]:8333 -[2600:1f16:625:e00:8314:b91e:a7ba:702]:8333 -[2600:1f16:625:e00:88bb:ee9a:10de:12]:8333 -[2600:1f16:625:e00:8c30:56f5:a29a:91de]:8333 -[2600:1f16:625:e00:8fdf:6517:7718:8c42]:8333 -[2600:1f16:625:e00:91fd:78b1:62a3:193]:8333 -[2600:1f16:625:e00:930d:93ed:76a6:3285]:8333 -[2600:1f16:625:e00:93c2:615f:a79a:c11f]:8333 -[2600:1f16:625:e00:a780:8bc8:a1f6:d417]:8333 -[2600:1f16:625:e00:a951:e663:4046:8c3a]:8333 -[2600:1f16:625:e00:ab19:5fe3:f155:1371]:8333 -[2600:1f16:625:e00:aefd:9cc7:d3:6e86]:8333 -[2600:1f16:625:e00:b031:e86e:8604:324a]:8333 -[2600:1f16:625:e00:b6e:4399:9dc2:6b45]:8333 -[2600:1f16:625:e00:b7c7:58c6:21a1:fd41]:8333 -[2600:1f16:625:e00:c169:6282:178c:27d6]:8333 -[2600:1f16:625:e00:c94e:58b:bd35:d815]:8333 -[2600:1f16:625:e00:caa5:7369:73a4:5711]:8333 -[2600:1f16:625:e00:cd15:b9f2:6e3e:6fd1]:8333 -[2600:1f16:625:e00:d6f3:775:66b7:3e92]:8333 -[2600:1f16:625:e00:dbec:f7d9:e15:f8e0]:8333 -[2600:1f16:625:e00:dbf4:4d41:594e:bc20]:8333 -[2600:1f16:625:e00:e11b:4589:a0c3:9cc7]:8333 -[2600:1f16:625:e00:ed68:15b0:3a97:be0c]:8333 -[2600:1f16:625:e00:eef3:bce0:84ee:a98b]:8333 -[2600:1f16:625:e00:ef3a:f66e:f059:d03f]:8333 -[2600:1f16:625:e00:f67c:d398:5b6:d34f]:8333 -[2600:1f16:625:e00:fe35:5099:3a8e:d123]:8333 -[2600:1f18:64d9:1603:6f6f:eef9:b595:1958]:8333 -[2600:3c00::f03c:91ff:fe84:d650]:8333 -[2600:3c00::f03c:91ff:fe89:7438]:8333 -[2600:3c00::f03c:91ff:fe91:3e49]:8333 -[2600:3c00::f03c:91ff:febb:981e]:8333 -[2600:3c01::f03c:91ff:fe69:89e9]:8333 -[2600:3c01::f03c:91ff:fe91:6a29]:8333 -[2600:3c03::f03c:91ff:fe28:1445]:8333 -[2600:3c03::f03c:91ff:fee0:233e]:8333 -[2600:6c55:7200:24d:cf4:811c:7cb3:f7a7]:8333 -[2600:8805:2400:14e:226:4aff:fe02:2ba4]:8333 -[2601:18d:4600:3cc2:20e7:b3ff:fecf:a99]:8333 -[2601:1c2:1702:5241:47d:4016:ec42:6705]:8333 -[2601:441:4101:70cd:4e3:8e81:3250:1f0b]:8333 -[2601:602:9980:f78:211:11ff:fec5:1ae]:8333 -[2601:646:4103:179f:5809:1bff:fe55:6678]:8333 -[2602:4c:323:b101:35a3:9de8:6984:ef56]:8333 -[2602:ff62:104:ac1:8000::]:8333 -[2602:ffc5:40::1:711e]:8333 -[2602:ffc5::c30:1c75]:8333 -[2604:a880:2:d0::17e9:2001]:8333 -[2604:a880:2:d0::22f8:f001]:8333 -[2604:a880:2:d0::22f9:1]:8333 -[2604:a880:2:d0::22f9:c001]:8333 -[2604:a880:2:d0::22f9:d001]:8333 -[2604:a880:2:d0::22f9:e001]:8333 -[2604:a880:2:d0::22fa:2001]:8333 -[2604:a880:2:d0::22fa:3001]:8333 -[2604:a880:400:d0::1684:5001]:8333 -[2604:a880:400:d0::1ac4:b001]:8333 -[2604:a880:400:d0::2004:4001]:8333 -[2604:a880:400:d0::2004:5001]:8333 -[2604:a880:400:d0::2004:6001]:8333 -[2604:a880:400:d0::2004:c001]:8333 -[2604:a880:400:d0::2004:d001]:8333 -[2604:a880:400:d0::2004:e001]:8333 -[2604:a880:400:d0::2004:f001]:8333 -[2604:a880:400:d0::2005:1]:8333 -[2604:a880:400:d0::2005:3001]:8333 -[2604:a880:400:d0::261f:6001]:8333 -[2604:a880:400:d0::28b8:5001]:8333 -[2604:a880:400:d0::ad7:e001]:8333 -[2605:4d00::50]:8333 -[2605:5d80:2002::245]:8333 -[2605:9880:0:953:225:90ff:fed2:c0b4]:8333 -[2606:c380::215:17ff:feb3:3ec]:8333 -[2607:1c00:a:6:3c1c:1b0d:ba4:8ea9]:8333 -[2607:1c00:a:6::1000]:8333 -[2607:4480:2:2000:250:56ff:fe86:6449]:8333 -[2607:5300:120:671::]:8333 -[2607:5300:120:962::]:8333 -[2607:5300:201:2000::1:556]:8333 -[2607:5300:203:118:3733::1414]:8333 -[2607:5300:60:10aa::1]:8333 -[2607:5300:60:1e83::]:8333 -[2607:5300:60:1e83::1000]:8333 -[2607:5300:60:1e83::2000]:8333 -[2607:5300:60:2d0::1]:8333 -[2607:5300:60:3ddf::]:8333 -[2607:5300:60:3f3c::]:8333 -[2607:5300:60:5428::]:8333 -[2607:5300:60:ac0::1]:8333 -[2607:5300:61:f4b::1]:8333 -[2607:9000:0:1:5054:ff:fe5d:264e]:8333 -[2607:f1c0:846:9a00::87:d00e]:8333 -[2607:f2d8:4005:d:a8a2:eeff:fee0:a859]:8333 -[2607:f948:0:1::1:40]:8333 -[2607:fa18:3a01::50]:8333 -[2607:fea8:3ca0:926::2]:8333 -[2607:fea8:4da0:3b0::2]:8333 -[2607:ff10:c5:502:225:90ff:fe32:d446]:8333 -[2607:ff28:9005:1::2567:57e0]:8333 -[2620:71:4000:0:192:30:120:110]:8333 -[2620:b8:4000:1000::93:1]:8333 -[2800:1a0::9]:8333 -[2801:84:0:1034:76d4:35ff:fe7f:5033]:8333 -[2a00:16d8:c::5b6a:c261]:8333 -[2a00:1768:2001:24::148:218]:8333 -[2a00:19e0:1:1:225:90ff:fea5:fc0]:8333 -[2a00:1a48:7810:101:be76:4eff:fe08:c774]:8333 -[2a00:6340:2004:0:5054:ff:fe54:38c]:8333 -[2a00:7b80:477:21::1c8c:83a6]:8333 -[2a00:7c80:0:71::8]:8333 -[2a00:7c80:0:97::7]:8333 -[2a01:238:4363:4900:d85e:c1d9:2b32:61d0]:8333 -[2a01:488:66:1000:53a9:22b:0:1]:8333 -[2a01:488:67:1000:5bfa:5526:0:1]:8333 -[2a01:488:67:1000:b01c:3379:0:1]:8333 -[2a01:4d60:3:1:5::1]:8333 -[2a01:4f8:10a:1d8f::2]:8333 -[2a01:4f8:10a:1e81::2]:8333 -[2a01:4f8:10a:2261::2]:8833 -[2a01:4f8:10a:239c::2]:9002 -[2a01:4f8:10a:294a::2]:8333 -[2a01:4f8:10a:31d3::2]:8333 -[2a01:4f8:10a:3fe6::2]:8333 -[2a01:4f8:10a:b2e::2]:8333 -[2a01:4f8:10b:12d7::2]:8333 -[2a01:4f8:10b:d50::2]:8333 -[2a01:4f8:10b:e2d::2]:8333 -[2a01:4f8:10b:ee1::2]:8333 -[2a01:4f8:110:5107::2]:8333 -[2a01:4f8:110:5292::2]:8333 -[2a01:4f8:110:536e::2]:8333 -[2a01:4f8:120:43e4::2]:8333 -[2a01:4f8:130:3332::2]:8333 -[2a01:4f8:130:430b::2]:8333 -[2a01:4f8:130:618e::2]:8333 -[2a01:4f8:130:71d2::2]:8333 -[2a01:4f8:130:7422::2]:8333 -[2a01:4f8:131:33ad::2]:8333 -[2a01:4f8:131:33ad:fea1::666]:8333 -[2a01:4f8:131:3428::2]:8333 -[2a01:4f8:140:1326::2]:8333 -[2a01:4f8:140:524a::2]:8333 -[2a01:4f8:140:6055::2]:8333 -[2a01:4f8:140:7410::2]:8333 -[2a01:4f8:140:931a::2]:8333 -[2a01:4f8:141:2254::2]:8333 -[2a01:4f8:141:22ae::2]:8333 -[2a01:4f8:150:11d4::2]:8333 -[2a01:4f8:150:70a4::2]:8333 -[2a01:4f8:150:726b::2]:8333 -[2a01:4f8:150:72ee::4202]:8333 -[2a01:4f8:150:90ca::2]:8333 -[2a01:4f8:151:30c9::2]:8333 -[2a01:4f8:151:334d::3]:8333 -[2a01:4f8:151:7175::2]:8333 -[2a01:4f8:160:41f0::1:33]:8333 -[2a01:4f8:160:636e::2]:8333 -[2a01:4f8:161:7026::2]:8333 -[2a01:4f8:162:2108::2]:8333 -[2a01:4f8:162:3121::50]:8333 -[2a01:4f8:162:424c::2]:8333 -[2a01:4f8:171:1c1b::2]:8333 -[2a01:4f8:171:1c3::2]:8333 -[2a01:4f8:171:2258::2]:8333 -[2a01:4f8:171:27d6::2]:8333 -[2a01:4f8:171:2f28::2]:8333 -[2a01:4f8:171:d23::2]:8333 -[2a01:4f8:172:10da::2]:8333 -[2a01:4f8:172:504::2]:8333 -[2a01:4f8:173:1622::2]:8333 -[2a01:4f8:173:42::2]:8333 -[2a01:4f8:190:24eb::2]:8333 -[2a01:4f8:190:528d::2]:8333 -[2a01:4f8:190:61f3::2]:8333 -[2a01:4f8:191:418f::2]:3333 -[2a01:4f8:191:63b4:5000::1]:8333 -[2a01:4f8:191:81b7::2]:8333 -[2a01:4f8:191:8328::3]:8333 -[2a01:4f8:192:4a5::2]:8333 -[2a01:4f8:192:5230::2]:8333 -[2a01:4f8:200:1012::2]:8333 -[2a01:4f8:200:32a6::2]:8333 -[2a01:4f8:200:414e::2]:8333 -[2a01:4f8:200:416a::2]:8333 -[2a01:4f8:200:90c3::2]:8333 -[2a01:4f8:201:148d::2]:8333 -[2a01:4f8:201:2cc::2]:8333 -[2a01:4f8:201:3e3::2]:8333 -[2a01:4f8:201:53cc::2]:8333 -[2a01:4f8:201:6011::4]:8333 -[2a01:4f8:202:3030::2]:8333 -[2a01:4f8:202:31e3::2]:8333 -[2a01:4f8:202:32c6::2]:8333 -[2a01:4f8:202:6035::2]:8333 -[2a01:4f8:210:5488::2]:8333 -[2a01:4f8:211:1e17::2]:8333 -[2a01:4f8:211:1ec5::2]:8333 -[2a01:4f8:212:1826::2]:8333 -[2a01:4f8:221:f59::2]:8333 -[2a01:4f8:c0c:1026::2]:8333 -[2a01:4f8:c0c:1028::2]:8333 -[2a01:4f8:c0c:1029::2]:8333 -[2a01:4f8:c0c:105f::2]:8333 -[2a01:4f8:c0c:1064::2]:8333 -[2a01:4f8:c0c:106b::2]:8333 -[2a01:4f8:c0c:106d::2]:8333 -[2a01:4f8:c0c:1070::2]:8333 -[2a01:4f8:c0c:1105::2]:8333 -[2a01:4f8:c0c:1106::2]:8333 -[2a01:4f8:c0c:1134::2]:8333 -[2a01:4f8:c0c:1135::2]:8333 -[2a01:4f8:c0c:113c::2]:8333 -[2a01:4f8:c0c:115c::2]:8333 -[2a01:4f8:c0c:115e::2]:8333 -[2a01:4f8:c0c:1170::2]:8333 -[2a01:4f8:c0c:1172::2]:8333 -[2a01:4f8:c0c:117b::2]:8333 -[2a01:4f8:c0c:117c::2]:8333 -[2a01:4f8:c0c:1180::2]:8333 -[2a01:4f8:c0c:1181::2]:8333 -[2a01:4f8:c0c:1185::2]:8333 -[2a01:4f8:c0c:1186::2]:8333 -[2a01:4f8:c0c:1187::2]:8333 -[2a01:4f8:c0c:1188::2]:8333 -[2a01:4f8:c0c:1189::2]:8333 -[2a01:4f8:c0c:121::2]:8333 -[2a01:4f8:c0c:122::2]:8333 -[2a01:4f8:c0c:15a8::2]:8333 -[2a01:4f8:c0c:1da4::2]:8333 -[2a01:4f8:c0c:1ff7::2]:8333 -[2a01:4f8:c0c:2262::2]:8333 -[2a01:4f8:c0c:73d::2]:8333 -[2a01:4f8:c0c:790::2]:8333 -[2a01:4f8:c0c:7a8::2]:8333 -[2a01:4f8:c0c:7a9::2]:8333 -[2a01:4f8:c0c:7e9::2]:8333 -[2a01:4f8:c0c:816::2]:8333 -[2a01:4f8:c0c:817::2]:8333 -[2a01:4f8:c0c:818::2]:8333 -[2a01:4f8:c0c:820::2]:8333 -[2a01:4f8:c0c:821::2]:8333 -[2a01:4f8:c0c:822::2]:8333 -[2a01:4f8:c0c:896::2]:8333 -[2a01:4f8:c0c:8c6::2]:8333 -[2a01:4f8:c0c:8c9::2]:8333 -[2a01:4f8:c0c:8d1::2]:8333 -[2a01:4f8:c0c:8d2::2]:8333 -[2a01:4f8:c0c:8d9::2]:8333 -[2a01:4f8:c0c:8da::2]:8333 -[2a01:4f8:c0c:8dc::2]:8333 -[2a01:4f8:c0c:8f1::2]:8333 -[2a01:4f8:c0c:91e::2]:8333 -[2a01:4f8:c0c:927::2]:8333 -[2a01:4f8:c0c:939::2]:8333 -[2a01:4f8:c0c:944::2]:8333 -[2a01:4f8:c0c:951::2]:8333 -[2a01:4f8:c0c:967::2]:8333 -[2a01:4f8:c0c:96f::2]:8333 -[2a01:4f8:c0c:97d::2]:8333 -[2a01:4f8:c0c:982::2]:8333 -[2a01:4f8:c0c:9fc::2]:8333 -[2a01:4f8:c0c:b35::2]:8333 -[2a01:4f8:c0c:b4c::2]:8333 -[2a01:4f8:c0c:bfe::2]:8333 -[2a01:4f8:c0c:c08::2]:8333 -[2a01:4f8:c0c:c13::2]:8333 -[2a01:4f8:c0c:c14::2]:8333 -[2a01:4f8:c0c:c16::2]:8333 -[2a01:4f8:c0c:c19::2]:8333 -[2a01:4f8:c0c:c32::2]:8333 -[2a01:4f8:c0c:c36::2]:8333 -[2a01:4f8:c0c:c39::2]:8333 -[2a01:4f8:c0c:c58::2]:8333 -[2a01:4f8:c0c:c5e::2]:8333 -[2a01:4f8:c0c:c70::2]:8333 -[2a01:4f8:c0c:c72::2]:8333 -[2a01:4f8:c0c:c79::2]:8333 -[2a01:4f8:c0c:cb1::2]:8333 -[2a01:4f8:c0c:cf5::2]:8333 -[2a01:4f8:c0c:cff::2]:8333 -[2a01:4f8:c0c:d0e::2]:8333 -[2a01:4f8:c0c:d1b::2]:8333 -[2a01:4f8:c0c:d67::2]:8333 -[2a01:4f8:c0c:d68::2]:8333 -[2a01:4f8:c0c:d81::2]:8333 -[2a01:4f8:c0c:e2d::2]:8333 -[2a01:4f8:c0c:e30::2]:8333 -[2a01:4f8:c0c:e4f::2]:8333 -[2a01:4f8:c0c:e5b::2]:8333 -[2a01:4f8:c0c:e88::2]:8333 -[2a01:4f8:c0c:f69::2]:8333 -[2a01:4f8:c0c:f76::2]:8333 -[2a01:4f8:c0c:f77::2]:8333 -[2a01:4f8:c0c:f78::2]:8333 -[2a01:4f8:c0c:f89::2]:8333 -[2a01:4f8:c0c:f8a::2]:8333 -[2a01:4f8:c0c:fd6::2]:8333 -[2a01:4f8:c0c:fea::2]:8333 -[2a01:4f8:c17:24ee::2]:8333 -[2a01:4f8:c17:2c16::2]:8333 -[2a01:4f8:c17:330f::2]:8333 -[2a01:4f8:c17:34f0::2]:8333 -[2a01:4f8:c17:3986::2]:8333 -[2a01:4f8:c17:3b02::2]:8333 -[2a01:4f8:c17:3d85::2]:8333 -[2a01:4f8:c17:4271::2]:8333 -[2a01:4f8:c17:5dc0::2]:8333 -[2a01:4f8:c17:63a0::2]:8333 -[2a01:4f8:c17:67f8::2]:8333 -[2a01:4f8:c17:710b::2]:8333 -[2a01:4f8:c17:e00::2]:8333 -[2a01:680:10:10::1]:8333 -[2a01:6f0:ffff:120::8dcb]:8333 -[2a01:79d:b7dd:ffb4:5d86:70b8:fc7f:f253]:8333 -[2a01:7a0:2:1374::4]:8333 -[2a01:7a0:2:1374::5]:8333 -[2a01:7a0:2:137c::3]:8333 -[2a01:7c8:aaaa:373:5054:ff:feb3:2947]:8333 -[2a01:7c8:aaaa:3a0:5054:ff:fe8c:974c]:8333 -[2a01:7c8:aab0:4b7:910d:625e:a13e:c342]:8333 -[2a01:7c8:aab5:3e6:5054:ff:fed7:4e54]:8333 -[2a01:7c8:aab5:41e:5054:ff:fe38:f4fb]:8333 -[2a01:7c8:aaba:343::8333]:8333 -[2a01:7c8:aabc:18c:5054:ff:fefd:3b49]:8333 -[2a01:7c8:aabd:3d5:5054:ff:fe95:f586]:8333 -[2a01:7e00::f03c:91ff:fe50:94b8]:8333 -[2a01:8e01:b943:3a63:d250:99ff:fe1f:4fb2]:8333 -[2a01:b2e0:2::40]:8333 -[2a01:d0:0:1c::245]:8333 -[2a01:d0:8fc3::2]:8333 -[2a01:e34:ec29:e8d0:25c7:c1ce:b7a3:d238]:8333 -[2a01:e34:ec4a:c2d0:1cf3:40d2:a79f:3901]:8333 -[2a01:e34:eed7:6670:ec1b:bf7c:b012:6069]:8333 -[2a01:e35:2433:e320:9c8e:6ff0:990f:f06e]:8333 -[2a01:e35:2ee5:610:21f:d0ff:fe4e:7460]:8333 -[2a02:1205:5051:a640:d6ae:52ff:fea3:ac]:8333 -[2a02:120b:2c2a:5ec0:10dd:31ff:fe42:5079]:8333 -[2a02:168:6273::614]:8333 -[2a02:180:6:1::18]:8333 -[2a02:180:6:1::ed]:8333 -[2a02:1811:b707:116:8c1f:c5be:bf3a:54df]:8333 -[2a02:20c8:1422:1::a3]:8333 -[2a02:2168:d05:2c00:216:3eff:fef7:a099]:8333 -[2a02:27f8:2012:0:e9f7:268f:c441:6129]:8333 -[2a02:2808:5401:0:225:90ff:fe4e:ee42]:8333 -[2a02:390:9000:0:218:7dff:fe10:be33]:8333 -[2a02:7aa0:1201::bd4e:1219]:8333 -[2a02:7aa0:1619::590:eba2]:8333 -[2a02:7aa0:1619::a7a2:7e86]:8333 -[2a02:c200:1:10:2:5:800:1]:8333 -[2a02:c205:2002:2550::17]:8333 -[2a02:c205:2008:272::1]:8333 -[2a02:c205:2010:5484::1]:8333 -[2a02:c205:3001:6710::1]:8333 -[2a02:c205:3001:7714::2]:8333 -[2a02:c205:3002:888::1]:8333 -[2a02:c207:2002:9013::1]:8333 -[2a02:c207:2008:3392::1]:8333 -[2a02:c207:2008:8337::1]:8333 -[2a02:c207:2009:213::1]:8333 -[2a02:c207:2010:7751::1]:8333 -[2a02:c207:2010:7986::1]:8333 -[2a02:c207:2011:7829::1]:8333 -[2a02:c207:2011:8299::1]:8333 -[2a02:c207:2012:2133::1]:8333 -[2a02:c207:2012:263::1]:8333 -[2a02:c207:2012:2682::1]:8333 -[2a02:c207:2012:3635::1]:8333 -[2a02:c207:2012:4826::1]:8333 -[2a02:c207:2012:5668::1]:8333 -[2a02:c207:3001:5824::1]:8333 -[2a02:c207:3001:7776::1]:8333 -[2a02:c207:3002:621::1]:8333 -[2a02:ce80:0:20::1]:8333 -[2a03:2260:11e:301::8]:8333 -[2a03:2260:11e:302::3]:8333 -[2a03:4000:2:496::8]:8333 -[2a03:4000:6:12e7::1]:8333 -[2a03:4000:6:416c::53]:8333 -[2a03:b0c0:3:d0::1219:6001]:8333 -[2a03:b0c0:3:d0::1b99:c001]:8333 -[2a03:b0c0:3:d0::1b99:e001]:8333 -[2a03:b0c0:3:d0::1b9a:3001]:8333 -[2a03:b0c0:3:d0::23f7:1001]:8333 -[2a03:b0c0:3:d0::23f7:2001]:8333 -[2a03:b0c0:3:d0::23f7:4001]:8333 -[2a03:b0c0:3:d0::23f7:5001]:8333 -[2a03:b0c0:3:d0::23f7:7001]:8333 -[2a03:b0c0:3:d0::23f7:9001]:8333 -[2a03:b0c0:3:d0::23fb:1001]:8333 -[2a03:b0c0:3:d0::23fb:2001]:8333 -[2a03:b0c0:3:d0::23fb:3001]:8333 -[2a03:b0c0:3:d0::23fb:5001]:8333 -[2a03:b0c0:3:d0::23fb:6001]:8333 -[2a03:b0c0:3:d0::23fb:8001]:8333 -[2a03:b0c0:3:d0::23ff:b001]:8333 -[2a03:b0c0:3:d0::2400:1]:8333 -[2a03:b0c0:3:d0::2400:3001]:8333 -[2a03:b0c0:3:d0::2400:4001]:8333 -[2a03:b0c0:3:d0::2400:e001]:8333 -[2a03:b0c0:3:d0::2400:f001]:8333 -[2a03:b0c0:3:d0::2401:e001]:8333 -[2a03:b0c0:3:d0::2402:1]:8333 -[2a03:b0c0:3:d0::2402:2001]:8333 -[2a03:b0c0:3:d0::2402:8001]:8333 -[2a03:b0c0:3:d0::2402:9001]:8333 -[2a03:b0c0:3:d0::2402:b001]:8333 -[2a03:b0c0:3:d0::2402:d001]:8333 -[2a03:b0c0:3:d0::2402:e001]:8333 -[2a03:b0c0:3:d0::2403:1001]:8333 -[2a03:b0c0:3:d0::2403:2001]:8333 -[2a03:b0c0:3:d0::2403:3001]:8333 -[2a03:b0c0:3:d0::2403:4001]:8333 -[2a03:b0c0:3:d0::2403:6001]:8333 -[2a03:b0c0:3:d0::2403:a001]:8333 -[2a03:b0c0:3:d0::2403:b001]:8333 -[2a03:b0c0:3:d0::2403:e001]:8333 -[2a03:b0c0:3:d0::2403:f001]:8333 -[2a03:b0c0:3:d0::2404:1]:8333 -[2a03:b0c0:3:d0::2404:3001]:8333 -[2a03:b0c0:3:d0::2404:4001]:8333 -[2a03:b0c0:3:d0::2404:6001]:8333 -[2a03:b0c0:3:d0::2404:8001]:8333 -[2a03:b0c0:3:d0::2404:9001]:8333 -[2a03:b0c0:3:d0::2404:b001]:8333 -[2a03:b0c0:3:d0::2405:2001]:8333 -[2a03:b0c0:3:d0::2405:3001]:8333 -[2a03:b0c0:3:d0::2405:8001]:8333 -[2a03:b0c0:3:d0::2405:9001]:8333 -[2a03:b0c0:3:d0::2405:a001]:8333 -[2a03:b0c0:3:d0::44b8:9001]:8333 -[2a03:b0c0:3:d0::44b8:e001]:8333 -[2a03:b0c0:3:d0::44b8:f001]:8333 -[2a03:b0c0:3:d0::44b9:1]:8333 -[2a03:b0c0:3:d0::44b9:1001]:8333 -[2a03:b0c0:3:d0::44b9:2001]:8333 -[2a03:b0c0:3:d0::44b9:4001]:8333 -[2a04:2180:0:2::94]:8333 -[2a04:3542:1000:910:8492:b8ff:fe91:711d]:8333 -[2a04:52c0:101:122::ba8e]:8333 -[2a05:3580:d400:140d:da6e:826e:e771:4100]:8333 -[2a06:9fc0:2a06:9fc0:2a06:9fc1:67c:e706]:8333 -226eupdnaouu4h2v.onion:8333 -2frgxpe5mheghyom.onion:8333 -3ihjnsvwc3x6dp2o.onion:8333 -3w77hrilg6q64opl.onion:8333 -4ls4o6iszcd7mkfw.onion:8333 -4p3abjxqppzxi7qi.onion:8333 -546esc6botbjfbxb.onion:8333 -5msftytzlsskr4ut.onion:8333 -5ty6rxpgrkmdnk4a.onion:8333 -akmqyuidrf56ip26.onion:8333 -alhlegtjkdmbqsvt.onion:8333 -bafk5ioatlgt7dgl.onion:8333 -bup5n5e3kurvjzf3.onion:8333 -cjygd7pu5lqkky5j.onion:8333 -cyvpgt25274i5b7c.onion:8333 -dekj4wacywpqsad3.onion:8333 -dqpxwlpnv3z3hznl.onion:8333 -drarzpycbtxwbcld.onion:8333 -drp4pvejybx2ejdr.onion:8333 -dxkmtmwiq7ddtgul.onion:8333 -e6j57zkyibu2smad.onion:8333 -ejcqevujcqltqn7d.onion:8333 -eqgbt2ghfvsshbvo.onion:8333 -fgizgkdnndilo6ka.onion:8333 -fqxup4oev33eeidg.onion:8333 -gb5ypqt63du3wfhn.onion:8333 -ggdy2pb2avlbtjwq.onion:8333 -hahhloezyfqh3hci.onion:8333 -ihdv6bzz2gx72fs7.onion:8333 -in7r5ieo7ogkxbne.onion:8333 -kvd44sw7skb5folw.onion:8333 -mn744hbioayn3ojs.onion:8333 -ms4ntrrisfxzpvmy.onion:8333 -n5lqwpjabqg62ihx.onion:8333 -o4sl5na6jeqgi3l6.onion:8333 -omjv24nbck4k5ud6.onion:8333 -po3j2hfkmf7sh36o.onion:8333 -psco6bxjewljrczx.onion:8333 -qi5yr6lvlckzffor.onion:8333 -qlv6py6hdtzipntn.onion:8333 -qynmpgdbp23xyfnj.onion:8333 -rhtawcs7xak4gi3t.onion:8333 -rjacws757ai66lre.onion:8333 -rjlnp3hwvrsmap6e.onion:8333 -rkdvqcrtfv6yt4oy.onion:8333 -rlafimkctvz63llg.onion:8333 -rlj4ppok4dnsdu5n.onion:8333 -seoskudzk6vn6mqz.onion:8333 -tayqi57tfiy7x3vk.onion:8333 -tchop676j6yppwwm.onion:8333 -trrtyp3sirmwttyu.onion:8333 -tx4zd7d5exonnblh.onion:8333 -u4ecb7txxi6l3gix.onion:8333 -umcxcmfycvejw264.onion:8333 -v7xqd42ocemalurd.onion:8333 -vb267mt3lnwfdmdb.onion:8333 -vev3n5fxfrtqj6e5.onion:8333 -visevrizz3quyagj.onion:8333 -vpg6p5e5ln33dqtp.onion:8333 -vr2ruasinafoy3fl.onion:8333 -x6pthvd5x6abyfo7.onion:8333 -xbwbzrspvav7u5ie.onion:8333 -xfcevnql2chnawko.onion:8333 -ycivnom44dmxx4ob.onion:8333 -yzdvlv5daitafekn.onion:8333 +5.196.77.193:9333 +31.214.157.83:9333 +37.157.183.16:9333 +45.55.176.26:9333 +46.101.6.204:9333 +46.105.55.208:9333 +47.189.129.218:9333 +62.210.206.140:9333 +62.210.254.201:9333 +63.141.224.98:9333 +66.178.182.35:9333 +68.60.159.136:9333 +70.77.123.81:9333 +71.88.54.22:9333 +71.120.188.82:9333 +73.40.6.11:9333 +77.77.46.250:9333 +80.77.37.36:9333 +80.108.143.19:9333 +80.241.212.207:9333 +81.27.96.92:9333 +81.138.88.100:9333 +82.118.242.3:9333 +82.192.64.136:9333 +85.21.144.226:9333 +85.234.150.199:9333 +88.198.230.142:9333 +89.69.140.68:9333 +89.152.237.246:9333 +91.109.112.90:9333 +91.109.112.94:9333 +91.152.122.132:9333 +91.240.141.175:9333 +93.190.140.198:9333 +97.85.42.188:9333 +104.172.24.79:9333 +104.243.38.34:9333 +107.150.45.210:9333 +107.191.39.237:9333 +108.56.194.156:9333 +109.195.179.63:9333 +134.213.222.108:9333 +136.243.153.156:9333 +158.129.212.236:9333 +162.13.4.69:9333 +172.245.161.141:9333 +173.208.194.94:9333 +173.209.44.34:9333 +178.217.186.125:9333 +184.164.147.82:21333 +185.8.165.150:10333 +185.47.62.72:9333 +185.50.213.124:9333 +185.66.250.44:9333 +185.87.184.29:9333 +188.0.182.10:9335 +188.155.136.21:9333 +192.3.165.30:9333 +198.15.127.242:10333 +217.23.14.155:9333 +217.28.96.180:9333 diff --git a/contrib/seeds/nodes_test.txt b/contrib/seeds/nodes_test.txt index 98365ee505ce..58db6a5d4cac 100644 --- a/contrib/seeds/nodes_test.txt +++ b/contrib/seeds/nodes_test.txt @@ -1,11 +1,5 @@ # List of fixed seed nodes for testnet -# Onion nodes -thfsmmn2jbitcoin.onion -it2pj4f7657g3rhi.onion -nkf5e6b7pl4jfd4a.onion -4zhkir2ofl7orfom.onion -t6xj6wilh4ytvcs7.onion -i6y6ivorwakd7nw3.onion -ubqj4rsu3nqtxmtp.onion - +104.236.211.206 +66.178.182.35 +173.209.44.34 \ No newline at end of file diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 872626f16089..dcd33fbe4c49 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -48,8 +48,8 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi */ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { - const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; - const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + const char* pszTimestamp = "NY Times 05/Oct/2011 Steve Jobs, Apple’s Visionary, Dies at 56"; + const CScript genesisOutputScript = CScript() << ParseHex("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9") << OP_CHECKSIG; return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward); } @@ -74,66 +74,66 @@ class CMainParams : public CChainParams { public: CMainParams() { strNetworkID = "main"; - consensus.nSubsidyHalvingInterval = 210000; - consensus.BIP34Height = 227931; - consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); - consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 - consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 - consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks - consensus.nPowTargetSpacing = 10 * 60; + consensus.nSubsidyHalvingInterval = 840000; + consensus.BIP34Height = 710000; + consensus.BIP34Hash = uint256S("fa09d204a83a768ed5a7c8d441fa62f2043abf420cff1226c7b4329aeb9d51cf"); + consensus.BIP65Height = 918684; // bab3041e8977e0dc3eeff63fe707b92bde1dd449d8efafb248c27c8264cc311a + consensus.BIP66Height = 811879; // 7aceee012833fa8952f8835d8b1b3ae233cd6ab08fdb27a771d2bd7bdc491894 + consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days + consensus.nPowTargetSpacing = 2.5 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; - consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 - consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.nRuleChangeActivationThreshold = 6048; // 75% of 8064 + consensus.nMinerConfirmationWindow = 8064; // nPowTargetTimespan / nPowTargetSpacing * 4 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 // Deployment of BIP68, BIP112, and BIP113. consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1485561600; // January 28, 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517356801; // January 31st, 2018 // Deployment of SegWit (BIP141, BIP143, and BIP147) consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1; - consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016. - consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017. + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1485561600; // January 28, 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1517356801; // January 31st, 2018 // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000723d3581fe1bd55373540a"); + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000006805c7318ce2736c0"); // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x0000000000000000003b9ce759c2a087d52abc4266f8f4ebd6d768b89defa50a"); //477890 + consensus.defaultAssumeValid = uint256S("0x1673fa904a93848eca83d5ca82c7af974511a7e640e22edc2976420744f2e56a"); //1155631 /** * 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 * a large 32-bit integer with any alignment. */ - pchMessageStart[0] = 0xf9; - pchMessageStart[1] = 0xbe; - pchMessageStart[2] = 0xb4; - pchMessageStart[3] = 0xd9; - nDefaultPort = 8333; + pchMessageStart[0] = 0xfb; + pchMessageStart[1] = 0xc0; + pchMessageStart[2] = 0xb6; + pchMessageStart[3] = 0xdb; + nDefaultPort = 9333; nPruneAfterHeight = 100000; - genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(1317972665, 2084524493, 0x1e0ffff0, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256S("0x12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2")); + assert(genesis.hashMerkleRoot == uint256S("0x97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9")); // Note that of those with the service bits flag, most only support a subset of possible options - vSeeds.emplace_back("seed.bitcoin.sipa.be", true); // Pieter Wuille, only supports x1, x5, x9, and xd - vSeeds.emplace_back("dnsseed.bluematt.me", true); // Matt Corallo, only supports x9 - vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org", false); // Luke Dashjr - vSeeds.emplace_back("seed.bitcoinstats.com", true); // Christian Decker, supports x1 - xf - vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch", true); // Jonas Schnelli, only supports x1, x5, x9, and xd - vSeeds.emplace_back("seed.btc.petertodd.org", true); // Peter Todd, only supports x1, x5, x9, and xd - - base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,0); + vSeeds.emplace_back("seed-a.litecoin.loshan.co.uk", true); + vSeeds.emplace_back("dnsseed.thrasher.io", true); + vSeeds.emplace_back("dnsseed.litecointools.com", true); + vSeeds.emplace_back("dnsseed.litecoinpool.org", true); + vSeeds.emplace_back("dnsseed.koin-project.com", false); + + base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,48); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,5); - base58Prefixes[SECRET_KEY] = std::vector(1,128); + base58Prefixes[SCRIPT_ADDRESS2] = std::vector(1,50); + base58Prefixes[SECRET_KEY] = std::vector(1,176); base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4}; @@ -145,28 +145,31 @@ class CMainParams : public CChainParams { checkpointData = (CCheckpointData) { { - { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")}, - { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")}, - { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")}, - {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")}, - {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")}, - {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")}, - {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")}, - {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")}, - {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")}, - {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")}, - {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")}, - {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")}, - {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")}, + { 1500, uint256S("0x841a2965955dd288cfa707a755d05a54e45f8bd476835ec9af4402a2b59a2967")}, + { 4032, uint256S("0x9ce90e427198fc0ef05e5905ce3503725b80e26afd35a987965fd7e3d9cf0846")}, + { 8064, uint256S("0xeb984353fc5190f210651f150c40b8a4bab9eeeff0b729fcb3987da694430d70")}, + { 16128, uint256S("0x602edf1859b7f9a6af809f1d9b0e6cb66fdc1d4d9dcd7a4bec03e12a1ccd153d")}, + { 23420, uint256S("0xd80fdf9ca81afd0bd2b2a90ac3a9fe547da58f2530ec874e978fce0b5101b507")}, + { 50000, uint256S("0x69dc37eb029b68f075a5012dcc0419c127672adb4f3a32882b2b3e71d07a20a6")}, + { 80000, uint256S("0x4fcb7c02f676a300503f49c764a89955a8f920b46a8cbecb4867182ecdb2e90a")}, + {120000, uint256S("0xbd9d26924f05f6daa7f0155f32828ec89e8e29cee9e7121b026a7a3552ac6131")}, + {161500, uint256S("0xdbe89880474f4bb4f75c227c77ba1cdc024991123b28b8418dbbf7798471ff43")}, + {179620, uint256S("0x2ad9c65c990ac00426d18e446e0fd7be2ffa69e9a7dcb28358a50b2b78b9f709")}, + {240000, uint256S("0x7140d1c4b4c2157ca217ee7636f24c9c73db39c4590c4e6eab2e3ea1555088aa")}, + {383640, uint256S("0x2b6809f094a9215bafc65eb3f110a35127a34be94b7d0590a096c3f126c6f364")}, + {409004, uint256S("0x487518d663d9f1fa08611d9395ad74d982b667fbdc0e77e9cf39b4f1355908a3")}, + {456000, uint256S("0xbf34f71cc6366cd487930d06be22f897e34ca6a40501ac7d401be32456372004")}, + {638902, uint256S("0x15238656e8ec63d28de29a8c75fcf3a5819afc953dcd9cc45cecc53baec74f38")}, + {721000, uint256S("0x198a7b4de1df9478e2463bd99d75b714eab235a2e63e741641dc8a759a9840e5")}, } }; chainTxData = ChainTxData{ - // Data as of block 000000000000000000d97e53664d17967bd4ee50b23abb92e54a34eb222d15ae (height 478913). - 1501801925, // * UNIX timestamp of last known number of transactions - 243756039, // * total number of transactions between genesis and that timestamp - // (the tx=... number in the SetBestChain debug.log lines) - 3.1 // * estimated number of transactions per second after that timestamp + // Data as of block b44bc5ae41d1be67227ba9ad875d7268aa86c965b1d64b47c35be6e8d5c352f4 (height 1155626). + 1487715936, // * UNIX timestamp of last known number of transactions + 9243806, // * total number of transactions between genesis and that timestamp + // (the tx=... number in the SetBestChain debug.log lines) + 0.06 // * estimated number of transactions per second after that timestamp }; } }; @@ -178,14 +181,14 @@ class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = "test"; - consensus.nSubsidyHalvingInterval = 210000; - consensus.BIP34Height = 21111; - consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); - consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 - consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 - consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks - consensus.nPowTargetSpacing = 10 * 60; + consensus.nSubsidyHalvingInterval = 840000; + consensus.BIP34Height = 76; + consensus.BIP34Hash = uint256S("8075c771ed8b495ffd943980a95f702ab34fce3c8c54e379548bda33cc8c0573"); + consensus.BIP65Height = 76; // 8075c771ed8b495ffd943980a95f702ab34fce3c8c54e379548bda33cc8c0573 + consensus.BIP66Height = 76; // 8075c771ed8b495ffd943980a95f702ab34fce3c8c54e379548bda33cc8c0573 + consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days + consensus.nPowTargetSpacing = 2.5 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains @@ -196,41 +199,42 @@ class CTestNetParams : public CChainParams { // Deployment of BIP68, BIP112, and BIP113. consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1483228800; // January 1, 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517356801; // January 31st, 2018 // Deployment of SegWit (BIP141, BIP143, and BIP147) consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1; - consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016 - consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1483228800; // January 1, 2017 + consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1517356801; // January 31st, 2018 // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000002830dab7f76dbb7d63"); + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000054cb9e7a0"); // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1"); //1135275 + consensus.defaultAssumeValid = uint256S("0x43a16a626ef2ffdbe928f2bc26dcd5475c6a1a04f9542dfc6a0a88e5fcf9bd4c"); //8711 - pchMessageStart[0] = 0x0b; - pchMessageStart[1] = 0x11; - pchMessageStart[2] = 0x09; - pchMessageStart[3] = 0x07; - nDefaultPort = 18333; + pchMessageStart[0] = 0xfd; + pchMessageStart[1] = 0xd2; + pchMessageStart[2] = 0xc8; + pchMessageStart[3] = 0xf1; + nDefaultPort = 19335; nPruneAfterHeight = 1000; - genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(1486949366, 293345, 0x1e0ffff0, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256S("0x4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0")); + assert(genesis.hashMerkleRoot == uint256S("0x97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9")); vFixedSeeds.clear(); vSeeds.clear(); // nodes with support for servicebits filtering should be at the top - vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true); - vSeeds.emplace_back("seed.tbtc.petertodd.org", true); - vSeeds.emplace_back("testnet-seed.bluematt.me", false); + vSeeds.emplace_back("testnet-seed.litecointools.com", true); + vSeeds.emplace_back("seed-b.litecoin.loshan.co.uk", true); + vSeeds.emplace_back("dnsseed-testnet.thrasher.io", true); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,111); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,196); + base58Prefixes[SCRIPT_ADDRESS2] = std::vector(1,58); base58Prefixes[SECRET_KEY] = std::vector(1,239); base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; @@ -241,18 +245,17 @@ class CTestNetParams : public CChainParams { fRequireStandard = false; fMineBlocksOnDemand = false; - checkpointData = (CCheckpointData) { { - {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")}, + {2056, uint256S("17748a31ba97afdc9a4f86837a39d287e3e7c7290a08a1d816c5969c78a83289")}, } }; chainTxData = ChainTxData{ - // Data as of block 00000000000001c200b9790dc637d3bb141fe77d155b966ed775b17e109f7c6c (height 1156179) - 1501802953, - 14706531, - 0.15 + // Data as of block f2dc531da6be01f53774f970aaaca200c7a8317ee9fd398ee733b40f14e265d1 (height 8702) + 1487715270, + 8731, + 0.01 }; } @@ -271,8 +274,8 @@ class CRegTestParams : public CChainParams { consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests) consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests) consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks - consensus.nPowTargetSpacing = 10 * 60; + consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // two weeks + consensus.nPowTargetSpacing = 2.5 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains @@ -297,24 +300,24 @@ class CRegTestParams : public CChainParams { pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; - nDefaultPort = 18444; + nDefaultPort = 19444; nPruneAfterHeight = 1000; - genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(1296688602, 0, 0x207fffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256S("0x530827f38f93b43ed12af0b3ad25a288dc02ed74d6d7857862df51fc56c416f9")); + assert(genesis.hashMerkleRoot == uint256S("0x97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9")); vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds. fDefaultConsistencyChecks = true; fRequireStandard = false; - fMineBlocksOnDemand = true; + fMineBlocksOnDemand = true; checkpointData = (CCheckpointData) { { - {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")}, + {0, uint256S("530827f38f93b43ed12af0b3ad25a288dc02ed74d6d7857862df51fc56c416f9")}, } }; @@ -326,6 +329,7 @@ class CRegTestParams : public CChainParams { base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,111); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,196); + base58Prefixes[SCRIPT_ADDRESS2] = std::vector(1,58); base58Prefixes[SECRET_KEY] = std::vector(1,239); base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; diff --git a/src/chainparams.h b/src/chainparams.h index f55ae4cf7f06..867dc743fcd4 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -50,6 +50,7 @@ class CChainParams enum Base58Type { PUBKEY_ADDRESS, SCRIPT_ADDRESS, + SCRIPT_ADDRESS2, SECRET_KEY, EXT_PUBLIC_KEY, EXT_SECRET_KEY, diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 224c9eb0ea31..16a4da65f7ba 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -32,7 +32,7 @@ class CBaseMainParams : public CBaseChainParams public: CBaseMainParams() { - nRPCPort = 8332; + nRPCPort = 9332; } }; @@ -44,8 +44,8 @@ class CBaseTestNetParams : public CBaseChainParams public: CBaseTestNetParams() { - nRPCPort = 18332; - strDataDir = "testnet3"; + nRPCPort = 19332; + strDataDir = "testnet4"; } }; @@ -57,7 +57,7 @@ class CBaseRegTestParams : public CBaseChainParams public: CBaseRegTestParams() { - nRPCPort = 18332; + nRPCPort = 19332; strDataDir = "regtest"; } }; diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 2c99ca8ab09c..9b20b95f497c 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -1,1472 +1,79 @@ #ifndef BITCOIN_CHAINPARAMSSEEDS_H #define BITCOIN_CHAINPARAMSSEEDS_H /** - * List of fixed seed nodes for the bitcoin network + * List of fixed seed nodes for the litecoin network * AUTOGENERATED by contrib/seeds/generate-seeds.py * * Each line contains a 16-byte IPv6 address and a port. * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly. */ static SeedSpec6 pnSeed6_main[] = { - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0xe4,0x46,0xc6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x04,0x0f,0xb4,0x1d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x04,0x0f,0xb4,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x02,0x43,0x6e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x27,0xe0,0x67}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x2b,0x7c,0x9a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbd,0xa5,0x66}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe2,0x95,0x91}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe4,0x07,0x92}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe4,0x40,0x47}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xf9,0x98,0x65}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xfe,0x7c,0x37}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xff,0x40,0xe7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xff,0x5a,0xea}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0e,0xc0,0x08,0x1b}, 21301}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x3e,0x03,0x56}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x55,0x23,0x50}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x1c,0x80,0x41}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x6c,0x53,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe9,0x02,0xee}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x1b,0x41,0xa8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x38,0xf1,0xdb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x40,0x4b,0x84}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x49,0x46,0x1a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x79,0x9a,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xcb,0x60,0x48}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe1,0x22,0x3e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe3,0x45,0x92}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe8,0x88,0x77}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x10,0x7b,0xeb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x13,0xcd,0x35}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x84,0x88,0x23}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xb8,0xea,0x55}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xd3,0x66,0xa1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x30,0x40,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x61,0x8d,0x74}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa0,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa4,0x10}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x86,0xe2,0xb5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x93,0x6e,0x2b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xc2,0x0a,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xf7,0x16,0x35}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x1b,0x41,0x9e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x85,0x8d,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2b,0xf8,0xa0,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x20,0x82,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x20,0xc1,0x9d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x2e,0xa1,0x79}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x38,0x61,0x3f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x74,0xb2,0x4f}, 8188}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x10,0xf0,0x62}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x14,0xf6,0x64}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x15,0x61,0x87}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x3b,0x0a,0xed}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x3b,0x0d,0x3b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x94,0x10,0xd2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa0,0x60}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xbc,0x2c,0x14}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe5,0xee,0xbb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe7,0x10,0x95}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x58,0x23,0xb5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x58,0x64,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xb8,0x81,0x5e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xc7,0x44,0xcc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x1e,0x26,0xcb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x3f,0xa2,0xf2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x61,0x85,0xd0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x72,0xe3,0xe0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0x0f,0x00,0x11}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0xae,0x45,0xef}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x07,0x87,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x0e,0x40,0x52}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0xcc,0x69,0x19}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xff,0xa0,0x57}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x2f,0x02,0x14}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x7d,0x83,0x37}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x2b,0x82,0xb2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6a,0x10,0x6f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6b,0xc8,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6d,0x14,0x63}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x85,0xc2,0x02}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x85,0xc2,0x9c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xb0,0x06,0x5e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xb6,0xa9,0xde}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xcd,0x84,0xf5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd8,0xee,0x85}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xe7,0xef,0xd4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x22,0xe7,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0xcb,0x66,0x56}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0xe9,0xf5,0x27}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0xb7,0x4c,0x49}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x60,0xc7,0xa6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc4,0x0c,0x3f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xd7,0x06,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xdd,0xc1,0x37}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x42,0xc1,0xc0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x45,0xeb,0xe6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x6f,0x0a,0xdb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x77,0x8a,0xaf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x84,0xc1,0xde}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xc2,0x2a,0x4c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xeb,0x29,0xcc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x0b,0x61,0x2b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x29,0x03,0xd4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x29,0xab,0x23}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x29,0xab,0x24}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x37,0x40,0xd8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x54,0x2a,0x38}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x30,0x30,0xfa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x70,0x20,0x1d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0xfa,0x4a,0x14}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x5d,0xa1,0xa2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xc6,0x00,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x05,0xa7,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xe0,0x0b,0x67}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x48,0xa0,0xd5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x7a,0xed,0x7c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x56,0x89,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0xa5,0x63,0x90}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x40,0x4a,0xc1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x4c,0xe3,0x88}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xad,0xa1,0x2c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xb2,0x16,0x2c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x2f,0x89,0x1b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x4d,0x2e,0xfa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x5b,0xc1,0x98}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x5f,0xe2,0xc2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x78,0xf6,0xfe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xa3,0x88,0x88}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xcb,0x0d,0x39}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xec,0x25,0xd6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xef,0x25,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xf7,0xb3,0x2c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x22,0x0e,0x34}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x6d,0xa3,0x99}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0xc4,0xac,0x2d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x84,0xe6,0x90}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa0,0x02,0x69}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x52,0x4d,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x64,0xcb,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x93,0x44,0xed}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xed,0xf0,0x66}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x02,0xf6,0x7f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x07,0x56}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x0a,0xee}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x1b,0x60,0x25}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x53,0x60,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xe4,0xc2,0xbb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x2d,0x45,0xd8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x45,0x2c,0xb7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x48,0xc6,0x44}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x5f,0xcc,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0xec,0x7f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0xf2,0x04}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x86,0x42,0x92}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc1,0x6d,0xc7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc5,0xd2,0x41}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc7,0x66,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc8,0xcd,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x6c,0x1b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x80,0x51}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x8b,0x61}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xe8,0xca,0xf6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x3c,0x40,0xfc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x3d,0x08,0xe4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x80,0x29,0x30}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x80,0x6f,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x89,0x29,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x96,0x2b,0x11}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xa9,0x02,0x2b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xae,0xd1,0x57}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xff,0x2b,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x2a,0xc1,0x06}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x34,0x91,0xe7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x34,0xea,0x46}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x55,0x66,0x71}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x5c,0x5c,0xf7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x92,0x23,0x7b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xc6,0xde}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd9,0xa3,0x87}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xf5,0x1b,0xb9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xfb,0xcb,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x15,0x90,0xe2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x19,0xc2,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x19,0xc2,0x1c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x90,0x77,0xde}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xb7,0x8c,0x3e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xe4,0xcb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xea,0xfe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xda,0x96,0x01}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xe4,0xc4,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x0f,0x02,0xeb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x3d,0x06,0xd2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x5c,0x73,0xc2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x78,0x08,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x78,0x25,0xe6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xe9,0xb5,0x92}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xef,0x65,0x66}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x57,0x4e,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x62,0xc6,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x62,0xe1,0xd6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x63,0x3a,0xc2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x96,0xc0,0x11}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xc4,0x88,0x1f}, 17556}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x3a,0xc1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x3a,0xc2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x16,0x60,0x84}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x16,0x68,0x30}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x19,0x50,0x62}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x22,0x63,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x8e,0xc3,0x70}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa3,0xe0,0xbb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa3,0xe0,0xc3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xee,0x4f,0xeb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x2e,0xf0,0xd6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x41,0xe8,0x81}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x47,0x75,0x5a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x95,0x26,0xac}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x9c,0x61,0x91}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0xb1,0x30,0x68}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x6a,0xc2,0x61}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x87,0x00,0xbb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x96,0xbd,0x9b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xb9,0xc6,0xd8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc4,0x0b,0x2d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc5,0x2c,0x85}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe0,0x00,0xe3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe2,0x0a,0x5a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe4,0x2d,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe5,0x4d,0xef}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xee,0x64,0xf9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xf0,0x8d,0xa9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x1b,0x07,0xd1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x36,0x10,0x87}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x59,0x54,0x5d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x64,0x33,0x30}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x64,0x4c,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x68,0xd6,0xeb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x73,0x56,0xf6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x7b,0x50,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xae,0x58,0xd3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xbc,0xe0,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xbe,0x45,0xf2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x4a,0x51,0x5d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x9c,0x23,0x08}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xb0,0xed,0xf1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xb5,0x2c,0x68}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xe3,0x2b,0xab}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x4f,0x66,0xd0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x4f,0x66,0xd1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x9a,0xed,0x18}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xb7,0x30,0x3e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xb7,0x30,0x47}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd5,0xa1,0x02}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd5,0xc9,0x5e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x14,0xe3,0x27}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x1c,0x29,0x5b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x7f,0x82,0x11}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x64,0x24,0x30,0x65}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x00,0x51,0x2a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x00,0x51,0x2b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x0b,0x40,0x2e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x18,0xf4,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x2f,0xd2,0x32}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x4c,0x29,0xa9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x50,0xa8,0x39}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xcb,0x33,0xba}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xe0,0x76,0x4f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xfa,0x04,0x4a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc0,0xaa,0xca}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc4,0x00,0x63}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc7,0xc0,0x55}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdb,0xfb,0x2e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdf,0x6c,0x21}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xed,0x02,0xbd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xf7,0xe6,0x1c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x2d,0xd2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xae,0x22,0x4d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xae,0x22,0x4e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xb4,0x47,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3b,0x0c,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xa8,0x25,0x0d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xaf,0x03,0x12}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xea,0xc1,0x6a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x09,0xad,0x0d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x65,0xdc,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xac,0x68,0x77}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xc3,0xc1,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xce,0xb1,0x15}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe2,0x23,0x1c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xff,0x00,0x6b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x71,0x1d,0xb7,0x8f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x72,0x91,0x61,0x49}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x42,0xcd,0xab}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x43,0xc9,0x28}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0xc2,0xe2,0xa8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x1c,0x46,0x90}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x18,0xa6,0x49}, 9998}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x4c,0xf4,0xc9}, 10022}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x52,0x04,0xe8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0xfe,0xad,0x28}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0xcb,0xa3,0x80}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xab,0x46,0x2d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7d,0x3f,0x39,0x07}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7d,0x80,0x23,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xd0,0xf4,0x7c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xe6,0xd0,0x49}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x72,0x0a,0xe9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x72,0x0a,0xeb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x84,0xef,0x24,0x69}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xd5,0xd6,0xe9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x3d,0xee,0x79}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x3e,0x56,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x90,0x80,0x31}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x30,0x90,0x34}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x74,0xa0,0xb0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x75,0xc1,0x71}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0x13,0x4f,0xd0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0x44,0x40,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0x3b,0x60,0x10}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0xa2,0xa0,0xe8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0x88,0x73,0xe6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0x3b,0xe8,0x6f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0x6f,0x02,0x4a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0xa2,0x80,0x17}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0x6b,0x74,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0xe5,0x16,0x4a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0xe5,0x24,0x47}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x02,0x69,0x3c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x4c,0xe0,0xd6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0xb9,0x13,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x93,0x20,0x1e,0x19}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x93,0xe5,0x0d,0xd2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0x67,0x07,0x77}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x96,0x65,0x72,0xc2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x96,0xe5,0x00,0x8f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0x42,0xcf,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x81,0xd4,0xec}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x81,0xd4,0xfb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa0,0x10,0xce,0x1f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x01,0xe9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x04,0x7d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xdc,0xf6,0xe1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0xac,0xda,0xba}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0xe6,0x46,0x91}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0xeb,0x4a,0x2d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa9,0x2c,0x22,0x58}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaa,0x4b,0xc3,0xa8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x70,0x02,0x43}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x5e,0xa4,0x26}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xb7,0xe8,0x6d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd0,0xb0,0x7a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd4,0xc2,0x72}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xe8,0xe4,0x92}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x7e,0x7c,0x5c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x91,0x6d,0x33}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x18,0xc6,0xcd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x25,0x3e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x63,0xde}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x6a,0x90,0xb7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb1,0x21,0x01,0x28}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xa2,0xd6,0xe1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xa4,0x6d,0x53}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xaa,0x8a,0xca}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xaf,0x88,0x7a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xda,0xd1,0xa2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x02,0x40}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x22,0x90}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xff,0x29,0x15}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xff,0x90,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0xb5,0xd0,0x2a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0xc8,0x80,0x3a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0xeb,0x32,0x0e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0xd7,0x94,0x9a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x40,0x0d,0x2b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x5e,0xa4,0xaa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x98,0x6b,0xfb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0xb6,0xe9,0xce}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x04,0x18,0xc7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x14,0x63,0x31}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x18,0x61,0x0b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x1b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x47}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1a,0xc4,0xf9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1c,0x4c,0xb3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x23,0x8b,0xfa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x29,0x71,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xd5,0x7b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xd5,0x7c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xe8,0x72}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x33,0xc0,0x28}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x35,0x81,0xf4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x47,0xb1,0x64}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x4d,0x81,0xb0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x52,0xc9,0x33}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x79,0xad,0xdf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x8c,0xfc,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x91,0x81,0xb8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x91,0x82,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x9a,0x9c,0x32}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xa2,0x7c,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xaa,0x2a,0x02}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xba,0x95,0xc5,0x60}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x41,0xd4,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x41,0xd5,0x30}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x5d,0xd1,0xc0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x71,0x4f,0x2d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x71,0x54,0x74}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x71,0xa4,0xe7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x7a,0x10,0x99}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0xe0,0x1c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xaf,0xef,0xe3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xd6,0x80,0x12}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xe3,0x40,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xfd,0x02,0x7d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbd,0x2d,0xcb,0xa6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0xb8,0xc6,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x97,0x91,0xfa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xce,0xca,0x06}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xe4,0x65,0x9d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x02,0x4c,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x1b,0xd1,0x64}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x21,0xed,0xbb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x2e,0x53,0x11}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x31,0x2b,0xdb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x18,0xb6,0x1b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x1c,0xce,0xc9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x3f,0x8f,0xc5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x47,0x6d,0x5b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x4f,0x08,0x24}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x87,0x5d,0x26}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xba,0xa0,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x09,0x8c,0x86}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x27,0xce,0x1d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x43,0x24,0x59}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xa9,0x63,0x52}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xd6,0xd6,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xdf,0x47,0x93}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x25,0x76,0x0b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x36,0x71,0x7d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x65,0x0c,0x8b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x8f,0x0c,0x69}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xfb,0x53,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x7f,0xe0,0x32}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x0c,0x8a,0x92}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x74,0x62,0xb9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x7a,0x80,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x1d,0x06,0x30}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x85,0x73,0x73}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x3b,0x11,0xa0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x0f,0x0b,0x04}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x6f,0xf1,0xc3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcd,0xfb,0x55,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xf4,0x46,0x28}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xfe,0x32,0x48}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x4c,0x5d,0x53}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6b,0x61,0xf2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6e,0x49,0x6b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x76,0xeb,0xbe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x49,0x8e,0xe2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x51,0x09,0xdf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x7e,0x6b,0xa6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xb1,0x56,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xfa,0x06,0xbe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0x01,0xdb,0x9b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0xd3,0x6d,0xa5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0xdf,0x03,0x2c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd3,0x15,0x81,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x32,0x62,0xa1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x33,0x8c,0xb7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x38,0x6c,0x51}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x53,0x23,0xad}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x5a,0xb3,0xce}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x5d,0xe2,0x5a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x6e,0xab,0x76}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x05,0x24,0x3a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x05,0xb5,0xcd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x11,0x10,0xfb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x5b,0xcd,0x86}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x5b,0xd3,0x11}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x9b,0x03,0xd8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xa8,0x0d,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xba,0xaa,0x6d}, 8334}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xde,0xd0,0x96}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x20,0xd5,0x70}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x3b,0x04,0xd4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x7e,0xc1,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xc5,0x4f,0x4a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xda,0x93,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xe3,0x27,0x54}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xf5,0xce,0xb5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xf9,0x5c,0xe6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x0c,0xc7,0xcf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x02,0xb1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x05,0x44}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x1c,0xc2,0x02}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x23,0x82,0x2a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x40,0x2f,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x65,0x48,0xf2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x91,0x51,0xe5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xa8,0x8f,0xa9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xa9,0x07,0x6f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xb6,0xc0,0x07}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdb,0x58,0xe8,0xe5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdb,0x71,0xf4,0x34}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0x82,0x80,0x3a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0xf4,0xe1,0xef}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdd,0x8d,0x03,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xde,0xa6,0xb0,0x63}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0xfc,0xad,0x93}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x10,0x25,0x04,0xe5,0xac,0xb0,0x22,0xcd}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x10,0x78,0x18,0xa6,0x5d,0x2c,0x24,0x61}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x10,0xec,0x23,0x6a,0xbd,0x3b,0xf3,0xc0}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x18,0x6d,0x3f,0x17,0xb7,0xad,0x95,0xcf}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x18,0x70,0x02,0x42,0xac,0x03,0xaa,0xf9}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x18,0xa6,0x11,0x02,0x2a,0xbf,0xeb,0x70}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x1c,0xe5,0x24,0x8c,0x4f,0xf5,0x2b,0x1d}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x20,0x0f,0x15,0x6a,0xbc,0x77,0x3a,0xcd}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x24,0x18,0x19,0xd1,0xcd,0xdc,0xb1,0xaf}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x28,0x57,0x3d,0x78,0xaa,0xf8,0xeb,0x28}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x28,0xb2,0x1b,0x84,0x64,0xfb,0x2d,0x6a}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x2c,0x70,0x0d,0x51,0xd0,0x46,0x12,0x09}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x2c,0xac,0x2f,0xcf,0x46,0xbb,0xbe,0x0d}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x30,0x5e,0x20,0xee,0xa9,0x4f,0x6f,0x69}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x30,0xcd,0x08,0x49,0xad,0xfe,0x6e,0x67}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x34,0x5b,0x0f,0x12,0xae,0x1e,0x29,0x48}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x3c,0x40,0x14,0x6e,0x97,0x41,0x5a,0x3a}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x3c,0x9e,0x3c,0x3e,0x9d,0x6e,0x73,0x40}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x04,0x99,0x29,0xa8,0xd0,0x47,0x7e,0xa1}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x00,0x51,0x00,0x24,0x81,0xb2,0x59,0xe3}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x08,0x89,0x2d,0x7c,0xb6,0x1b,0xbf,0x0d}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x0c,0x9f,0x37,0x9c,0xad,0xd2,0xc9,0x38}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x0c,0xd6,0x2e,0xb4,0xb8,0x2b,0xad,0xdb}, 8333}, - {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x0c,0xf0,0x2e,0x3a,0xb2,0x9d,0x62,0x07}, 8333}, - {{0x20,0x01,0x00,0x00,0x53,0xaa,0x06,0x4c,0x14,0x85,0xfb,0xf9,0xa7,0x98,0x1f,0xfe}, 8333}, - {{0x20,0x01,0x00,0x00,0x53,0xaa,0x06,0x4c,0x00,0x59,0x61,0x7f,0xa1,0x0d,0x00,0xe0}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0x20,0x2c,0xd0,0x47,0x50,0xeb,0x12}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0x36,0x1d,0x50,0x38,0x81,0x69,0x30}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0xa4,0x27,0xd8,0x9c,0x0a,0xcf,0xa9}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0xae,0x05,0xa8,0x52,0x4b,0xdc,0xc4}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x18,0x92,0x3e,0x3a,0x3f,0x74,0xaf,0xfa}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x1c,0x95,0x1a,0x60,0xd1,0xf5,0x21,0x5b}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x20,0x0b,0x16,0xef,0xb9,0xcf,0x98,0x60}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x28,0xe4,0xfb,0xff,0x32,0x37,0x09,0x92}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x2c,0xe8,0x1d,0x9e,0xb3,0xbf,0xb5,0x3e}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x30,0x0a,0x2e,0x20,0x47,0x50,0xeb,0x12}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x30,0xa2,0x1a,0xd9,0x53,0x24,0x83,0x6a}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x34,0x09,0x19,0x96,0xbc,0xac,0x24,0x1f}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x34,0x4b,0x2b,0xd4,0xbb,0x3e,0x0e,0x26}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x34,0xb3,0x11,0xdb,0xe7,0xda,0xd4,0x61}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0x39,0x2e,0x0c,0xba,0x30,0x28,0x8e}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0x80,0x0e,0xf4,0xb5,0xf0,0xee,0x4d}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0x9f,0x00,0x52,0x9c,0x0c,0x1f,0x41}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x3c,0x73,0x30,0x4a,0x9d,0x8b,0x99,0xd5}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x3c,0xac,0x33,0xe4,0x39,0xca,0x03,0x8c}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x00,0x6f,0x36,0x67,0x53,0x98,0x53,0x8f}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x08,0x8c,0x03,0xe6,0x94,0x54,0x33,0x31}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x00,0x89,0x3b,0x55,0x9f,0xcc,0x8e,0x66}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x0c,0x9b,0x3d,0x65,0xbd,0xf4,0x5d,0x58}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x0c,0xb7,0x08,0xcc,0xb8,0xee,0x68,0x06}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x24,0xf6,0x37,0xb5,0xb9,0xd2,0x2a,0xa7}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x3c,0x63,0x08,0x2e,0xaa,0xbc,0xbd,0x39}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x3c,0xf5,0x2e,0xb7,0xc9,0x66,0x56,0x1d}, 8333}, - {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x0c,0xf4,0x28,0xe2,0xaa,0xbd,0xb7,0x66}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x10,0xf6,0x04,0x53,0x3c,0xa4,0x1a,0x8e}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x14,0xdd,0x29,0x8b,0x43,0x1c,0xbf,0xec}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x30,0x51,0x15,0x61,0xb6,0x2d,0x73,0xa5}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x34,0x67,0x0f,0xfa,0xb6,0x12,0xe9,0xc6}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x08,0xe8,0x1e,0x26,0xe8,0xe3,0xee,0xd7}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x0c,0x82,0x37,0xb3,0x47,0xee,0x3a,0xe2}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x10,0x52,0x3c,0xd8,0xa8,0x9b,0x0e,0x67}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x14,0x4d,0x23,0xf3,0xab,0xcb,0x8b,0xcb}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x1c,0x2e,0x31,0xdf,0xad,0xf1,0xe6,0x16}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x1c,0x41,0x21,0x3b,0xfa,0xcc,0x9c,0x6b}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x20,0x93,0x12,0xb5,0x8c,0xbf,0x4f,0x57}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x24,0x3a,0x23,0x94,0xfd,0x91,0x71,0x2c}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x28,0x33,0x09,0xf8,0xc9,0x4c,0x68,0x81}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x2c,0x84,0x29,0xd3,0xae,0x5a,0xf6,0xf0}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x2c,0xe4,0x0d,0x50,0xcb,0x22,0x36,0x72}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x38,0x24,0x08,0x16,0xc3,0x0d,0xe9,0xd4}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x38,0x9a,0x24,0xe9,0xcb,0x5c,0xa1,0xcd}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x38,0xbd,0x08,0x8f,0x21,0x93,0x49,0x32}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x4f,0x0c,0xb1,0xd6,0x5b,0xd7,0x75}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x51,0x28,0x0b,0xb1,0xe9,0x0f,0xfd}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x5a,0x02,0xe2,0x21,0x93,0x49,0x32}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x5e,0x3e,0xbf,0x3d,0xc0,0x70,0x3a}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x04,0xc9,0x12,0xfc,0xd1,0xd9,0xdc,0x21}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x00,0x6e,0x34,0xe7,0xd0,0xa7,0x67,0x72}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x08,0xde,0x1f,0x29,0x2a,0xea,0xf9,0x6f}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x0c,0x5f,0x26,0x74,0xa4,0x67,0x78,0x7c}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x0c,0xc0,0x23,0xa4,0xad,0x7c,0xc9,0x98}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x20,0xc0,0x20,0x97,0xd1,0x88,0x9c,0x3b}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x24,0x20,0x0d,0xda,0x4f,0xf6,0x87,0x94}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x28,0x92,0x0f,0xcb,0x26,0xb2,0x22,0xac}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0x20,0x1a,0xd7,0x26,0xb2,0x22,0xac}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0xae,0x21,0x1b,0xe7,0x17,0x77,0x88}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0xd0,0x6e,0xdd,0xa4,0x18,0xa9,0xe9}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0xd9,0x32,0x78,0xb0,0x04,0x65,0xa7}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x38,0x7a,0x17,0xd5,0xda,0xcb,0xbd,0xf1}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x3c,0x38,0x0c,0x41,0x43,0x3c,0x7b,0x87}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x04,0x67,0x01,0x93,0xa8,0xb0,0xa1,0x22}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x0c,0x65,0xfb,0x96,0x97,0xd2,0xa9,0xb0}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x0c,0x9f,0x26,0x33,0xd1,0x69,0x99,0x99}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x0c,0xe2,0x0a,0xba,0xd1,0x20,0x90,0xdb}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x10,0x5d,0x26,0xf2,0xa2,0x41,0x73,0x39}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x10,0x62,0x3f,0x95,0xe0,0x65,0xfc,0x21}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x10,0xa6,0x19,0xf6,0xab,0x95,0xeb,0xcb}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x14,0xe2,0x22,0xcb,0x73,0x8f,0x94,0x89}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x18,0xfb,0x3d,0xa9,0x89,0x3d,0x1d,0x57}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x1c,0xc3,0x25,0x34,0xe0,0x20,0x53,0xfa}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x20,0x6d,0x2b,0x34,0xd0,0xcb,0x9d,0xe8}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x20,0xcb,0x02,0xcb,0xb9,0xa7,0xca,0x5e}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x24,0x5c,0x27,0x53,0x43,0x82,0x70,0x4b}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x24,0xd6,0x22,0x5f,0x79,0x3b,0x0b,0xf5}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x24,0xda,0x08,0xf0,0xbb,0xf9,0x9c,0x93}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x28,0xa2,0x10,0x7b,0x43,0x8e,0xb0,0x8d}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0x16,0x0d,0x58,0xb3,0x81,0x0b,0x61}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0x68,0x30,0x68,0xcb,0x59,0x3b,0xe7}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0x90,0x38,0x55,0xb9,0x4f,0xc9,0x26}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0xa2,0x35,0x92,0xc1,0x11,0xdd,0x82}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0xce,0x1f,0x6e,0xb3,0x81,0x86,0x05}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x34,0x35,0x39,0x15,0x2b,0xcc,0x6c,0xc7}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x34,0x38,0x2b,0x9f,0xad,0x57,0xa7,0x21}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x34,0x74,0x1d,0xf1,0xe7,0x32,0xe5,0xe3}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x38,0xc4,0x37,0xaf,0xab,0x0a,0xf5,0xef}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x00,0x3a,0x39,0xfd,0xa4,0x3b,0x55,0x91}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x3c,0x9d,0x2a,0x45,0xd5,0x37,0x3b,0xd6}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x3c,0xfb,0x2c,0xf5,0x52,0x54,0x4d,0x1e}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x04,0x3f,0x03,0x37,0xad,0xb4,0x63,0x10}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x04,0x93,0x09,0x95,0xd2,0xe9,0x39,0xbe}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x00,0x5b,0x0c,0xe3,0xb2,0x75,0x92,0xab}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x08,0xa8,0x05,0x9d,0xd0,0xcb,0xd5,0x85}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x0c,0x8e,0x1b,0xa0,0xc5,0xa9,0xda,0xce}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x0c,0xdb,0x36,0x5f,0x23,0x02,0xf7,0x29}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x0c,0xf5,0x22,0x2e,0x89,0x3e,0x71,0x6c}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x00,0xd6,0x10,0x85,0xb8,0xdd,0x41,0xc2}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x10,0x1a,0x23,0xb3,0x6b,0x98,0xf8,0x88}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x18,0x05,0x0f,0x38,0x3e,0xb2,0x21,0x21}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x18,0x58,0x16,0xf9,0x38,0x33,0xda,0x19}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x18,0xea,0x27,0x35,0xe7,0x3d,0xad,0xc5}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x1c,0x44,0x2b,0x70,0x9d,0xe7,0xa7,0xcc}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x0a,0x3f,0x95,0xbb,0x7c,0xc0,0x9f}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x0c,0x34,0x73,0xb8,0x5d,0x0d,0xdd}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x0f,0x05,0xa0,0x47,0xc6,0x55,0x07}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x97,0x20,0x4a,0x47,0xc5,0x58,0x81}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x24,0x8f,0x24,0xcd,0xaa,0xf5,0xde,0xe3}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x28,0x7d,0x16,0x8e,0x3c,0xaf,0x47,0xaf}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x28,0xc1,0x05,0x8d,0xb7,0x21,0x94,0xc1}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x2c,0x31,0x30,0xa3,0x39,0xd3,0x05,0x28}, 8188}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x2c,0x3d,0x30,0x9b,0xd2,0xdb,0x82,0x88}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x2c,0x47,0x1b,0x36,0x52,0xc1,0x3c,0x73}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x30,0x4a,0x10,0xe1,0xb7,0x39,0x82,0x2a}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x30,0xa3,0x29,0xfd,0x33,0xf6,0xea,0xab}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x34,0x27,0x85,0x9b,0xb5,0x25,0x10,0x69}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x34,0x59,0x25,0x41,0x36,0x51,0xd6,0x75}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x04,0xf5,0x9c,0x88,0xaf,0x91,0xd3,0xd3}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x0c,0xd1,0x1d,0x54,0xb8,0x0a,0x42,0xf4}, 8333}, - {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x0c,0xfa,0x37,0xe6,0x9d,0x8e,0x74,0x74}, 8333}, - {{0x20,0x01,0x13,0xd8,0x1c,0x01,0x20,0x00,0x24,0x70,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x14,0x70,0xff,0xfd,0x20,0x2c,0x02,0x25,0x90,0xff,0xfe,0x8f,0x5f,0x62}, 8333}, - {{0x20,0x01,0x14,0xba,0x02,0x00,0x00,0x00,0x54,0x3c,0x42,0xce,0xa4,0x8b,0xb0,0xd0}, 8333}, - {{0x20,0x01,0x14,0xba,0x02,0xfc,0x07,0x00,0x41,0xb2,0xdf,0x51,0xef,0xd8,0xf5,0x81}, 8333}, - {{0x20,0x01,0x19,0xf0,0x50,0x00,0x8c,0x8b,0x54,0x00,0x00,0xff,0xfe,0x1f,0xc0,0x23}, 8333}, - {{0x20,0x01,0x19,0xf0,0x00,0x05,0x07,0x49,0x54,0x00,0x00,0xff,0xfe,0x71,0xc3,0xfc}, 8333}, - {{0x20,0x01,0x19,0xf0,0x00,0x05,0x00,0xbc,0x54,0x00,0x00,0xff,0xfe,0x3b,0x93,0x39}, 8333}, - {{0x20,0x01,0x19,0xf0,0x74,0x02,0x04,0x2c,0x54,0x00,0x00,0xff,0xfe,0x6c,0xb9,0xb8}, 8333}, - {{0x20,0x01,0x1a,0xf8,0x40,0x10,0xa0,0x8f,0xf8,0x11,0xe5,0xf0,0x3f,0x63,0xe7,0x53}, 8333}, - {{0x20,0x01,0x1a,0xf8,0x40,0x10,0xa0,0x94,0x33,0x33,0x00,0x00,0x00,0x00,0x8c,0x38}, 8333}, - {{0x20,0x01,0x1a,0xf8,0x40,0x70,0xa0,0x16,0x33,0x33,0x00,0x00,0x00,0x00,0x5a,0xfb}, 8333}, - {{0x20,0x01,0x1a,0xf8,0x47,0x00,0xa0,0x71,0x44,0x44,0x00,0x00,0x00,0x00,0xe2,0x6e}, 8333}, - {{0x20,0x01,0x1b,0xc8,0x01,0xa0,0x59,0x0e,0x02,0xe0,0xf4,0xff,0xfe,0x16,0x3a,0x39}, 8333}, - {{0x20,0x01,0x20,0x40,0x00,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89}, 8333}, - {{0x20,0x01,0x02,0x88,0x10,0x01,0x01,0x07,0x29,0x4e,0x55,0x81,0x74,0xbd,0x42,0xf9}, 8333}, - {{0x20,0x01,0x03,0xc8,0xc1,0x03,0xa0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48}, 8333}, - {{0x20,0x01,0x41,0x28,0x61,0x35,0x00,0x10,0x02,0x0c,0x29,0xff,0xfe,0x69,0x9e,0x81}, 8333}, - {{0x20,0x01,0x41,0x28,0x61,0x35,0x20,0x10,0x02,0x1e,0x0b,0xff,0xfe,0xe8,0xa3,0xc0}, 8333}, - {{0x20,0x01,0x41,0x28,0x61,0x35,0xe0,0x01,0x50,0x54,0x00,0xff,0xfe,0x37,0xe9,0xeb}, 8333}, - {{0x20,0x01,0x41,0x78,0x00,0x06,0x14,0x27,0x00,0x62,0x01,0x16,0x01,0x88,0x00,0x85}, 8333}, - {{0x20,0x01,0x41,0xd0,0x10,0x04,0x20,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x10,0x08,0x27,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0x47,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0x6f,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0x73,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0x74,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0x7d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0x8b,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0xc1,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0xd2,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0xe1,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x01,0xe6,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x16,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x20,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x32,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x8a,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x8c,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x8d,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x94,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x95,0x0a,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x03}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0x9c,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0xa2,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0xa2,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0xab,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0xbf,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x02,0xc7,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x03,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfa,0x25}, 8333}, - {{0x20,0x01,0x41,0xd0,0x03,0x03,0x19,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xe2}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xe3}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x1b,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x3d,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x4d,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x7a,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x8f,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xba,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbd,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbe,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xc6,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xd8,0x44,0x13,0x37,0x00,0x00,0x00,0x00,0x10,0x17}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x0d,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0x0d,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xde,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x08,0xe3,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x4e,0x3f,0x00,0x00,0x00,0x00,0x1c,0x7d,0x6b,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x63,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x68,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x6c,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x6f,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0a,0xfa,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0d,0x11,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0d,0x2a,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x41,0xd0,0x00,0x0e,0x13,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x41,0xf0,0x00,0x61,0x00,0x00,0x72,0xf3,0x95,0xff,0xfe,0x09,0x75,0x21}, 8333}, - {{0x20,0x01,0x41,0xf0,0x00,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x07,0x15,0x1c,0xba,0xac,0x6f,0xff,0xfe,0xb7,0x3b,0xa9}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x0b,0x08,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x0b,0x09,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x15,0x11,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x15,0x1b,0x95,0x2c,0x3e,0x8a,0x9a,0x24,0xe1,0x70,0x84}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x15,0x0f,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x1a,0x01,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x1c,0x0b,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x04,0x70,0x1f,0x1d,0x03,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}, 8333}, - {{0x20,0x01,0x04,0x70,0x00,0x25,0x04,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x04,0x70,0x00,0x28,0x03,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333}, - {{0x20,0x01,0x04,0x70,0x75,0x4f,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x7a}, 8333}, - {{0x20,0x01,0x04,0x70,0x00,0x07,0x0b,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x04,0x70,0x7d,0xda,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x04,0x70,0x00,0x08,0x0c,0x70,0x02,0x0c,0x29,0xff,0xfe,0x6a,0x8f,0xdc}, 8333}, - {{0x20,0x01,0x04,0x70,0x00,0x08,0x0c,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54}, 8333}, - {{0x20,0x01,0x04,0x70,0x00,0x0a,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x04,0x70,0xd0,0x0d,0x00,0x00,0x36,0x64,0xa9,0xff,0xfe,0x9a,0x51,0x50}, 8333}, - {{0x20,0x01,0x04,0x70,0xdb,0xf2,0xaa,0xaa,0x00,0x00,0x00,0x00,0x0b,0x17,0xc0,0x1c}, 8333}, - {{0x20,0x01,0x04,0x70,0xf4,0x57,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa6}, 8333}, - {{0x20,0x01,0x48,0x01,0x78,0x19,0x00,0x74,0xb7,0x45,0xb9,0xd5,0xff,0x10,0xa6,0x1a}, 8333}, - {{0x20,0x01,0x48,0x01,0x78,0x19,0x00,0x74,0xb7,0x45,0xb9,0xd5,0xff,0x10,0xaa,0xec}, 8333}, - {{0x20,0x01,0x48,0x01,0x78,0x28,0x01,0x04,0xbe,0x76,0x4e,0xff,0xfe,0x10,0x13,0x25}, 8333}, - {{0x20,0x01,0x4b,0xa0,0xca,0xfe,0x13,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x4b,0xa0,0xca,0xfe,0x04,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x05,0x58,0x60,0x45,0x00,0x23,0x18,0x30,0x89,0x6c,0xd9,0x01,0x19,0x0d}, 8333}, - {{0x20,0x01,0x06,0x7c,0x12,0x20,0x08,0x0c,0x00,0x00,0x00,0x00,0x93,0xe5,0x0d,0xd2}, 8333}, - {{0x20,0x01,0x06,0x7c,0x21,0x28,0xff,0xff,0x60,0x62,0x36,0xff,0xfe,0x30,0x65,0x32}, 8333}, - {{0x20,0x01,0x08,0xd8,0x09,0x23,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x0e,0xbd}, 8333}, - {{0x20,0x01,0x09,0x81,0x44,0x52,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00}, 8333}, - {{0x20,0x01,0x09,0x81,0x00,0x46,0x00,0x01,0xba,0x27,0xeb,0xff,0xfe,0x5b,0xed,0xee}, 8333}, - {{0x20,0x01,0x09,0x81,0xbd,0xbd,0x00,0x01,0xc5,0x06,0x7d,0x38,0x4b,0x47,0xda,0x15}, 8333}, - {{0x20,0x01,0x09,0x85,0x79,0xaf,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35}, 8333}, - {{0x20,0x01,0x0b,0xc8,0x22,0x5f,0x01,0x0e,0x05,0x05,0x65,0x73,0x75,0x73,0x0d,0x0a}, 8333}, - {{0x20,0x01,0x0b,0xc8,0x32,0x3c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53}, 8333}, - {{0x20,0x01,0x0b,0xc8,0x32,0x3c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04}, 8333}, - {{0x20,0x01,0x0b,0xc8,0x32,0x3c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xca,0xfe}, 8333}, - {{0x20,0x01,0x0b,0xc8,0x36,0x80,0x42,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x01,0x0b,0xc8,0x39,0x9f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x02,0x01,0xe2,0x55,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe2,0x55,0x87}, 8333}, - {{0x20,0x02,0x01,0xe2,0x55,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe2,0x55,0x88}, 8333}, - {{0x20,0x02,0x2a,0x33,0x21,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x33,0x21,0xc4}, 8333}, - {{0x20,0x02,0x2e,0x04,0x78,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x04,0x78,0x4b}, 8333}, - {{0x20,0x02,0x2e,0xbc,0x2c,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16}, 8333}, - {{0x20,0x02,0x2f,0x5a,0x3c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x3c,0x1c}, 10011}, - {{0x20,0x02,0x2f,0x5a,0x56,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x56,0x2a}, 8333}, - {{0x20,0x02,0x2f,0x5b,0xa5,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5b,0xa5,0xf9}, 8333}, - {{0x20,0x02,0x31,0x41,0x02,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x41,0x02,0x8c}, 8333}, - {{0x20,0x02,0x32,0x3f,0xa2,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x3f,0xa2,0xf2}, 8333}, - {{0x20,0x02,0x32,0x3f,0x0f,0xbd,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x3f,0x0f,0xbd}, 8333}, - {{0x20,0x02,0x33,0xff,0x69,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x02,0x3e,0x6a,0x10,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x6a,0x10,0x6f}, 8333}, - {{0x20,0x02,0x3e,0x70,0x0b,0xbc,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x70,0x0b,0xbc}, 8333}, - {{0x20,0x02,0x3e,0x7a,0x67,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7a,0x67,0x27}, 8333}, - {{0x20,0x02,0x3f,0x62,0xe6,0xbb,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x62,0xe6,0xbb}, 8333}, - {{0x20,0x02,0x45,0x40,0x4b,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x40,0x4b,0x30}, 8333}, - {{0x20,0x02,0x4e,0x6b,0xc7,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x02,0x50,0x52,0x4d,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x52,0x4d,0x8a}, 8333}, - {{0x20,0x02,0x51,0xa9,0x9c,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xa9,0x9c,0xc9}, 8333}, - {{0x20,0x02,0x54,0xfb,0xcb,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x02,0x5b,0xc2,0x54,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xc2,0x54,0x28}, 8333}, - {{0x20,0x02,0x5b,0xce,0x12,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xce,0x12,0x53}, 8333}, - {{0x20,0x02,0x5b,0xdb,0x19,0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xdb,0x19,0xe8}, 8333}, - {{0x20,0x02,0x5c,0x3f,0x39,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x3f,0x39,0x12}, 8333}, - {{0x20,0x02,0x5d,0xbd,0x91,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xbd,0x91,0xa9}, 8333}, - {{0x20,0x02,0x5d,0xbe,0x8c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xbe,0x8c,0xc6}, 8333}, - {{0x20,0x02,0x5f,0xd3,0x89,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xd3,0x89,0x44}, 8333}, - {{0x20,0x02,0x65,0xc8,0xa0,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0xc8,0xa0,0x18}, 8333}, - {{0x20,0x02,0x67,0x50,0xa8,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x50,0xa8,0x39}, 8333}, - {{0x20,0x02,0x67,0xfa,0x04,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xfa,0x04,0x4b}, 8333}, - {{0x20,0x02,0x6a,0x0e,0x3e,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x6a,0x0e,0x3e,0xa8}, 10011}, - {{0x20,0x02,0x6a,0x0f,0x24,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x6a,0x0f,0x24,0x97}, 8333}, - {{0x20,0x02,0x6d,0xec,0x5a,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xec,0x5a,0xc7}, 8333}, - {{0x20,0x02,0x70,0x4a,0xd6,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x4a,0xd6,0xd4}, 9997}, - {{0x20,0x02,0x72,0x37,0xfc,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x37,0xfc,0xf6}, 20188}, - {{0x20,0x02,0x76,0xb2,0x7f,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xb2,0x7f,0x40}, 8333}, - {{0x20,0x02,0x78,0x19,0x7e,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x19,0x7e,0x80}, 7743}, - {{0x20,0x02,0x78,0x1b,0x8d,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x1b,0x8d,0xb8}, 8333}, - {{0x20,0x02,0x7b,0x38,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7b,0x38,0xcd,0x00}, 8333}, - {{0x20,0x02,0xac,0x52,0xb8,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x52,0xb8,0x54}, 8333}, - {{0x20,0x02,0xb6,0x10,0x1c,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x10,0x1c,0xa3}, 8333}, - {{0x20,0x02,0xb9,0x46,0x69,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x46,0x69,0x4a}, 8339}, - {{0x20,0x02,0xb9,0x94,0x91,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x94,0x91,0x67}, 8333}, - {{0x20,0x02,0xbc,0x28,0x6b,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x28,0x6b,0x92}, 8333}, - {{0x20,0x02,0xc2,0x3f,0x8f,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x3f,0x8f,0xc5}, 8333}, - {{0x20,0x02,0xc3,0x38,0x3f,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0xc3,0x38,0x3f,0x0a}, 8333}, - {{0x20,0x02,0xd1,0xb1,0x56,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0xb1,0x56,0x15}, 8333}, - {{0x20,0x02,0xd2,0xd3,0x6d,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0xd2,0xd3,0x6d,0xa5}, 8333}, - {{0x20,0x02,0xd9,0x17,0x02,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x17,0x02,0xb1}, 8333}, - {{0x20,0x02,0xdb,0x71,0xf4,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0xdb,0x71,0xf4,0x34}, 8333}, - {{0x20,0x03,0x00,0x0a,0x03,0x6f,0x4f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x20,0x03,0x00,0x0a,0x03,0x7f,0xef,0x4f,0xde,0xad,0xba,0xbe,0xb0,0x0b,0xbe,0xef}, 8333}, - {{0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x2c,0x63,0xd8}, 8333}, - {{0x24,0x00,0x89,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xd5,0x9d,0x8d}, 8333}, - {{0x24,0x01,0x25,0x00,0x02,0x03,0x00,0x10,0x01,0x53,0x01,0x20,0x01,0x56,0x00,0x83}, 8333}, - {{0x24,0x01,0xa4,0x00,0x32,0x00,0x56,0x00,0x14,0xee,0xf3,0x61,0x4b,0xdc,0x1f,0x7c}, 8333}, - {{0x24,0x02,0x1f,0x00,0x81,0x00,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x24,0x03,0x42,0x00,0x04,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff}, 8333}, - {{0x24,0x05,0x98,0x00,0xb4,0x40,0x94,0x7f,0x59,0xa5,0xf3,0x79,0x18,0x76,0x85,0x8c}, 8333}, - {{0x24,0x05,0xaa,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}, 8333}, - {{0x24,0x06,0xda,0x14,0x04,0x45,0x52,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x1a,0x58,0x81,0xfe,0x6e,0xd0,0x11,0x03}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x22,0xaa,0x25,0x85,0xfe,0x88,0x7d,0x58}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x26,0x74,0x33,0xbb,0x25,0xd6,0xcb,0xba}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x2e,0x19,0xa8,0xc7,0xa3,0x6a,0xbd,0xe0}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x3c,0xc8,0x04,0x3d,0xfb,0xcc,0x50,0x67}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x52,0x28,0x2b,0x53,0xbb,0x9a,0xed,0xf5}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x57,0x29,0x01,0x02,0x99,0x8c,0xd4,0x1a}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x59,0x1b,0x48,0x81,0x39,0x86,0x37,0x03}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x59,0xb9,0x0b,0x50,0xf4,0x7f,0xb5,0x60}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x61,0xf2,0xcf,0xb0,0x8c,0x45,0x5f,0xdd}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x63,0x56,0x68,0xe0,0x73,0xfc,0xac,0x0b}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x66,0x0e,0xf6,0xbc,0x35,0x63,0xba,0x8e}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x06,0x91,0x00,0x9e,0xf2,0xdf,0x22,0x7d}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x72,0x1c,0x83,0xd2,0x67,0x65,0x43,0x00}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x72,0x37,0x09,0xbe,0x46,0x01,0xbc,0x15}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x7a,0x3b,0xc2,0x03,0xfd,0x11,0x6c,0x7d}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x7a,0x74,0xa8,0x0e,0x88,0x9a,0xba,0x42}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x7e,0xe3,0xa1,0x81,0xf2,0x5c,0xfa,0x79}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x8a,0x25,0x90,0x84,0x01,0x40,0x45,0x49}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x8b,0xc0,0xc6,0xfd,0xec,0xfb,0xf0,0x74}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x91,0xce,0xd0,0xba,0x1b,0x9e,0xc2,0x7b}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x93,0x36,0x44,0xe7,0x84,0xb4,0x85,0xb9}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x93,0x6c,0xc3,0xb9,0xa1,0xd0,0x08,0x48}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x93,0xef,0x1e,0xef,0x65,0xc8,0x76,0x6d}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x94,0xe0,0x5b,0x27,0x78,0xc2,0x51,0x11}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x98,0x15,0xa2,0x02,0x18,0xa3,0x2a,0x36}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x9e,0x1b,0x13,0x5c,0x74,0x72,0x09,0xd9}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x9f,0x84,0x02,0x78,0x68,0xf5,0xb8,0xea}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa0,0x62,0x49,0x3f,0xa6,0xf8,0xca,0x75}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa1,0x92,0x0b,0x98,0x30,0x66,0x8f,0x11}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa1,0xcb,0x2f,0x19,0x4a,0x54,0x38,0xc9}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa4,0xa2,0x04,0xc9,0xc4,0x3a,0x98,0xae}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa7,0xe9,0xcd,0x48,0xfa,0x90,0x46,0xd3}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x0a,0x88,0x00,0x99,0x66,0x71,0xfc,0xe4}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xab,0xe1,0x2e,0x48,0xeb,0x97,0x2a,0xb5}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xac,0xf5,0x2b,0x21,0x5d,0x2a,0x6b,0x31}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xb5,0x1f,0x89,0x66,0x74,0xa5,0x6c,0x53}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xb8,0xe3,0xf3,0xca,0xe4,0x12,0xda,0xa5}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xba,0x7c,0x6d,0xa8,0xda,0x59,0xb1,0xb6}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xbe,0x04,0x6f,0x8e,0x8f,0x93,0xc5,0x55}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xc8,0x2d,0x2a,0x0b,0x31,0xa5,0xe2,0x8d}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xc9,0x93,0xeb,0x06,0xbd,0x2c,0x1e,0x65}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xd4,0xb9,0xbf,0xf8,0xc4,0xd4,0x1e,0x05}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xd7,0x0d,0xa7,0x3d,0x1d,0xdd,0x43,0x9e}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xe1,0x03,0xf4,0x56,0xb2,0x96,0x9f,0x29}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xea,0x3b,0x27,0xec,0x07,0xc2,0xae,0xbc}, 8333}, - {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xf6,0x2c,0x50,0x13,0x37,0x9b,0x36,0x3e}, 8333}, - {{0x24,0x0b,0x00,0x10,0xca,0x20,0x00,0xf0,0x02,0x24,0xe8,0xff,0xfe,0x1f,0x60,0xd9}, 8333}, - {{0x24,0x0b,0x02,0x50,0x01,0xe0,0x24,0x00,0xb9,0xef,0x8f,0xe3,0xa6,0x9a,0x73,0x78}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x13,0xf4,0xce,0xb6,0xa9,0xdb,0x4f,0x47}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x25,0x50,0x93,0x66,0xa5,0xd9,0x78,0xa5}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x02,0x7d,0x06,0xed,0x7c,0x8d,0x7b,0xee}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x2e,0xd6,0x8a,0x19,0x04,0xeb,0x36,0xc1}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x34,0xc7,0x2e,0x9e,0xe6,0x0e,0xf8,0x23}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x38,0xde,0x04,0x42,0x72,0xdf,0x63,0x46}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x3a,0x1e,0x87,0x8f,0x99,0x1a,0x95,0x82}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x3d,0x88,0x18,0x05,0x54,0xe3,0xf4,0xc8}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x3f,0x3e,0x58,0xbd,0xec,0x82,0x5d,0xac}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x44,0x9a,0x95,0x15,0x84,0x36,0xf4,0x07}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x4f,0x84,0x27,0x7f,0xe6,0x4d,0x1f,0x06}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x52,0x29,0xde,0x84,0x82,0x26,0x72,0x57}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x57,0x43,0x42,0xc3,0x95,0x1b,0xe9,0x7a}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x5a,0x29,0x08,0x5b,0x86,0xb5,0xfa,0x0e}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x5d,0xe8,0x08,0x1e,0x6d,0x79,0x33,0x0b}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x5f,0xca,0xad,0x1e,0x5b,0x9c,0x52,0x65}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x68,0xc4,0xca,0x1b,0x81,0x3e,0x1b,0xce}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x00,0x06,0xde,0x9e,0x7b,0x5e,0xa5,0x58}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x6c,0x72,0x1f,0xcd,0x04,0x33,0xdc,0x97}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x77,0xee,0x62,0x9f,0xbc,0x13,0xfb,0x4f}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x79,0xd0,0x85,0xd6,0x51,0x6f,0x32,0x93}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x00,0x81,0x42,0x2f,0x9e,0xf3,0x45,0x79}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x82,0x2b,0x5f,0x05,0xec,0x8d,0x48,0xc6}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x08,0x2a,0x76,0xa2,0xfd,0xc9,0x84,0x5e}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x83,0xca,0xce,0xf6,0xe0,0x4c,0x50,0xc0}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x8b,0xa2,0xa3,0x6c,0x86,0x87,0xd5,0xaa}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x8c,0x80,0x5c,0x67,0x3b,0x47,0x90,0xb3}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x8e,0xb8,0xf4,0x7f,0x6d,0x53,0xe3,0xae}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x98,0x9c,0xf8,0xf8,0xa9,0x22,0x1b,0x9a}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x98,0xc9,0x1e,0xb3,0xea,0x12,0xa8,0xf0}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x9e,0xe5,0xa8,0xf6,0x6b,0x2a,0x86,0x6e}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xa4,0x6b,0x7b,0xd5,0x62,0x9f,0xf7,0x5c}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xa6,0x27,0x82,0x99,0x87,0x84,0xd4,0x39}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xad,0x0b,0x95,0x5e,0xb4,0xe5,0xd9,0x7d}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xae,0x82,0x71,0x17,0x9d,0x69,0x7c,0x86}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xcc,0xee,0x36,0x5a,0x43,0xf8,0xb8,0x71}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xd5,0xee,0xa3,0xe2,0x2f,0x85,0xe5,0x93}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xd5,0xf0,0x1f,0xe0,0x6b,0xd5,0x18,0xa8}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xe4,0xa7,0x5a,0xba,0xaf,0x87,0x4c,0xdb}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xe8,0xe5,0x02,0xd0,0xfb,0x6f,0x02,0xf5}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xe9,0xef,0x46,0x90,0xa5,0xac,0x92,0xbe}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xef,0xba,0x22,0x60,0x69,0x97,0xfc,0xf7}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xf1,0x07,0x2d,0x08,0x0c,0x67,0xe5,0xdd}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xf1,0xb9,0x88,0xfb,0xf3,0xdb,0xa8,0x6e}, 8333}, - {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xf7,0x9c,0x17,0xb7,0x6f,0x75,0x95,0xb7}, 8333}, - {{0x26,0x00,0x1f,0x14,0x06,0xae,0xd9,0x00,0x65,0x50,0x3f,0xc5,0xe0,0x74,0xa7,0x2c}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x12,0x43,0x38,0xb3,0x0c,0xaa,0xd6,0x2e}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x16,0x6d,0xa9,0x56,0x10,0x41,0xf9,0x7d}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x35,0xf2,0x24,0x28,0xfc,0x57,0xd6,0x38}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x3c,0x75,0x33,0x3e,0x0b,0x7f,0x8c,0xc0}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x3f,0xbf,0x03,0x1f,0x1b,0x57,0x8b,0x18}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x56,0x17,0x75,0x75,0x03,0x79,0xa8,0xcc}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x58,0xfa,0xfc,0xe6,0x00,0x30,0xa5,0xdc}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x5e,0x74,0x70,0xdc,0xaf,0x78,0x6b,0x77}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x70,0x36,0xf6,0x51,0x02,0xee,0x39,0xcd}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x07,0xfc,0x90,0x04,0xe7,0xbe,0xff,0xe2}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x81,0x4a,0x23,0xf6,0xe9,0x96,0x5e,0x64}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x82,0x2c,0xa8,0x8b,0x0f,0x9c,0x57,0xe3}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x83,0x14,0xb9,0x1e,0xa7,0xba,0x07,0x02}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x88,0xbb,0xee,0x9a,0x10,0xde,0x00,0x12}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x8c,0x30,0x56,0xf5,0xa2,0x9a,0x91,0xde}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x8f,0xdf,0x65,0x17,0x77,0x18,0x8c,0x42}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x91,0xfd,0x78,0xb1,0x62,0xa3,0x01,0x93}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x93,0x0d,0x93,0xed,0x76,0xa6,0x32,0x85}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x93,0xc2,0x61,0x5f,0xa7,0x9a,0xc1,0x1f}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xa7,0x80,0x8b,0xc8,0xa1,0xf6,0xd4,0x17}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xa9,0x51,0xe6,0x63,0x40,0x46,0x8c,0x3a}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xab,0x19,0x5f,0xe3,0xf1,0x55,0x13,0x71}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xae,0xfd,0x9c,0xc7,0x00,0xd3,0x6e,0x86}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xb0,0x31,0xe8,0x6e,0x86,0x04,0x32,0x4a}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x0b,0x6e,0x43,0x99,0x9d,0xc2,0x6b,0x45}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xb7,0xc7,0x58,0xc6,0x21,0xa1,0xfd,0x41}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xc1,0x69,0x62,0x82,0x17,0x8c,0x27,0xd6}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xc9,0x4e,0x05,0x8b,0xbd,0x35,0xd8,0x15}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xca,0xa5,0x73,0x69,0x73,0xa4,0x57,0x11}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xcd,0x15,0xb9,0xf2,0x6e,0x3e,0x6f,0xd1}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xd6,0xf3,0x07,0x75,0x66,0xb7,0x3e,0x92}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xdb,0xec,0xf7,0xd9,0x0e,0x15,0xf8,0xe0}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xdb,0xf4,0x4d,0x41,0x59,0x4e,0xbc,0x20}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xe1,0x1b,0x45,0x89,0xa0,0xc3,0x9c,0xc7}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xed,0x68,0x15,0xb0,0x3a,0x97,0xbe,0x0c}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xee,0xf3,0xbc,0xe0,0x84,0xee,0xa9,0x8b}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xef,0x3a,0xf6,0x6e,0xf0,0x59,0xd0,0x3f}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xf6,0x7c,0xd3,0x98,0x05,0xb6,0xd3,0x4f}, 8333}, - {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xfe,0x35,0x50,0x99,0x3a,0x8e,0xd1,0x23}, 8333}, - {{0x26,0x00,0x1f,0x18,0x64,0xd9,0x16,0x03,0x6f,0x6f,0xee,0xf9,0xb5,0x95,0x19,0x58}, 8333}, - {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0xd6,0x50}, 8333}, - {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x89,0x74,0x38}, 8333}, - {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x91,0x3e,0x49}, 8333}, - {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xbb,0x98,0x1e}, 8333}, - {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x69,0x89,0xe9}, 8333}, - {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x91,0x6a,0x29}, 8333}, - {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x28,0x14,0x45}, 8333}, - {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xe0,0x23,0x3e}, 8333}, - {{0x26,0x00,0x6c,0x55,0x72,0x00,0x02,0x4d,0x0c,0xf4,0x81,0x1c,0x7c,0xb3,0xf7,0xa7}, 8333}, - {{0x26,0x00,0x88,0x05,0x24,0x00,0x01,0x4e,0x02,0x26,0x4a,0xff,0xfe,0x02,0x2b,0xa4}, 8333}, - {{0x26,0x01,0x01,0x8d,0x46,0x00,0x3c,0xc2,0x20,0xe7,0xb3,0xff,0xfe,0xcf,0x0a,0x99}, 8333}, - {{0x26,0x01,0x01,0xc2,0x17,0x02,0x52,0x41,0x04,0x7d,0x40,0x16,0xec,0x42,0x67,0x05}, 8333}, - {{0x26,0x01,0x04,0x41,0x41,0x01,0x70,0xcd,0x04,0xe3,0x8e,0x81,0x32,0x50,0x1f,0x0b}, 8333}, - {{0x26,0x01,0x06,0x02,0x99,0x80,0x0f,0x78,0x02,0x11,0x11,0xff,0xfe,0xc5,0x01,0xae}, 8333}, - {{0x26,0x01,0x06,0x46,0x41,0x03,0x17,0x9f,0x58,0x09,0x1b,0xff,0xfe,0x55,0x66,0x78}, 8333}, - {{0x26,0x02,0x00,0x4c,0x03,0x23,0xb1,0x01,0x35,0xa3,0x9d,0xe8,0x69,0x84,0xef,0x56}, 8333}, - {{0x26,0x02,0xff,0x62,0x01,0x04,0x0a,0xc1,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x02,0xff,0xc5,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x71,0x1e}, 8333}, - {{0x26,0x02,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x30,0x1c,0x75}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x17,0xe9,0x20,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf8,0xf0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0x00,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0xc0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0xd0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0xe0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xfa,0x20,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xfa,0x30,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x16,0x84,0x50,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1a,0xc4,0xb0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0x40,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0x50,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0x60,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xc0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xd0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xe0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xf0,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x05,0x00,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x05,0x30,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x26,0x1f,0x60,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x28,0xb8,0x50,0x01}, 8333}, - {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0xd7,0xe0,0x01}, 8333}, - {{0x26,0x05,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333}, - {{0x26,0x05,0x5d,0x80,0x20,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x45}, 8333}, - {{0x26,0x05,0x98,0x80,0x00,0x00,0x09,0x53,0x02,0x25,0x90,0xff,0xfe,0xd2,0xc0,0xb4}, 8333}, - {{0x26,0x06,0xc3,0x80,0x00,0x00,0x00,0x00,0x02,0x15,0x17,0xff,0xfe,0xb3,0x03,0xec}, 8333}, - {{0x26,0x07,0x1c,0x00,0x00,0x0a,0x00,0x06,0x3c,0x1c,0x1b,0x0d,0x0b,0xa4,0x8e,0xa9}, 8333}, - {{0x26,0x07,0x1c,0x00,0x00,0x0a,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00}, 8333}, - {{0x26,0x07,0x44,0x80,0x00,0x02,0x20,0x00,0x02,0x50,0x56,0xff,0xfe,0x86,0x64,0x49}, 8333}, - {{0x26,0x07,0x53,0x00,0x01,0x20,0x06,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x01,0x20,0x09,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x02,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x05,0x56}, 8333}, - {{0x26,0x07,0x53,0x00,0x02,0x03,0x01,0x18,0x37,0x33,0x00,0x00,0x00,0x00,0x14,0x14}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x10,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x1e,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x1e,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x1e,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x02,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x3d,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x3f,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x54,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x60,0x0a,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x26,0x07,0x53,0x00,0x00,0x61,0x0f,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x26,0x07,0x90,0x00,0x00,0x00,0x00,0x01,0x50,0x54,0x00,0xff,0xfe,0x5d,0x26,0x4e}, 8333}, - {{0x26,0x07,0xf1,0xc0,0x08,0x46,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0xd0,0x0e}, 8333}, - {{0x26,0x07,0xf2,0xd8,0x40,0x05,0x00,0x0d,0xa8,0xa2,0xee,0xff,0xfe,0xe0,0xa8,0x59}, 8333}, - {{0x26,0x07,0xf9,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x40}, 8333}, - {{0x26,0x07,0xfa,0x18,0x3a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333}, - {{0x26,0x07,0xfe,0xa8,0x3c,0xa0,0x09,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x26,0x07,0xfe,0xa8,0x4d,0xa0,0x03,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x26,0x07,0xff,0x10,0x00,0xc5,0x05,0x02,0x02,0x25,0x90,0xff,0xfe,0x32,0xd4,0x46}, 8333}, - {{0x26,0x07,0xff,0x28,0x90,0x05,0x00,0x01,0x00,0x00,0x00,0x00,0x25,0x67,0x57,0xe0}, 8333}, - {{0x26,0x20,0x00,0x71,0x40,0x00,0x00,0x00,0x01,0x92,0x00,0x30,0x01,0x20,0x01,0x10}, 8333}, - {{0x26,0x20,0x00,0xb8,0x40,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x00,0x01}, 8333}, - {{0x28,0x00,0x01,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09}, 8333}, - {{0x28,0x01,0x00,0x84,0x00,0x00,0x10,0x34,0x76,0xd4,0x35,0xff,0xfe,0x7f,0x50,0x33}, 8333}, - {{0x2a,0x00,0x16,0xd8,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0x6a,0xc2,0x61}, 8333}, - {{0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x24,0x00,0x00,0x00,0x00,0x01,0x48,0x02,0x18}, 8333}, - {{0x2a,0x00,0x19,0xe0,0x00,0x01,0x00,0x01,0x02,0x25,0x90,0xff,0xfe,0xa5,0x0f,0xc0}, 8333}, - {{0x2a,0x00,0x1a,0x48,0x78,0x10,0x01,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x08,0xc7,0x74}, 8333}, - {{0x2a,0x00,0x63,0x40,0x20,0x04,0x00,0x00,0x50,0x54,0x00,0xff,0xfe,0x54,0x03,0x8c}, 8333}, - {{0x2a,0x00,0x7b,0x80,0x04,0x77,0x00,0x21,0x00,0x00,0x00,0x00,0x1c,0x8c,0x83,0xa6}, 8333}, - {{0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333}, - {{0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333}, - {{0x2a,0x01,0x02,0x38,0x43,0x63,0x49,0x00,0xd8,0x5e,0xc1,0xd9,0x2b,0x32,0x61,0xd0}, 8333}, - {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0x53,0xa9,0x02,0x2b,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0x5b,0xfa,0x55,0x26,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0xb0,0x1c,0x33,0x79,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x4d,0x60,0x00,0x03,0x00,0x01,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x1d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x1e,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x22,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8833}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x23,0x9c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 9002}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x29,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x31,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x3f,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x0b,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x12,0xd7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x0d,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x0e,0x2d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x0e,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x51,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x52,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x53,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x43,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x33,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x43,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x61,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x71,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x74,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x33,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x33,0xad,0xfe,0xa1,0x00,0x00,0x00,0x00,0x06,0x66}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x34,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x13,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x52,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x60,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x74,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x93,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x22,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x22,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x11,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x70,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x72,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x72,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x90,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x30,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x33,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x71,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x41,0xf0,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x33}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x63,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x70,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x21,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x31,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x42,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x1c,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x01,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x22,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x27,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x2f,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x0d,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x10,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x05,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x16,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x24,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x52,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x61,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x41,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 3333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x63,0xb4,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x81,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x83,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x04,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x52,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x10,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x32,0xa6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x41,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x41,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x90,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x14,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x02,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x03,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x53,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x60,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x31,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x32,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x60,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x10,0x54,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x1e,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x1e,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x12,0x18,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x02,0x21,0x0f,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x5e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x01,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x15,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x1d,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x1f,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x22,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0b,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0b,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0b,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x5e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x2d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x24,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x2c,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x33,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x34,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x39,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x3b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x3d,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x42,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x5d,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x63,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x67,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x71,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x06,0x80,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x06,0xf0,0xff,0xff,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0xcb}, 8333}, - {{0x2a,0x01,0x07,0x9d,0xb7,0xdd,0xff,0xb4,0x5d,0x86,0x70,0xb8,0xfc,0x7f,0xf2,0x53}, 8333}, - {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333}, - {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333}, - {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xaa,0x03,0x73,0x50,0x54,0x00,0xff,0xfe,0xb3,0x29,0x47}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xaa,0x03,0xa0,0x50,0x54,0x00,0xff,0xfe,0x8c,0x97,0x4c}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xb0,0x04,0xb7,0x91,0x0d,0x62,0x5e,0xa1,0x3e,0xc3,0x42}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xb5,0x03,0xe6,0x50,0x54,0x00,0xff,0xfe,0xd7,0x4e,0x54}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xb5,0x04,0x1e,0x50,0x54,0x00,0xff,0xfe,0x38,0xf4,0xfb}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xba,0x03,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x33}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xbc,0x01,0x8c,0x50,0x54,0x00,0xff,0xfe,0xfd,0x3b,0x49}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xbd,0x03,0xd5,0x50,0x54,0x00,0xff,0xfe,0x95,0xf5,0x86}, 8333}, - {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x50,0x94,0xb8}, 8333}, - {{0x2a,0x01,0x8e,0x01,0xb9,0x43,0x3a,0x63,0xd2,0x50,0x99,0xff,0xfe,0x1f,0x4f,0xb2}, 8333}, - {{0x2a,0x01,0xb2,0xe0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}, 8333}, - {{0x2a,0x01,0x00,0xd0,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x45}, 8333}, - {{0x2a,0x01,0x00,0xd0,0x8f,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x01,0x0e,0x34,0xec,0x29,0xe8,0xd0,0x25,0xc7,0xc1,0xce,0xb7,0xa3,0xd2,0x38}, 8333}, - {{0x2a,0x01,0x0e,0x34,0xec,0x4a,0xc2,0xd0,0x1c,0xf3,0x40,0xd2,0xa7,0x9f,0x39,0x01}, 8333}, - {{0x2a,0x01,0x0e,0x34,0xee,0xd7,0x66,0x70,0xec,0x1b,0xbf,0x7c,0xb0,0x12,0x60,0x69}, 8333}, - {{0x2a,0x01,0x0e,0x35,0x24,0x33,0xe3,0x20,0x9c,0x8e,0x6f,0xf0,0x99,0x0f,0xf0,0x6e}, 8333}, - {{0x2a,0x01,0x0e,0x35,0x2e,0xe5,0x06,0x10,0x02,0x1f,0xd0,0xff,0xfe,0x4e,0x74,0x60}, 8333}, - {{0x2a,0x02,0x12,0x05,0x50,0x51,0xa6,0x40,0xd6,0xae,0x52,0xff,0xfe,0xa3,0x00,0xac}, 8333}, - {{0x2a,0x02,0x12,0x0b,0x2c,0x2a,0x5e,0xc0,0x10,0xdd,0x31,0xff,0xfe,0x42,0x50,0x79}, 8333}, - {{0x2a,0x02,0x01,0x68,0x62,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14}, 8333}, - {{0x2a,0x02,0x01,0x80,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18}, 8333}, - {{0x2a,0x02,0x01,0x80,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xed}, 8333}, - {{0x2a,0x02,0x18,0x11,0xb7,0x07,0x01,0x16,0x8c,0x1f,0xc5,0xbe,0xbf,0x3a,0x54,0xdf}, 8333}, - {{0x2a,0x02,0x20,0xc8,0x14,0x22,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa3}, 8333}, - {{0x2a,0x02,0x21,0x68,0x0d,0x05,0x2c,0x00,0x02,0x16,0x3e,0xff,0xfe,0xf7,0xa0,0x99}, 8333}, - {{0x2a,0x02,0x27,0xf8,0x20,0x12,0x00,0x00,0xe9,0xf7,0x26,0x8f,0xc4,0x41,0x61,0x29}, 8333}, - {{0x2a,0x02,0x28,0x08,0x54,0x01,0x00,0x00,0x02,0x25,0x90,0xff,0xfe,0x4e,0xee,0x42}, 8333}, - {{0x2a,0x02,0x03,0x90,0x90,0x00,0x00,0x00,0x02,0x18,0x7d,0xff,0xfe,0x10,0xbe,0x33}, 8333}, - {{0x2a,0x02,0x7a,0xa0,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xbd,0x4e,0x12,0x19}, 8333}, - {{0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x90,0xeb,0xa2}, 8333}, - {{0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0xa7,0xa2,0x7e,0x86}, 8333}, - {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x05,0x08,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x05,0x20,0x02,0x25,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17}, 8333}, - {{0x2a,0x02,0xc2,0x05,0x20,0x08,0x02,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x05,0x20,0x10,0x54,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x05,0x30,0x01,0x67,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x05,0x30,0x01,0x77,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x02,0xc2,0x05,0x30,0x02,0x08,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x02,0x90,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x08,0x33,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x08,0x83,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x09,0x02,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x10,0x77,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x10,0x79,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x11,0x78,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x11,0x82,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x21,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x02,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x26,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x36,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x48,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x56,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x30,0x01,0x58,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x30,0x01,0x77,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xc2,0x07,0x30,0x02,0x06,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0xce,0x80,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x03,0x22,0x60,0x01,0x1e,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333}, - {{0x2a,0x03,0x22,0x60,0x01,0x1e,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, - {{0x2a,0x03,0x40,0x00,0x00,0x02,0x04,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333}, - {{0x2a,0x03,0x40,0x00,0x00,0x06,0x12,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x03,0x40,0x00,0x00,0x06,0x41,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x12,0x19,0x60,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x1b,0x99,0xc0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x1b,0x99,0xe0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x1b,0x9a,0x30,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x10,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x20,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x40,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x50,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x70,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x90,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x10,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x20,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x30,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x50,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x60,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x80,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xff,0xb0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0x30,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0x40,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0xe0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0xf0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x01,0xe0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x20,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x80,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x90,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0xb0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0xd0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0xe0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x10,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x20,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x30,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x40,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x60,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xa0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xb0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xe0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xf0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x00,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x30,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x40,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x60,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x80,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x90,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0xb0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x20,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x30,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x80,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x90,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0xa0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb8,0x90,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb8,0xe0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb8,0xf0,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x00,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x10,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x20,0x01}, 8333}, - {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x40,0x01}, 8333}, - {{0x2a,0x04,0x21,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94}, 8333}, - {{0x2a,0x04,0x35,0x42,0x10,0x00,0x09,0x10,0x84,0x92,0xb8,0xff,0xfe,0x91,0x71,0x1d}, 8333}, - {{0x2a,0x04,0x52,0xc0,0x01,0x01,0x01,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0xba,0x8e}, 8333}, - {{0x2a,0x05,0x35,0x80,0xd4,0x00,0x14,0x0d,0xda,0x6e,0x82,0x6e,0xe7,0x71,0x41,0x00}, 8333}, - {{0x2a,0x06,0x9f,0xc0,0x2a,0x06,0x9f,0xc0,0x2a,0x06,0x9f,0xc1,0x06,0x7c,0xe7,0x06}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd6,0xbc,0x4a,0x3c,0x6d,0x03,0xa9,0x4e,0x1f,0x55}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd1,0x62,0x6b,0xbc,0x9d,0x61,0xc8,0x63,0xe1,0xcc}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xda,0x0e,0x96,0xca,0xb6,0x16,0xef,0xe1,0xbf,0x4e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdd,0xbf,0xf3,0xc5,0x0b,0x37,0xa1,0xee,0x39,0xeb}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe2,0xe5,0xc7,0x79,0x12,0xc8,0x87,0xf6,0x28,0xb6}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe3,0xf6,0x00,0xa6,0xf0,0x7b,0xf3,0x74,0x7e,0x08}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xef,0x3c,0x49,0x0b,0xc1,0x74,0xc2,0x92,0x86,0xe1}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0x24,0x59,0xe2,0x79,0x5c,0xa4,0xa8,0xf2,0x93}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xec,0xf1,0xe8,0xdd,0xe6,0x8a,0x98,0x36,0xab,0x80}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x99,0x0c,0x51,0x03,0x89,0x7b,0xe4,0x3f,0x5e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0xce,0xb2,0x1a,0x69,0x50,0xd8,0x18,0x4a,0xb3}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x08,0x0a,0xae,0xa1,0xc0,0x9a,0xcd,0x3f,0x8c,0xcb}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0d,0x1f,0xd6,0xf4,0x9b,0x55,0x23,0x54,0xe4,0xbb}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x12,0x70,0x61,0xfd,0xf4,0xea,0xe0,0xa5,0x63,0xa9}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x16,0x2a,0xf3,0x4f,0x5d,0xd7,0xf8,0x8e,0x87,0xe2}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x19,0x14,0x9e,0x58,0x02,0xc5,0x9f,0x09,0x00,0x7b}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x1f,0x7b,0x2d,0xed,0xae,0xf3,0xb3,0xe5,0xab}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x41,0x1c,0xbf,0x02,0x0c,0xef,0x60,0x89,0x63}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x5f,0xc7,0xd4,0x89,0xc0,0x6f,0xa2,0x24,0x71}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0xd4,0xc9,0xb2,0xc8,0x87,0xc6,0x39,0x9a,0x8b}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x27,0x93,0xdf,0xe5,0x58,0x40,0x69,0xa9,0x30,0x03}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x22,0x45,0x02,0x56,0x89,0x14,0x17,0x38,0x37,0xe3}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x24,0x0c,0x19,0xe8,0xc7,0x2d,0x65,0x23,0x86,0xae}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x29,0x91,0x93,0x28,0x6d,0x68,0xd0,0xb7,0x79,0x40}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2c,0x2f,0x47,0xf1,0xc4,0xae,0xf6,0x42,0x20,0x66}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0x7b,0x87,0xc2,0x7e,0xd8,0xe9,0xbb,0x14,0xed}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0x87,0x8d,0x3c,0x3a,0x05,0x56,0x19,0xa6,0xd0}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0x0e,0x75,0xb8,0x99,0xc1,0x60,0x7d,0x9c,0x48}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x41,0xc7,0x5f,0x07,0x39,0xd1,0xaf,0xfd,0x16,0x5f}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x43,0x7f,0x1e,0xa0,0x8e,0xfb,0x8c,0xab,0x85,0xa4}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x55,0x47,0xce,0x4a,0xdf,0x92,0x83,0xd2,0xb9,0x76}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x63,0x7f,0xce,0x1c,0x28,0x70,0x30,0xdd,0xb9,0x32}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x64,0xb8,0xd9,0xc6,0x28,0x91,0x6f,0x97,0xd5,0x98}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0x57,0x0b,0x3d,0x20,0x0c,0x0d,0xed,0x20,0xf7}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x77,0x24,0xbe,0xb4,0x1e,0x49,0x20,0x64,0x6d,0x7e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x73,0x13,0x5d,0x71,0xa1,0x12,0xb8,0xae,0xd0,0x7e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7b,0xb6,0x9d,0x1c,0xaa,0x61,0x7f,0x23,0xef,0xce}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0x84,0xef,0x06,0xe9,0x25,0x96,0x98,0x8b,0x37}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0x3b,0x88,0xf9,0x75,0x58,0x95,0x92,0x95,0xd1}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0xeb,0xe7,0xe3,0xc7,0x1c,0xf2,0x87,0xb6,0x6d}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x86,0x1a,0xc7,0x98,0x61,0x7e,0xb7,0x7c,0x15,0xa9}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x89,0xe6,0x0b,0x0a,0x5f,0xb8,0x15,0xc3,0x23,0x73}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0x40,0x2b,0x4b,0xfd,0xf8,0x11,0xef,0x2e,0x24}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0x56,0xd7,0xec,0xf6,0xac,0x64,0xc0,0x3f,0xc4}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0x87,0x58,0x0a,0x33,0x2d,0x7d,0x89,0xf1,0xd8}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0xc0,0x54,0x31,0x42,0x9d,0x73,0xed,0xad,0x66}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0xd3,0xc7,0xbd,0xca,0xe0,0xdb,0x21,0xd3,0xad}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x91,0x1d,0x25,0x50,0x79,0x57,0xaa,0xdf,0x32,0x19}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x31,0x04,0x77,0xf3,0x2a,0x31,0xfb,0xee,0xaa}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x8e,0xe7,0xfb,0xfe,0x4f,0xb0,0xf7,0xda,0xcc}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9c,0x63,0x3c,0x3f,0x72,0x44,0x59,0x69,0xcf,0x14}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9d,0xf9,0x91,0xfc,0x7d,0x25,0xdc,0xd6,0x85,0x67}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa7,0x08,0x20,0xfe,0x77,0xba,0x3c,0xbd,0x99,0x17}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa3,0x05,0x71,0x30,0xb8,0x15,0x48,0x9b,0x6b,0xdc}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaf,0xef,0x01,0xf3,0x4e,0x11,0x18,0x05,0xd2,0x23}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa8,0x75,0xef,0xb2,0x7b,0x5b,0x6c,0x51,0xb0,0x61}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa9,0x2b,0xb6,0xf4,0xb7,0x2c,0x67,0x04,0xf8,0x9d}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaa,0x24,0x4a,0xc5,0x19,0xce,0xe1,0x4c,0x00,0xc9}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0xcd,0xe7,0xf4,0x9d,0x5b,0x77,0xb1,0xc2,0x6f}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xac,0x75,0x1a,0x02,0x48,0x68,0x0a,0xec,0x6c,0xab}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbf,0x9f,0x33,0xd4,0x7d,0xbf,0x80,0x1c,0x15,0xdf}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb8,0x6c,0x1c,0xc6,0x4f,0xa8,0x2b,0xfa,0x75,0x04}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb9,0x44,0x4a,0xb6,0x0b,0xd0,0x8e,0xd0,0x59,0x4e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc0,0x91,0x56,0xb9,0x9c,0xe0,0xd9,0x7b,0xf1,0xc1}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc6,0x47,0x55,0xd7,0xa3,0x02,0x26,0x02,0x91,0x4d}, 8333} + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc4,0x4d,0xc1}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xd6,0x9d,0x53}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x9d,0xb7,0x10}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x37,0xb0,0x1a}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x65,0x06,0xcc}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x69,0x37,0xd0}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xbd,0x81,0xda}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0xce,0x8c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0xfe,0xc9}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0x8d,0xe0,0x62}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xb2,0xb6,0x23}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x3c,0x9f,0x88}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x4d,0x7b,0x51}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x58,0x36,0x16}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x78,0xbc,0x52}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x28,0x06,0x0b}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x4d,0x2e,0xfa}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x4d,0x25,0x24}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x6c,0x8f,0x13}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xf1,0xd4,0xcf}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x1b,0x60,0x5c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x8a,0x58,0x64}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0xf2,0x03}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc0,0x40,0x88}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x15,0x90,0xe2}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xea,0x96,0xc7}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xc6,0xe6,0x8e}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x45,0x8c,0x44}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x98,0xed,0xf6}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x6d,0x70,0x5a}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x6d,0x70,0x5e}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x98,0x7a,0x84}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xf0,0x8d,0xaf}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xbe,0x8c,0xc6}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x55,0x2a,0xbc}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xac,0x18,0x4f}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xf3,0x26,0x22}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x2d,0xd2}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xbf,0x27,0xed}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x38,0xc2,0x9c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xc3,0xb3,0x3f}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xd5,0xde,0x6c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0xf3,0x99,0x9c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x81,0xd4,0xec}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0x0d,0x04,0x45}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0xf5,0xa1,0x8d}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd0,0xc2,0x5e}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd1,0x2c,0x22}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xd9,0xba,0x7d}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0xa4,0x93,0x52}, 21333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x08,0xa5,0x96}, 10333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x2f,0x3e,0x48}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xd5,0x7c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x42,0xfa,0x2c}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x57,0xb8,0x1d}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x00,0xb6,0x0a}, 9335}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x9b,0x88,0x15}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x03,0xa5,0x1e}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x0f,0x7f,0xf2}, 10333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x0e,0x9b}, 9333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x1c,0x60,0xb4}, 9333} }; static SeedSpec6 pnSeed6_test[] = { - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0xcb,0x26,0x31,0xba,0x48,0x51,0x31,0x39,0x0d}, 18333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x44,0xf4,0xf4,0xf0,0xbf,0xf7,0x7e,0x6d,0xc4,0xe8}, 18333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x8b,0xd2,0x78,0x3f,0x7a,0xf8,0x92,0x8f,0x80}, 18333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe6,0x4e,0xa4,0x47,0x4e,0x2a,0xfe,0xe8,0x95,0xcc}, 18333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9f,0xae,0x9f,0x59,0x0b,0x3f,0x31,0x3a,0x8a,0x5f}, 18333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x47,0xb1,0xe4,0x55,0xd1,0xb0,0x14,0x3f,0xb6,0xdb}, 18333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa0,0x60,0x9e,0x46,0x54,0xdb,0x61,0x3b,0xb2,0x6f}, 18333} + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xec,0xd3,0xce}, 19335}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xb2,0xb6,0x23}, 19335}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd1,0x2c,0x22}, 19335} }; #endif // BITCOIN_CHAINPARAMSSEEDS_H From 166fcb2aec9e22742f16dcd5cbe041632db4936f Mon Sep 17 00:00:00 2001 From: shaolinfry Date: Sat, 18 Feb 2017 11:13:07 +0000 Subject: [PATCH 151/196] Litecoin: Add scrypt N=1024 PoW # Conflicts: # src/txdb.cpp --- src/Makefile.am | 8 +- src/Makefile.test.include | 1 + src/chain.h | 5 + src/crypto/scrypt-sse2.cpp | 136 +++++++++++++++ src/crypto/scrypt.cpp | 329 +++++++++++++++++++++++++++++++++++++ src/crypto/scrypt.h | 45 +++++ src/init.cpp | 4 + src/miner.cpp | 1 + src/primitives/block.cpp | 8 + src/primitives/block.h | 2 + src/test/scrypt_tests.cpp | 35 ++++ src/txdb.cpp | 10 +- src/validation.cpp | 4 +- 13 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 src/crypto/scrypt-sse2.cpp create mode 100644 src/crypto/scrypt.cpp create mode 100644 src/crypto/scrypt.h create mode 100644 src/test/scrypt_tests.cpp diff --git a/src/Makefile.am b/src/Makefile.am index f7abab482e9e..5a994261f940 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -246,7 +246,7 @@ libbitcoin_wallet_a_SOURCES = \ $(BITCOIN_CORE_H) # crypto primitives library -crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) $(SSL_CFLAGS) crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/aes.cpp \ @@ -260,6 +260,8 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/hmac_sha512.h \ crypto/ripemd160.cpp \ crypto/ripemd160.h \ + crypto/scrypt.cpp \ + crypto/scrypt.h \ crypto/sha1.cpp \ crypto/sha1.h \ crypto/sha256.cpp \ @@ -442,8 +444,8 @@ if GLIBC_BACK_COMPAT endif libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) -libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) -libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) $(CRYPTO_LIBS) +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL $(SSL_CFLAGS) libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif diff --git a/src/Makefile.test.include b/src/Makefile.test.include index b48bfc76b785..e603d4b067ae 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -67,6 +67,7 @@ BITCOIN_TESTS =\ test/script_tests.cpp \ test/script_standard_tests.cpp \ test/scriptnum_tests.cpp \ + test/scrypt_tests.cpp \ test/serialize_tests.cpp \ test/sighash_tests.cpp \ test/sigopcount_tests.cpp \ diff --git a/src/chain.h b/src/chain.h index 1223539e7374..6320f4fd4195 100644 --- a/src/chain.h +++ b/src/chain.h @@ -294,6 +294,11 @@ class CBlockIndex return *phashBlock; } + uint256 GetBlockPoWHash() const + { + return GetBlockHeader().GetPoWHash(); + } + int64_t GetBlockTime() const { return (int64_t)nTime; diff --git a/src/crypto/scrypt-sse2.cpp b/src/crypto/scrypt-sse2.cpp new file mode 100644 index 000000000000..d9e7ffccc5f5 --- /dev/null +++ b/src/crypto/scrypt-sse2.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2009 Colin Percival, 2011 ArtForz, 2012-2013 pooler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include "crypto/scrypt.h" +#include +#include +#include +#include + +#include + +static inline void xor_salsa8_sse2(__m128i B[4], const __m128i Bx[4]) +{ + __m128i X0, X1, X2, X3; + __m128i T; + int i; + + X0 = B[0] = _mm_xor_si128(B[0], Bx[0]); + X1 = B[1] = _mm_xor_si128(B[1], Bx[1]); + X2 = B[2] = _mm_xor_si128(B[2], Bx[2]); + X3 = B[3] = _mm_xor_si128(B[3], Bx[3]); + + for (i = 0; i < 8; i += 2) { + /* Operate on "columns". */ + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + + /* Operate on "rows". */ + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + } + + B[0] = _mm_add_epi32(B[0], X0); + B[1] = _mm_add_epi32(B[1], X1); + B[2] = _mm_add_epi32(B[2], X2); + B[3] = _mm_add_epi32(B[3], X3); +} + +void scrypt_1024_1_1_256_sp_sse2(const char *input, char *output, char *scratchpad) +{ + uint8_t B[128]; + union { + __m128i i128[8]; + uint32_t u32[32]; + } X; + __m128i *V; + uint32_t i, j, k; + + V = (__m128i *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128); + + for (k = 0; k < 2; k++) { + for (i = 0; i < 16; i++) { + X.u32[k * 16 + i] = le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + for (i = 0; i < 1024; i++) { + for (k = 0; k < 8; k++) + V[i * 8 + k] = X.i128[k]; + xor_salsa8_sse2(&X.i128[0], &X.i128[4]); + xor_salsa8_sse2(&X.i128[4], &X.i128[0]); + } + for (i = 0; i < 1024; i++) { + j = 8 * (X.u32[16] & 1023); + for (k = 0; k < 8; k++) + X.i128[k] = _mm_xor_si128(X.i128[k], V[j + k]); + xor_salsa8_sse2(&X.i128[0], &X.i128[4]); + xor_salsa8_sse2(&X.i128[4], &X.i128[0]); + } + + for (k = 0; k < 2; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], X.u32[k * 16 + i]); + } + } + + PBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32); +} diff --git a/src/crypto/scrypt.cpp b/src/crypto/scrypt.cpp new file mode 100644 index 000000000000..887f58770d19 --- /dev/null +++ b/src/crypto/scrypt.cpp @@ -0,0 +1,329 @@ +/* + * Copyright 2009 Colin Percival, 2011 ArtForz, 2012-2013 pooler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include "crypto/scrypt.h" +//#include "util.h" +#include +#include +#include +#include + +#if defined(USE_SSE2) && !defined(USE_SSE2_ALWAYS) +#ifdef _MSC_VER +// MSVC 64bit is unable to use inline asm +#include +#else +// GCC Linux or i686-w64-mingw32 +#include +#endif +#endif + +static inline uint32_t be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void be32enc(void *pp, uint32_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +/* Initialize an HMAC-SHA256 operation with the given key. */ +static void +HMAC_SHA256_Init(HMAC_SHA256_CTX *ctx, const void *_K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char *K = (const unsigned char *)_K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Update(HMAC_SHA256_CTX *ctx, const void *in, size_t len) +{ + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX *ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} + +#define ROTL(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) + +static inline void xor_salsa8(uint32_t B[16], const uint32_t Bx[16]) +{ + uint32_t x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15; + int i; + + x00 = (B[ 0] ^= Bx[ 0]); + x01 = (B[ 1] ^= Bx[ 1]); + x02 = (B[ 2] ^= Bx[ 2]); + x03 = (B[ 3] ^= Bx[ 3]); + x04 = (B[ 4] ^= Bx[ 4]); + x05 = (B[ 5] ^= Bx[ 5]); + x06 = (B[ 6] ^= Bx[ 6]); + x07 = (B[ 7] ^= Bx[ 7]); + x08 = (B[ 8] ^= Bx[ 8]); + x09 = (B[ 9] ^= Bx[ 9]); + x10 = (B[10] ^= Bx[10]); + x11 = (B[11] ^= Bx[11]); + x12 = (B[12] ^= Bx[12]); + x13 = (B[13] ^= Bx[13]); + x14 = (B[14] ^= Bx[14]); + x15 = (B[15] ^= Bx[15]); + for (i = 0; i < 8; i += 2) { + /* Operate on columns. */ + x04 ^= ROTL(x00 + x12, 7); x09 ^= ROTL(x05 + x01, 7); + x14 ^= ROTL(x10 + x06, 7); x03 ^= ROTL(x15 + x11, 7); + + x08 ^= ROTL(x04 + x00, 9); x13 ^= ROTL(x09 + x05, 9); + x02 ^= ROTL(x14 + x10, 9); x07 ^= ROTL(x03 + x15, 9); + + x12 ^= ROTL(x08 + x04, 13); x01 ^= ROTL(x13 + x09, 13); + x06 ^= ROTL(x02 + x14, 13); x11 ^= ROTL(x07 + x03, 13); + + x00 ^= ROTL(x12 + x08, 18); x05 ^= ROTL(x01 + x13, 18); + x10 ^= ROTL(x06 + x02, 18); x15 ^= ROTL(x11 + x07, 18); + + /* Operate on rows. */ + x01 ^= ROTL(x00 + x03, 7); x06 ^= ROTL(x05 + x04, 7); + x11 ^= ROTL(x10 + x09, 7); x12 ^= ROTL(x15 + x14, 7); + + x02 ^= ROTL(x01 + x00, 9); x07 ^= ROTL(x06 + x05, 9); + x08 ^= ROTL(x11 + x10, 9); x13 ^= ROTL(x12 + x15, 9); + + x03 ^= ROTL(x02 + x01, 13); x04 ^= ROTL(x07 + x06, 13); + x09 ^= ROTL(x08 + x11, 13); x14 ^= ROTL(x13 + x12, 13); + + x00 ^= ROTL(x03 + x02, 18); x05 ^= ROTL(x04 + x07, 18); + x10 ^= ROTL(x09 + x08, 18); x15 ^= ROTL(x14 + x13, 18); + } + B[ 0] += x00; + B[ 1] += x01; + B[ 2] += x02; + B[ 3] += x03; + B[ 4] += x04; + B[ 5] += x05; + B[ 6] += x06; + B[ 7] += x07; + B[ 8] += x08; + B[ 9] += x09; + B[10] += x10; + B[11] += x11; + B[12] += x12; + B[13] += x13; + B[14] += x14; + B[15] += x15; +} + +void scrypt_1024_1_1_256_sp_generic(const char *input, char *output, char *scratchpad) +{ + uint8_t B[128]; + uint32_t X[32]; + uint32_t *V; + uint32_t i, j, k; + + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128); + + for (k = 0; k < 32; k++) + X[k] = le32dec(&B[4 * k]); + + for (i = 0; i < 1024; i++) { + memcpy(&V[i * 32], X, 128); + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + for (i = 0; i < 1024; i++) { + j = 32 * (X[16] & 1023); + for (k = 0; k < 32; k++) + X[k] ^= V[j + k]; + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + + for (k = 0; k < 32; k++) + le32enc(&B[4 * k], X[k]); + + PBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32); +} + +#if defined(USE_SSE2) +// By default, set to generic scrypt function. This will prevent crash in case when scrypt_detect_sse2() wasn't called +void (*scrypt_1024_1_1_256_sp_detected)(const char *input, char *output, char *scratchpad) = &scrypt_1024_1_1_256_sp_generic; + +void scrypt_detect_sse2() +{ +#if defined(USE_SSE2_ALWAYS) + printf("scrypt: using scrypt-sse2 as built.\n"); +#else // USE_SSE2_ALWAYS + // 32bit x86 Linux or Windows, detect cpuid features + unsigned int cpuid_edx=0; +#if defined(_MSC_VER) + // MSVC + int x86cpuid[4]; + __cpuid(x86cpuid, 1); + cpuid_edx = (unsigned int)buffer[3]; +#else // _MSC_VER + // Linux or i686-w64-mingw32 (gcc-4.6.3) + unsigned int eax, ebx, ecx; + __get_cpuid(1, &eax, &ebx, &ecx, &cpuid_edx); +#endif // _MSC_VER + + if (cpuid_edx & 1<<26) + { + scrypt_1024_1_1_256_sp_detected = &scrypt_1024_1_1_256_sp_sse2; + printf("scrypt: using scrypt-sse2 as detected.\n"); + } + else + { + scrypt_1024_1_1_256_sp_detected = &scrypt_1024_1_1_256_sp_generic; + printf("scrypt: using scrypt-generic, SSE2 unavailable.\n"); + } +#endif // USE_SSE2_ALWAYS +} +#endif + +void scrypt_1024_1_1_256(const char *input, char *output) +{ + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + scrypt_1024_1_1_256_sp(input, output, scratchpad); +} diff --git a/src/crypto/scrypt.h b/src/crypto/scrypt.h new file mode 100644 index 000000000000..5431fb67ceeb --- /dev/null +++ b/src/crypto/scrypt.h @@ -0,0 +1,45 @@ +#ifndef SCRYPT_H +#define SCRYPT_H +#include +#include + +static const int SCRYPT_SCRATCHPAD_SIZE = 131072 + 63; + +void scrypt_1024_1_1_256(const char *input, char *output); +void scrypt_1024_1_1_256_sp_generic(const char *input, char *output, char *scratchpad); + +#if defined(USE_SSE2) +#if defined(_M_X64) || defined(__x86_64__) || defined(_M_AMD64) || (defined(MAC_OSX) && defined(__i386__)) +#define USE_SSE2_ALWAYS 1 +#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_sse2((input), (output), (scratchpad)) +#else +#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_detected((input), (output), (scratchpad)) +#endif + +void scrypt_detect_sse2(); +void scrypt_1024_1_1_256_sp_sse2(const char *input, char *output, char *scratchpad); +extern void (*scrypt_1024_1_1_256_sp_detected)(const char *input, char *output, char *scratchpad); +#else +#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_generic((input), (output), (scratchpad)) +#endif + +void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen); + +static inline uint32_t le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void le32enc(void *pp, uint32_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} +#endif diff --git a/src/init.cpp b/src/init.cpp index 5196eee9535f..34a9b49c8f19 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1272,6 +1272,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) int64_t nStart; +#if defined(USE_SSE2) + scrypt_detect_sse2(); +#endif + // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET if (!CWallet::Verify()) diff --git a/src/miner.cpp b/src/miner.cpp index 9d571a2eb022..adfedcc25435 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -14,6 +14,7 @@ #include "consensus/merkle.h" #include "consensus/validation.h" #include "hash.h" +#include "crypto/scrypt.h" #include "validation.h" #include "net.h" #include "policy/feerate.h" diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 3774ac3e4b54..454f10ed3d22 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -9,12 +9,20 @@ #include "tinyformat.h" #include "utilstrencodings.h" #include "crypto/common.h" +#include "crypto/scrypt.h" uint256 CBlockHeader::GetHash() const { return SerializeHash(*this); } +uint256 CBlockHeader::GetPoWHash() const +{ + uint256 thash; + scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash)); + return thash; +} + std::string CBlock::ToString() const { std::stringstream s; diff --git a/src/primitives/block.h b/src/primitives/block.h index c90a1dfa6448..fe51b8a7297a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -62,6 +62,8 @@ class CBlockHeader uint256 GetHash() const; + uint256 GetPoWHash() const; + int64_t GetBlockTime() const { return (int64_t)nTime; diff --git a/src/test/scrypt_tests.cpp b/src/test/scrypt_tests.cpp new file mode 100644 index 000000000000..2d7f19e4d3cc --- /dev/null +++ b/src/test/scrypt_tests.cpp @@ -0,0 +1,35 @@ +#include + +#include "uint256.h" +#include "util.h" +#include "utilstrencodings.h" +#include "crypto/scrypt.h" + +BOOST_AUTO_TEST_SUITE(scrypt_tests) + +BOOST_AUTO_TEST_CASE(scrypt_hashtest) +{ + // Test Scrypt hash with known inputs against expected outputs + #define HASHCOUNT 5 + const char* inputhex[HASHCOUNT] = { "020000004c1271c211717198227392b029a64a7971931d351b387bb80db027f270411e398a07046f7d4a08dd815412a8712f874a7ebf0507e3878bd24e20a3b73fd750a667d2f451eac7471b00de6659", "0200000011503ee6a855e900c00cfdd98f5f55fffeaee9b6bf55bea9b852d9de2ce35828e204eef76acfd36949ae56d1fbe81c1ac9c0209e6331ad56414f9072506a77f8c6faf551eac7471b00389d01", "02000000a72c8a177f523946f42f22c3e86b8023221b4105e8007e59e81f6beb013e29aaf635295cb9ac966213fb56e046dc71df5b3f7f67ceaeab24038e743f883aff1aaafaf551eac7471b0166249b", "010000007824bc3a8a1b4628485eee3024abd8626721f7f870f8ad4d2f33a27155167f6a4009d1285049603888fe85a84b6c803a53305a8d497965a5e896e1a00568359589faf551eac7471b0065434e", "0200000050bfd4e4a307a8cb6ef4aef69abc5c0f2d579648bd80d7733e1ccc3fbc90ed664a7f74006cb11bde87785f229ecd366c2d4e44432832580e0608c579e4cb76f383f7f551eac7471b00c36982" }; + const char* expected[HASHCOUNT] = { "00000000002bef4107f882f6115e0b01f348d21195dacd3582aa2dabd7985806" , "00000000003a0d11bdd5eb634e08b7feddcfbbf228ed35d250daf19f1c88fc94", "00000000000b40f895f288e13244728a6c2d9d59d8aff29c65f8dd5114a8ca81", "00000000003007005891cd4923031e99d8e8d72f6e8e7edc6a86181897e105fe", "000000000018f0b426a4afc7130ccb47fa02af730d345b4fe7c7724d3800ec8c" }; +#if defined(USE_SSE2) + scrypt_detect_sse2(); +#endif + uint256 scrypthash; + std::vector inputbytes; + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + for (int i = 0; i < HASHCOUNT; i++) { + inputbytes = ParseHex(inputhex[i]); +#if defined(USE_SSE2) + // Test SSE2 scrypt + scrypt_1024_1_1_256_sp_sse2((const char*)&inputbytes[0], BEGIN(scrypthash), scratchpad); + BOOST_CHECK_EQUAL(scrypthash.ToString().c_str(), expected[i]); +#endif + // Test generic scrypt + scrypt_1024_1_1_256_sp_generic((const char*)&inputbytes[0], BEGIN(scrypthash), scratchpad); + BOOST_CHECK_EQUAL(scrypthash.ToString().c_str(), expected[i]); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txdb.cpp b/src/txdb.cpp index 4c1b04cd945b..1c76b682703a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -287,8 +287,14 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) - return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString()); + // Litecoin: Disable PoW Sanity check while loading block index from disk. + // We use the sha256 hash for the block index for performance reasons, which is recorded for later use. + // CheckProofOfWork() uses the scrypt hash which is discarded after a block is accepted. + // While it is technically feasible to verify the PoW, doing so takes several minutes as it + // requires recomputing every PoW hash during every Litecoin startup. + // We opt instead to simply trust the data that is on your local disk. + //if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) + // return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString()); pcursor->Next(); } else { diff --git a/src/validation.cpp b/src/validation.cpp index 8a92992dba77..4b286abab90b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1022,7 +1022,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: } // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) + if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams)) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); return true; @@ -2803,7 +2803,7 @@ static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) + if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams)) return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed"); return true; From dd764bb478dde9524c89a98e830694dff2a029f6 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 15 Nov 2016 00:45:56 +1100 Subject: [PATCH 152/196] Litecoin: Add Litecoin logos and icons # Conflicts: # share/pixmaps/nsis-header.bmp # share/pixmaps/nsis-wizard.bmp --- share/pixmaps/bitcoin.ico | Bin 68756 -> 89957 bytes share/pixmaps/bitcoin128.png | Bin 10639 -> 16408 bytes share/pixmaps/bitcoin128.xpm | 599 +++++++------------ share/pixmaps/bitcoin16.png | Bin 827 -> 951 bytes share/pixmaps/bitcoin16.xpm | 321 +++++----- share/pixmaps/bitcoin256.png | Bin 28182 -> 39906 bytes share/pixmaps/bitcoin256.xpm | 845 ++++++++++++--------------- share/pixmaps/bitcoin32.png | Bin 1982 -> 2624 bytes share/pixmaps/bitcoin32.xpm | 231 +++----- share/pixmaps/bitcoin64.png | Bin 4592 -> 6681 bytes share/pixmaps/bitcoin64.xpm | 380 +++++------- share/pixmaps/nsis-header.bmp | Bin 25820 -> 25820 bytes share/pixmaps/nsis-wizard.bmp | Bin 154544 -> 154544 bytes src/qt/res/icons/about.png | Bin 3717 -> 2960 bytes src/qt/res/icons/bitcoin.icns | Bin 919273 -> 422514 bytes src/qt/res/icons/bitcoin.ico | Bin 57964 -> 65303 bytes src/qt/res/icons/bitcoin.png | Bin 312944 -> 133328 bytes src/qt/res/icons/bitcoin_testnet.ico | Bin 57251 -> 67293 bytes 18 files changed, 989 insertions(+), 1387 deletions(-) mode change 100644 => 100755 src/qt/res/icons/bitcoin.png diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico index f5480f41616a81cc3b65d0625f4f5e6f01a2f861..37533703f76aff466fc74158119db10474279fb0 100644 GIT binary patch literal 89957 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%0D%_iEz7^_~hg4?7T(nOcS4t5^LRG z;k+g}u7!t(Yu|qRt+r&z5^e3;wc6&*o3(A*wrM+e?$nQ;fBsq9v}u#JX3ZKcHa1q9 zF=K`{V#EkdVy=04d1-Chw9&DE8^WhlcqKTvg2Vq6AA0xhZ6R@N>f++ELSmKHq)8K_ za8?t(YVw{oapFYn#~**xcJ11w9X@Uk`rg^)qMA zXs1uhpQ4^Pp&dMUP}{zJyS9A!a&6qWahhm>CUa?E3&w)O6Pasy=gyrQNM7XsQ_=co zE;13$mh|-W94h|a5LS!GZ;POphHqru&PZmoHz|u3fvP-Mo2IyM6n% zmYkfd-MMq;HwUlZx^+vtapQ(|_3Bma(xpo}Cg1^naAfxE*_zY~&CShCv$eGahaB=k z^l||C_s_WZ{!zqdGqg?S{89Al6*kCgTEBk%v_*>+X?yqX)lQu{rN{Nkl`Fcx_?eQD zqCI~6SbO^Psg|Ceu04PLTzmQQ<*&z!7ccbJ)6&wkCr_Se4csJ2I}h4~m;Wx1+cEl2&@daNqGBWhz*|TTby?ggGuz~Av1fTGY`|z1-UcGvyAN&k% z+ygh@5!Z6xmMvTKynuJ)1ocIDahRO^>8GE}{=TQbzmxnD-`$1pSIIpzx^LgU+OlQK zbZ#p9;q`+D4|E^!nHXa?8Zc|tEN#e;A$lI8^}<!L!oqZa2M->sYdtjr z-y#t_;6iM&;Ymq7VzQj-MhM;pqWRH9@SQ_UaiN2x=DQK8^C~k{p%k8 z>khHoRBCQZ$*(J5D}9=7AG!>G;W07CCKV_ACMLvi$BrF3zj+M~EMB}=uZ3_2%|I`~ z65mIU9<7ZZKVHu#>4o)rNzJ5=j2bmc|DBjCt$=56>*B?WI@Z)rFmrTt)G>euQX87$ z!@oTGOFx+ihF?i9b2zW>yLa!_eMis9OJbdwnW^Xe_uqf7`wlNveIqx}MDqO5p+g$? zQx_*so~-*ttcm&9v17I9=xA-~)T!FcnKLys4h+dLY9POl88b%znfNO%pf%(Jb8OwZ z^*0!x2U0hy{w1&9UM#+s6h5s)>!e55xk%4~Kln~AqUC56dNgIq6uqy(7T)JfU56)V zBRr+1@7uRe+p}knu9=csx?lKB>}6e~5qq>^{`~oRF9fD5SFY6iCVD4oAUTB{N*Cau z!hpPlTj+t*r#F(XOGR6X{}l{`GX(^@k&;WV=v&bx_=PXjBXV8UFmxCVBcI_tx`p5H z5*t-NLk-`*f4}}dxj+sPFYH~lYLy;q`aXQaN5(=we)!=BJ-;_>*r4|Ss^=iMGbiJ)o{$)7^hi=;>i-!Ihz}*Cwyz`S1qU7HBS((t{Gyjp^_h6^ zKE89v8cqK_Z(XDJC%4IG?4dU#kMWJyh&6G9_v8S5E;+7h0NRN5$^L+z7jx#!(Z?Yl z;^N};e400Jp3W;UK!>SC)CIW4c<@(x^Bl>8@7}H#-U|a-DScFkVD?;Uh#pJ$2A|Pd zYA{-dzTqeJ44zRJz`1VSy82PCUOkQDn{U3+>esKYHEh^W6F%wdK+#i;gEb8~O79HM zgs1wN56;q8aySxa6Ha!Tnj(UO~aRvkG0{n!h^d;m0d}G}$7#c;#*9;vxlr`h;{sR|@y*w*qZ9NS>?a5ZQiTKU#QERt9Z24PDD`f& zaL!2V=~dtm^D`d2M+eX(YCH9YGuIFo8CUONm|yv&)^y4j9+4i2xKKk?j|9fd!M)TI){JNxYi7xF_K|+`pV(ht^5hQr zg@&W6D)#t9?xSCD4g1yl6pVQd8`#r%^yrZua~0#fu~j(WgNmoZg1NvGEWm+r@dX^{ zAINjC;C<#M{^-uYfdh4WW#3KDMeHC4;2`{A9QaC}q9@WHUKiY|<#nDOUvgxmVETqV z8+tJ2BVO=V#hzXaOgXSu#f#X$7wq9R>apTHe1{L@5Lm!*j=Wef554psVS%oxdEf>9 zFgARn-$#SMfF6bVi#CE8^?-T7iuh0qxL#tMDRrxBULBNmSrN&NpV3M59F1XK_)C9F z{HZ-?5iw#+;(#sK1jopIY9KkNdQ-&(?9H3^N=x9BI*3V(}j}D)vN0@ot%Tu=q{SZegIm6ALK246uyBK zesWOPc@O^MKWDDtHTph!O_c-WDm@EpEqVy)HJ-|RE%Be8NB9sDN>rhyUm)`Jj3^beGtPwrYZ-uG8Sg{NxV)DjeVhKcj*4LHNwt58VP^>Nquqy<)ZY zV+}xF(QlK3=sz4}PmtePD~TV!_9OIW*ai>b9J&HW8K1t6b&Ec=Jcb~CVCTkT(k}SR4%R4d-n`MkAUiu-#{nLJh2jJ? zh4Ij2_yd;U3XaSLu8dEwkN@NgzB4x5X6?s%nx24KrD_8;lWXXW&@VU)mw8>S*XY&g z1;zh@Jiid#Kfrz_d4wO-H*y%8;R0j9Nn#K8u@&3k9s3ycm&6dCb8>RD+}vEvXf*0) zepfh<6AA}@1}pl0=}CVb8~@<|7^rm-IFSSJo!Fx{d1H^h;~zSw`Up6LhQT$Zfvn+K zvrspL2S;U|PlUVW#D+w)pB!dv@`YZN7=bOdgR#LKUg9?xFbB4wS#X)T@Rb8B-o=5} z-~+yMz%hAlq-!1cF&6%-bs_6$wKsxBfHj&xt-*g{PhP`qG)whHV1RAZaP)^<=I6Y9 zkobQ=`sniFb7kTGZFGVCS@Mcr1l_=Y@{2tf)ti6=b5rlhCvf0C_TAtK_J9MvsskMI z9=r}lZ~^Tg2N;9<;XMbws`!&1_|N`mgyc|dJ)BS*1L-PaD%lu{)08XV>dk!JrKW>H(U>onV0+r3-k|ezSX}Ia$QO4pVYoM z?B#wiQoS#>-jaPEa*;UWyNW$_@)~^=ngIvMFYbpg^mN>ZPt;)g2x<}9pl~2R6c_UH zf%wuF!C`758~_V^SKL>zSN$;llY`_BT1+p4zJfhIU^|+{`iS}`7_S$;7m{)Fi}o*O ze}Mbwf6x!sYuHKO3g_T9wV3)t+~Gd4hi}B5noIogpX;y(tht|D;&>MaxJgc6BQfG< zaNvG&2;E_P=A{0S>)4Vv_T+5d{+Hf|dFj^~7u?B1`U7~(^Fr~TXF1cwcRr6~D!o9I zjg3t%wUKo!T%l$XD>#7fdli#dE(PV6Ay@4iD$LU|lE$Q{&i2q^q zzpMddE>FSa6`Un^&^G#WVn=AFMeYi{UbF2tk6{Uh8PDtsYCFJ zzD(i3d)Nq8wQJYbbrT+vi_~2>My_E$x~aTyDL z!4xjhqmh#e2k_x_@JEB-0yPvr=qunO+D;xv=P>$U>78bQinn1G$%6Wh^vH_27BAPppYMzQcd~N54797c_v^;JV`NyRics zG=Q4V{M2_<@6mgB$2`OU9N@l+eO@fl1mXgp(0=&EwbUi*5k010d|P5%N5x*9C2xvK ztoRI@-iP52_mZ!ShYpgD^rZNMJ;YyepX=%2h&{b82k*ltcmsa$K;`he9ENAai212$ zd3!y2UB)24SsRio#F+TQdt%Se%*X3!7WEchpc`O<7E$*^<5>6p%6;WOd=Tt|WDocS zHBx@pHIwn-Cma9=xX=9bJm@@r6aT!i$9H%O9_S|fj>H1~zN_Vm6VwIjC%qXOM%?lD z-ChrDsFT!VG>7_t@6;b`L9d8Cx<|gDjr57=zKs1$G{7tG-mmhXv-AyRqz^hm9%2JN z5hpmHbO7G5HiwJwjot@5@Rj+AKRpz6fHUh?*4ES??BtB5g9EWrHBIptJK0CVZ+gAF z{^PgmbydCRHS&@=2*&iA)GZZzIDrNed$D7y-2dLs$;q17Ox6XxLSy;5~6dPsm;P#64)R)RuI~0pIt{i&(RKK%aNvFLqW44l!I&I?zr-0|^7i?R z3s>MD`KfphN8uRj58^1X&lOD9{kzyJ|G`K0^V$ms9-!Uu3?7pQN~gh@o`4v`JGDQ@ z8C-ase87KtPWk|PE9xEj4)4KKaUWe^eAWQ)f*OFPfD3&b946oKpT3Y@kM#|jMx7xZ za1;E{E5?O`;KRB`;(1r%+FX46-E&XnciywiQ%L&p7{M(YErf&A5cGr`qjzTw3kKvl z>oaNsu}AlaKl9^1@#KDVoon#*j}Fz>zzy<+*b_r|Oua-e7@wHZ=hDkCH@rc&oZx%|LJGJtGwX0P5MP6H4OaGQZx(<$TN7r-0+`1m%UMZB=%@C zy&?Wnzlo{fsUN~E{n-s#&;BQUF9&(b8Q$SP@z2{UfIq&`8(|B%h~ATza0?E>7jzR0 zWu9EYV1wXQ`ak*m?)&6{@T;l#e@<{PqBGQIRd2w6o`t-F3)soNC4CD$GQOjEtQF7+ zv-{S?Drn;z_-u$L3n@VI2jJ8JB~3$pgkj+nE#26L;l1I!v6%d9W2MPf8r? zif@04_wQmLJ%G7rfs3q{l8FoX1O{jq8iO97*~EalKwgk1#0P)iD*2C=p%c_X-UB1v zCoj|<4rktnKjZ*CKL-(-nJ0yQY1lMG80nQRTv<{Ba zA5h!jf{G8e@-rAw6W{_pEcy-K)gG0~2Xca+c^|#t9<&CHh3n`HngiDG9W6i;(Hd$a z`XZb+ik@5(9K57PSiH}lzwu?E8LD#qkJ`rzXkKg1QSW`dfKhX+seES)Vq6)& znQ&mc#SBAyBtb>=nR;~HX)&)~?qfOR;2qwn;N z)E4xD-iNv>YnDvGV3X)+U9s^u>)LmH_y>OHbJ5n)OHURI9!P&-SdV}QK7k2w#z)Tl4mZ$pu7N}NOn$?2avZ+kH+e3auGdI8-{K4?Y#& z{+7=F9ZcwvL|>f*|DA$EhHygHAD&@Q>)0ouR@2X6KQ#I%7p zu7D%GEj>8##&7m8czz{wzLaN8KMMz1{ng&)@A&&i_s}CqANHxNnfeG0$KWCTCcQ2i zN#Bc3Qu~OV+A}7WXgb(%@H71kT7d3R@8|{4OYmerlU|OxCNX~{bL|(-g-Sgx^`F)= ze`NPR{Telveo@XnrAF=$9eyZ%XAZf^T8^5GzN>v*)qaP_`mkwtC77xIKYmw2)- zz`-+9dJB4CxJ_Quw+ol<$hCW=?nDWGHli^_{~zeve+z?tzpT&lNjyu?e@d+k7CfRw zqgTRR@%54%w*`xPve$A~eB`tC7v!~l!k6#G-|@m3f2l2BfhTq6A2I6xa1i*4P7y=t z^~%aoS^9_S9Q-U;l@ZOb5?>4azl^cyN4%N*Pt$S?1{=;v27?9XNU0`rG6GtJ{ zGk!0xU#4Fe&+jrqBxkvSlfm%IZE~ZG%75x?ll9B*<@I4?ptt8DNx!^qq0aHY{BHK{ zIr5j+P2P9@289ex7v%l-etIi42; z_ax2|FnypR|B91}n~LMFaaD2tCGLDr#8+~3kVAb>MC9l4%m3&(ni*dQfP;PXhw5q1hh+ZD_zbnIYh^viKg8VJwGdYw^8=-A_D_Ev<(%17~@Y(_77ep8eGuZ zze7`JSJx?G*IB72FQmTYitTz`W(~t01br0;{WQHS>j~;QEM4PVs*#W-F<$r{LMV|=?^FW?_OljsEo6-Yn04KP1Dzj^uz3DvQNf3kN%ck z_}xC3wF3PyJuvGB*0=P8?EBCo(O2S!@a&eiuWva0pP2iP^!(H(FF(J=ZS3uLO5C$q zPt%{V#%CXrbqIYr`wpyASi7*sWv#~Ajx+0h)_SaI*o$Qih>xt>=yQn+eINXiIkMWz zcScBj>Y)k$4eZ3yRSXt>CrTa~>6yWdIn_QDHe;_^PlGjn!5Q|gIoQ)-ZH}M#hhJ*X zf!Bx|y*m4I^!GBKQF8sFZ$Lo%znkCK?(XRsEO^`n7xshTF!5)7#Cj2Iv7Pye2RR`3 z={+_3QS{ZUHF!1vPvAX!Y3xID5BGAgwj>^`tyqh2J$WvAAp1puo`2N`IOFE#<&N#F z%h-Qo?+(ma?=mO0Gavbi?c^!X>ewsBSNeYTZ?IYB*Z0R*`>_A3K6Ahx7;8xQ1-DpF z;}@}Gjf9@zgRie1hd;|Do^v#YGwfrqCr50_Ke$Wm*?Ryd)}YK!4iFb|7;Z5?Yc=-y z*w4d%aL0E1H)q4f|E#$^Br#z7unyC)8RvNzLJB4&uSV z`|RPeUdKkx9K?)+_rQRIeK8JRSNF01!5*f{2ll_vCH6tt=YdBqE^hN!FTLx7hmVh) z^dyhLl9+*k+II#U>Lq*yFKj38s7YKyZoo0}n}e8fz+-rT|I{q>g#%pj?opAi^he}4 zw!%lWffz6jJRmMSd!pB%U&?DgoU(7*_FKU<7wpMH=7cwB3S;39^Y9*d2p-fT##c6C z8+K8{z)kI&k>BJx+$PU?#>%*iMVzT&?60#QL!5bDMQ(8&7%?8)qDB(~HxCc}Z$y+2 zLGqa~!Tu7wC$F%T*x^61B&OJc4a`qXCGOw|{$P&&fj53DjIm4kq5NkI@MKK5jUQ+j z`on$+&r7Hqj886MKN#UVwV!YKyHtHb|G*DzV_xRu z*%NqiEk06v^6t~(5A!Nc;agrlsdy<)@jKinugDF2V0>~4yNNSCqEYnY5`%PK-@vvQ zFWfeBkZ023yAl3@FZ1zS0S)4L5w(Weiaw%4)H7-T{W90#1O1HhgV+%R@{`V@zFyuhB%OTbBZ%l)-^X)!as`{jg8l-{ z#V6_kcrpf`nF9mr7&(Q;kw?T8ZG)3&4>6{mv9FAlpt;xtKhY0#h&2;A;NPWhDOWH5 zIuehE^v3kLa333ZX2bnp!o1kdflu@$XeROG%xBg4+&+Hr+#5ge2i+nD#1Q}Sfm+3w z*vI>D8hhbC8pD|A4!q|~yvaG@3Z~R_bP641PrzHA#mibSjd(EzImP^FFnuMTIiXL) zcJ-M9>MuEm-Fg4^MESw9CwyT(cnN2SA@<`798vuo{HBLsZu%4QiyTC!&@3<|CU62R z_VDd5>$~^+Ww_89AZW z0q_pKbD#;>PkxaTd`^WP0c@!U@EpxUbBGOC!by0ImSHXKNt{`y!pY{aF1v9E+AqgPq-KVi6I9+qaR=jUsaz#?Lx1qfy9EG7mfZ^d(j|xh}IBS z@``$ZU-$u+!5&Q~CX7Q*LjQse(kIE@*OneVA_~(#w6?dOE_)0{@)E9dEjf(MXa)A8 z53HN0z4%EDV*Nxtp-$2#VL$Z)4WO6fcjg9b*5Y7~?f8w(U^{t5e6WqVi7(^Bf3Rmx zFknplC0_)4qwLp>m231hy{oH-zw{89j1Mm4Fgd^+=!4RJ{2|`xD06V|J8=g$?1iJ~ z9DOw7;0HdDw_L{<@P=HXK9OJ8jmDuB)C~B-Ys`y(s)t4ch>7$I^1Y0H&Z>X*4h*a; z>&DBhGtoP2fI}SU8S$rvfjxX7C%_x*;S_PBrZ6wMjUDii-{C!ZL484U!4K`BrlZAR zgst4iJGW62QRoUSfBIj)Tz9(UvkAlIJ8jKm`1c2pUFowgm}VBY*yGS z`>~xl@Qa!ZPp}Shy(dXju3xxS#cX|d5s)p?E#0d zBk!6X&4GW!nK{sBatj?Kc3?t{K{uuDrpO++jly1?B?ceLzR!B;?TqLd^V8#y2XGnQ zGA;7^^PmSP8fV=Medw;6|c@H%yvH38V?tyfC#={0#D-6m%6p1J9Zs1w2) zW7~G^mJ0U2`<@-~!^GLmt&QxnJfvsAHu#AD)KoAf2he>Ee86sE!2!p}0eAx!=*Osa z%uVd!0Nf`Js9(fD)hng<=op%h&)^1r#1G!m$BORU^$QAWrZ9i^EI3%ArP5o!L5rxd z;D!d03*d^DvQB`X#FQLBkEj!94Dlxii8=K~HKj;6GzicZfL{;3r%YJdJ{DoaooDn)5F9d44x>adB@g8Y}z0 zzIv?T4n7bExI|1?3(&uj7tD`V!&}vtvNuQ1NnOWgdNXu~`^XLKM_-5|IYe)S?Pw*o z69;@|-%V_}DzSw(f9jbG+T`fu6eMwYM9#xkc#JO77Z6`^3w)@j7FwgW@fH06Gi4Xcz}tt~gKpxRw}VHyQ(9 z;3#!W=48L0&jekSeKtO;`?qXYKFR&&f`^ZhShM#$jng>Vd$*-wS`=H?OT->Fj-G~$0`-d`G)nh_Y-vv`LNp`ZKv2R8@|?AT5|m*T|{9Nfv#$0wkE zNJx**LPGi#Llgee;Q!|0Up^*Q%z_VgMQC!C4=k1EoMbRqaE_Ej;>;LwmdoVAVix-6 zm~4t!$mMcFF$?`;O6pvsm_-t=Tm0)B&+lf%EYvxY-%W~HynE(lgQ3{lnEdnSNQVD| zdE@dF=n?V_0wf6#tap3I~OY!s%DslHTGd1L(Laob``s6|>-TTGn#d%JJ*x zw5;Tpzx$u(PiB5YClvMY_pd57&tBF=-Q@@u{SBA=4wd|M@C^?BA~<52l|iokyVJaT zpJ&8R`CS47zZ7lnFPgSfG~$kvlXHg5mn%JxkwfZ9Zu|C58S?&ZIkxfnY7fc5ue;9w z&06l=vH!#GCeGf$*0LuOA!AEsAKGzP%Efk zZf@>x1g`^<R+XUI$|9egR`s=Rw+O}^WBG;$VH&DN++4Mt<2L|9wPpkIh z=m|x)^q!hN7rW?Rzyz$Yi{4S<@xaN|HHbOhgM*38Z7-PLWp36V_{{wDj?`N4XKd`E z=F*!I8~P2_KK#!5hjkmc(LaF&*T1zP+0DzV+>2k- zdfvk)`gP`@S79%V=Mc(t{n>m~c%Gc3gKu>k>rIdF&T zS+}q@r*5;q!hSY&nwrg;jDz(99HFK&Hnp5Hufsp}3F2V=am8`Mw z8SbdR&x0S>fQ{ITPRjhZMZ2rWezTLOr&kv7#y;kwkA=^yy~!_fojhQzq1GGhfw8~9 z*x1YU?8m@=dVg|&F*!31HWEv?2oI?tQYYl&i}u}x*SW+SpSYeqP;6B9VH0-qEK@zt zWbH$2*xzGr@}Gk}163d3E7yQI<1;_;LqDZv=1NY5N`K5}hxDGFbt~_&-vLjE0lWZz zV#D(zp1W}HJPf?(so^IWz!Ua8(IfZ|k60@xJ}@@=j1~wt`F`_JGJgbXCaxp4T*LM3 zZ?VQ8?ySGz5#y=9S>^c^Ht-tx&K?uCl3&CM9&lh6crzB7rRJA>GYbCUl6yTxV{*X? z|G@}bzziI~jr-6z@|kPkA^7tQ2Rm3ZgB3AmKIT_@9B_v<5p@DyfEjr%eM_#)-(7Ua zMb=B%)E4rKSQCHz1`B@Yj1P=Kt}zB&frI2B*ODvPhyCa-oFE6#FR%k+{6ItChqJRw z27Qz~U#Tg2n1a5;O>%@d!ar&&Yd`GfV9yJUg9}{C+-M5xRMu4F1305W9B2^x4DbUC z&g#d(Qa* zIgC%(fbIAWC(%~+HK}X#BGgy*t>8Ae;~)2-Z>sk}Z}Ep%h~M|62XtgEHE-Utr)Na| z)(#H6L>JPqf%~{0JFp+Wh#$FvZ}1qO@D;m=3;XoSc5;;Xyq!B$_K-rEBk!E={_MfC z0ZM!TvC34*0F~3yq>?NqqRX{*F64yR~P`cYXbLzY`+|7w^h)|75X0 znHm9(@Dcy%gXyz4_?f&xqtJeOIkEkga4p)!JE+q8;{EUDSMS*bM-*u1DFd*V%M;Di`rDyUG z|N4t&jpLAc`^oR_PVVltJ$er-!L@&OK7G4Dc3}7`FScl8JE2ID!N7is8Aqh7T{#SY z@jrE6{M&JoWK70p4*f66WKQO0pMo!#;;i;5rvFK%$bOu;i|qf(GZCNmZXPi%9^Px* zynI*lv*fv_M?gS@Ke^XzB5|$I-o+y(Fr-UzMAYaUdP(#b?IZ8QBO-EqJ9NC=-qn4A z=mYDgKg2}z)>NJiwD9%saCXYnX-4V<`HLo?1!yHbI&}%&Mo*k%^z`*V?d0axjC*C= zy#JX0(@M=oPOV`8VXx3@J0imm4DT-~S7nE9;{yQmFlF?ElA zfHCNYS*z2NQZvw0YB+vVTkze<)pI;Ca&U2}9MU!P9yJvoxd!|2iQ1*sTWB2ku|DEC z8(NGe(>riaP)OIL_8uM;WZyPueDuUz?xR1WR;e`s^_?CLeW$kIHwU$z9+rL$AHayX z3%@*_+}vkU|LHyO4V>_e`p%k!=Ogq!^as37|Dt*~=HMQB5PWiUcAw<#?YAC%W;|*Y z<4{BKO?^&`+D8pwJg{RF@Cy zzot%`E}tRsoQy7!BW;|Vs&wcSlE|Fwr%BR0Z2{PztEK99aJ z*4zKk1BY%s`aB>O*op68LoDfoc;=5DfFsyo7kyEOknZ=TZv1ZViQKbybZpz9bJt4? z7A`cBd)Nv-_)AWyapJ{7R)^e!2Wos_Ky!SupIi)U( zub)V7=i%iaI47WE=-!|%J@$C{`OgupcIQ2=k<$1(EWYjM(bbvk<-lK2SBJAkWtN%Ih5TCslELxna_(&Z>b69tx8E}%Z$z}Xu4aOMY0bV}- zLG!VT8i0-HGS{MAV8@yX`_X0QM=!}kc%S;cyT}1l2hyhktgIa`NqBU z|JcsjjB`-u?z=;}h3(~jekY%>pL}H>gFOuPJ=C6!J)27w1(Hah4sHEeQ8NJApMf}#3|D=sU@rr(Q4{8 zy2siAd$1AG_7F3IiIyZ$00M9UI2^#FP@oVB03N`< z1Oni|d>{ZY-T?pv;x7&dI3EGPbp!zL@%{U|kR1TndV&Aw!+}B=0QBtx06F=;cr63~ z+&~}zhAIE6Zw&^32T%~eiE#nPFvcvV9OLvaVX*%q5GMDRF~s=c9AHU41K5*JfP2Y@ z09W!cz>#taaHnGOnDjx~3Ba6m4zQ+N0PHE}09WccrtBQx{&)`Xr5|DV7!de)3490Rg>7l1+mh6}F%`7bxXvoDu`a?vHARD1)dmfQg9Uk(7xq9Z`7_z+P0dIIQ` z9svd=2f(Y6V?e*`7|<-e01UsK02<$J0E3E4;8poGU{11zy)20xq?OfJgli;9PqG z_|)$MehvFTK+_=*-m(J(Hy;4ut$RS!k3Ap;!ymhMF!=)@y8Qrn_wxXV{CNVzbsPeT zo%=vS*D;XPeE_8P8~~ZU2f){XO`v#a56B%j0P+Tpfzsi9pm^*Is2tk|DkqMCrl|v< zY5Evwo;?A&XLf+r>3yJU{t!Sd?gGP$JHW5SL!j^XA<+B#7#RF>1Pra70h6l-!1Vet zu(q=UEN>qHi(4na^3E}^wRZ@t?VkbL2S>op!3nT=a1QJqp9A~HXTaIn8E|oW44^Oe zfva;&dUXn*Z%=^J^9$hO{2aKxI0tTTFMzA-YfO6k?|}LLzyCiG0W=!@|7JU$GvZ=n z2$%8s|Cv=WY=ZwHZ1Mk10*8QrkdW|S2~2|XzY0iUPz+A_-y|gen}jq5#Yj+5{WbDG zY)Jo4fq!8_I$ABQ|FS`dnK=JLxPMg$AsY5{t{#8&|6>F9Kd{2T>I8aWaILVXPgR6) z|0D39R{Wz*fCo|tvv$FR6dh(w`)^bJHK6s^Iv$0VwFd_CcK!RUM@WT{ASBTG>w)Jl zPC)C9DG!hq;9)UBqh09esQyau{KaYUFfcB`Loquv^0BZ8he8V%Y(tn?T~CoSs$G};M{QUB}zpAcYhOl0X< zIe7k74H=6^iJq7OvwJ?|J08MW1WhMo(@j0fJ9rv1+|c9Z}`6v{HJ|7e?x)kJ9TuLnZ9-zc3+z z!awSm2x0^0km72p8MNfmV_a_ix<^3I3yvNmTz8z?8zt zX)(Qz!3hae{wEHoVn*j*CwO=e0!mEfFhBk~jFH6D;U9^=HN|9z|C{o^*{A;wqklXT zKK|ceOo0v$EiPst(DLa0pP~N`%l?M+A6mr4bUx_sjDWrd0GV?DVEW6Lr3UdLrVsvd zD`v3$U*W&9fBCQO|FHAd=3m?Y`1tGVKlE1Z`4d7sT08&%2%jp-V|x7Gg$eZU*wc3@ zw8SKLoE2ZW0sv9_Uj}tK6`BJ89C#`(`_k*H zs7Sx2(hTAu`Yz3d-S2y6;w2=yxX3DnChAvS?}`R4n&DbJw-NU}Jgr zI7&=UFZ>q8JofmR(s9d% zV>dUx>0xMx4);$*>R~vv3Xx3-4Mh^jf}yfVIF~Fe4jK0)S1Vy~BXKZNBhAKr<*n97 z6()%hF^`4c8)jLzon&23zKiDg7LSeAYlzwOb#X&1a@`4yy$he^ojr9(t}Bu@wf{!h zbabL^;MK1{cj`n_Vk9(8;2~@~X-ND%htbp(5Fpdt4%>07uc>(F&KLlOV{0!1k>C(>2FVB9Xz1I6!ozUk7v9kPCmfMX295Gq0 zfoH=oq&wfbL>#Bv)CWJ81k}~~<`O?sahsWM; zje`uMy0hhsmh-iRq3pOeOP@2*PXy3Q>dZZNT^3CD4}bZkx1jVneBd<{em!&&S_S1-SMUFD)EizcUI3$!4dqV1dBG5Ihob z0Wa%%_7+$BdrddhAy$r8-({}HZ#YvHZb~m-UJ#788Q;MSiKx5D2Ssd69n0Gfuk)B1 zmm2lT77mK%($i7&4vTLd$7PnKNP^0#yI*u{>rQLrr+i#~R_zMPm6Zi#&4s`up~wj2 zHzM#~XI|woPSPF%x6=!OJ3UT~XboaX5DsvyfrF%FSzH_p!y?xcg^3a z*>Nwbbo%mh2H8n^_|_q9ZU*A%1$8$mEcsNoJZmg5~=+C;o<3p(ao}d zY#TA8Nhrh}t^;5U&k9lfX&_(%LAxM!C#p?A-(~aE7jJ8CQEhfHHD1n z!VuH-xgc-D#aHgKY4J$CEye2lHVcrv@9IY=?|ki}=uJJOii&NxDG@}L5V{#b!XPHX zdV3(~nR#g>a~keBi%myxEGkMedycg@ySx7kV_e`Q;au8=2^1lHwVUqLY=QiCXsd!0g zM=-(#_p=M*faQ=UqhzMvl4gth)dHi~)JAqONilYtq%{LTUdLQ7so3@5wCX<3B;Waj z40_IKx{BXVj^RKgmm9u=OgOEtEMxf%d1A{luIYN5nn%G2kNDzod@yp}%XFKwciq#n z;A=~Z2(~?H&5)K{V;Zg_0;DCflx`vdOKXkW2k!>#PB}F?yY9r0RMo(3?suxrY*qWe z)qlHp6F;J_i!9iN_xa z@Us6;L$nb#Z0_Qd-h$uI>U3aCVUs3*fJE|nPkovZi;2H?K(;e@Ro+|zyylw)=S0E_ znF-TWrCeSF9M@-|H<>(1X>tak$6fA}nIi~i9xSBlrYqfo={2fpZ8h1j#%kXx?Q?}^ z#=#m(@Ov<=gRSVWkwnY2a6tB8=Gz0)FvjoMhl$h z2K02|s$Csr`43d_)>)3Aq96CfC|U*O5w2oiZ(S6Af4Anw>x@$Mj+KuEvM=JdBK6pR|J zFV1LC+}+HRMVTPIKo~PV?R!tgc=S=KQ^Ssvnh1XFW3?)#wvl(41AyAf?+Mon;T!L+ zt8 z>E`eM^2UL~5zD{t6GD=X_wJ(jpM1hhf$`GLSS|i5sDPVx;Mg8C0o7kXwA`=c;MCv2 zdw_kCHeR%aN;hhBx{|s571L5k2>rMyUyLuiL{_mm-n55=tSJNlfG<@BG zD&E`G{<2yV)M8oqMj!PsC1>WVv)yFtX4i}D+O=aQ7w1LNmS4L@5W!ZKPuJKc;0PGG zh*k4}^yVlUA6rf&*Bytl3eQ% zRF#=X%+yY6$HLb9DtNZ{{OUtKD47lnRCL0Pg1m|;ZccWY(4D-psbEK#y5|1iD-~5- zV1MeWblT|ZL{#5@D7MAxY>zl{JWtUwb=0Wl1e7Rsb(D%a>o`l^4$R7GZ9krWh?E|H zzI?GuhnfAMgP%IFnJ%w4n7n815;2BiA*pYjmkPp+7VU8XrlW>?fj6#u0YfFId5Qg7 zc&bg|MpNqSxJ*%&0aLg8?8Y+VfYkd{`gD8g3dA?^U*7)A`K@@8ccnDoSaF3NM!rH< z8|eWzGg*&65!U|xsfrJKm<~cp*w02Zi@Q{zZ)F-!)_5o3fqjZMl^=?(*TgTzPUbJ} zRR-Y+BB0tQxM1}GZt1awj5|8A0H9{?T3Y?U*G=HE30vlfX-~m~$Qr(=5%zoq#Uri< z%1*98d0l2*A0-D`f1dZhv-C<$lF)q4{RtB?Ap|9AVMQb*m+NA~D`U0BUn4-eKn7Yj z^KmL}bx9DpLk|16DI#6*ha0{2M9msYpYGvSMo8Q2t8scwv8(8uy>LUfp>d6@b5%4S zNtIEs7cIH!mz(ne?^P=ew;vY{D?{PZnpuLiMZ37q>%}P_A>rhnI%lg2Wa!@|1HWKg zgz8@jb?kha>=BLAWAByLl|+)p`E)2+G#^pd|NfG=htu$NG~dB>Oc zx`CsAS61@9(k-2h_3Nu?|>uCZ7-XBt^|;wr60t11k*7_7QFvU5_c zvmjK=^$b0B-e^10GTr`anSH%^d{4W$%uPht^mz|@!&7n(N7P9AlK^fq`xQc4cd%f#Ju(Y3{v$>6zNnT@ zlA2yx&&e{mXDZsVPd%QvpYhk2SjN)8E5D-HtBXLBx=2{qS&J>6dYqo+#rW-MDb{y* z4@1s*X7a+foiDL|zt5$LG*WK|bs}EQXc& zte*A|2i{H^9Mzd}59{Ipw?F3$d^Z7F^g)o`ZEv350a4y*mR;YTfS6>01nTajcXB-V ziYEw)_eP|^^^It>Q%DFbxIld32cHBD!NI;lnTU?NfkLKf1-0Ir`wBmao?+t?gJnEu&Z;*)ON62LaCH@ ztXf(8(jc{Vv)XqHGSa$lnkc=#Kx5~{A2`*oq?N=5ZZBl|ATuQITVjph1I|Zp#gUy< z3$7zYr3(hWdvyh;t`Kaq$H_rcbpKQp;!sX2T$SbLGr-TR|#xL1&fX~{p!WBcmJe* zud@&y@7gNYvMm99gU%Gi#7tNTh|jnPPHa!uTr)&}eoVESnkG*JjMKx4DS*X3ql9Z2 z=Rc*~dzWqaXwSF-5zfqjG}MvA@C;e5nV@uX=e6JK=cJ#~72STq5~AZe9n7B+JO$K= zAQ#sG@W@GjgExF%n;{VH1L2%$8?6lPTk-)aY^=$A5L!USC$VZXR~DIjUMkg}9QgZo z*N91);z)SS?gg0+{#?OUtLPEm?Dkc{`gME_1Avrb71fh3TB)R2I6G11zjN{RLztn zH%{_RhEK>TUSvkV^W>8(6i2{9-q58!+0lH)R<$i=0#71lX!|34;Fq!5E8^R*czy?DPQxfp*0fh{)OhCkNeI+@Q@h9AasPSI2KHj7gH8QjMawB> z&pAudtg$mDb0lOM;MlSiiyC-hvY=f!-{-1T|6J@i@g|GyjyP2_4;y#M=YV!Qu*Vh0B2#_!)yB08cR|&L)uv--|xC5R;Tu6!6zZU zP5U2>9K7@2W-oDIDGRMslr~vk%Se0AY_wmz6|VX)Y3l_2oY%5)?z>gQJ9RS~g?kIw zG)y+So?Lwme92Yio@U7sn>!Z07X?BBM#ZdvT2hd0dp6;fTG1E*aC~X4MjaCioT#4! zNS#Tm^<}9e9c!YVH-tGRusmlUCWvE8G_L;EiVgWZ$r&n7451rNdIw&{8X@06>s{i`OZDMDss;-s|c4OnA z@U&hTn(U7Gt6=+eNn>aH&zu5Gr66Y&L^`eswQ1#%TC-HrAM9=`LMYbjnwT%2qF$SB zDe*DbKfX_4T_s^%V>!6vL2~yM2x`C7IWN(=8~$i!aVKQXlYQPOBpX3$dq;Q-y-uhn z9b_uXOa*S_*1Z#{^*giv`!40YFmS@k2bX#Vo;7U?iGV3U5nS87ZDXh?y z8VQHvBs#Qg*tSp7gM$&j1CuN|sj`)W0Absld2xa}2sI+WzL`!fzed@t&#{FjBWB_g zLo?CI!27~}#z#UYupb(pthO?5;SS6&QWJ6(0+vt{Wa~;G`D;*EKd%~6M&^_~UbJ_U z^veNVD0TL7YkQ0Tq5;+Itba@B5AyvBK&ukxJ|V#K=BVa)T>7kZt=UaO(4ReF;8pXd z@SIKYXpLWgGKm4o_;we3J2&T5)Jpzki7=FlIYhktKnVs8I=J16ZO%lGX9W$Iz#U`@ zf9bdnEhMmU+G5E`3|R}2cN6S{Oja_{7=|W7=Qi3~Q^R4I&BVVqeAS$o9&_(}HY{T% zcmzGA6&a(*O?xiAS|dJ+HmLWg;_@_wka!T>ExR(3@gA}=yl5cyXS4uxK4`0zB|#RS z-ANpkzN~!c>b9KnmCIJ{wr^@)+zDap`bE+n!j4itv^aoy_`5-brzGyv z1Y|zr6QLWvYMG0ghy;z!MC9Oi;4&cbsJy!XDi(6o%-Xqc_x6A$K6KjR;m>~DpG?~e z0}}yi_FT8i(Ovw?ew+@#o*_iKsyIyx4Tx5 zTe}5&!Doq_)&hnc&L7r3VBsmOANeGkn^nJy{n?bagSaUbI--$l-o;$7!CNG4XL=8Q z^X2J{3=#`m$)*3GS%+Dd3s_{GEWZjoPm-F!+*B9dRAN8VMM~GN*9sR6dm|l~KC756{ z&dis)>+{uXE2?04tFs@t`vtt_>_h_FZO+>lNFkK>YSHmumoQXnbmH7oB3ayIIPcdh zrJq4+j$>(I0bU``zM>n98qgu#^0jSC!Wa~@EEn3( z8hg<)2tKx?H`aXu!n=IfFVG#t(7Kp}GlRw+Ax6prD_KjE+|gPrBjg*C>`+_6_GRh2 zId4@4&pz;{2@-!j?0XPfA~i)9UH(AfZiUCgi0`XU)3Hc8w|Z32`y*6yp;&;HB*MDR z3Ut2yeg5~^Y_CX+QBA{vo}#6!&DFNrjqg)(DOE$0_oSd#q-NF4WCgqzW!9C9a;}@w z@&$VelNpa9M1FjG11BJPLxM$u01xET*U9e3`*woC!D5FIM2=XR=blg}geHx^Ha|L|7b4du0KuX`XM3>C~qUb3Qefx}EVi z-}l$AVtVr$ilFq2vu~lD>by_l)I|A;nkCUez9O6?vze)_M*@~vN38Bi2{H{0QbWSz zp^xCOAkEAdHy7LS;{ZA9Q0M(7U~uHti3yTGbV%@g=EPmR*_dgQ;yX^g9}&-sXF^tt z78Q~f93o`t-Uu}=f^Iraw#ae-RhjMnzDm~H9+B9Q{5$pQM8-*GK{NRrHXBlu-jNEeoHJCE79TfHI6 zVl|tIs^gI`i6RLd@Ne7SLHA9tYRmRYn|^new1iYgpAI1&&rMDCq{ONBozCv;iT zm$ZqXRziy1``lE3^M;f6t<2Sc)q((ZzBYUV%cZ37_J<(#{lnJeaD%;v6`X7AsqEbl zR5-O53Jb{@X%EB=C#BKCstt00PZEU6(vkbi4AAHEG1JF#FdHgn=%+ZCYy{hLxTleW z2zrqgsYDO{;YO>z1yu~iOUVFOKNukr5cR*2$rnXJ$OpY@PBI`8)bgp!tCh_GD;~gu z@%DUkw zr5U<+azk)nC+rowB6cup^^Be@`P9|FjGYAmhH`d95se1ox5jW*A_@4S_y=goFna~* z6RNp`+qEXH&%0m?1GwIbSYQ_6UMB9d7Y1u%x*V>0V#)ZfV)2n_y&{GtTFW*)#lir< z!IKq&pn#`P_{Bi1?eAN6xqtmw9A&%;`%LItyqJEE45?vus_tw1?j!`MJDhI8W$pkL zs`e#0MPn;?y$<^+;wjkELHlGlI1Bs9E!aMrGkHsxVjPbI#3IkCh`RbUbJo1t5O~uT zD|e8;1p{B|U#y6L2#!SUWc|_O)2hs={S1Lc7FVu%fkbZ?%svtELp*PAcaz3nSRx)G z?d^GKpAQmP!HED_SRX#@*mEeCBRIb3S=+;A9E83DaWD|0u>i4nI^>Z9ET6W(6;qjK zyzcxcRKK^7mvAF+u*TB69)dSB-f0Z@j9!($*RgCRe(zCdKS@qm9x9@fxDx z@Cx#cR;|JP=T6AzTkFS%3S$={hl9=FW@vcXuky=hRjx|Fnrff8_ z3EfY!0mU%tUczLbswlA?bZ(wRm=xB$=YZLFWg*53onJZ!`cf-unwgp$ED>;d6>~Bp z^aua4Fb0}h`=Ov-3oPd`8G1U*2``6|8*suD#k+H}gtlktdrqEec&d!CKySfnBBTg_ zr`G2#&IH`zor)~=F5$1=1!{*Ewhz!_XOdejxB@hviyN?p7up9uR7)oxQXte; zgv?f63nGZ`-#ip#F=vCt8tEoProGk|Y#k%&V-(DQ_(Wtq|!HLn-SytAC9WEN&E6F7nYTu?meotL?R z*5Zn{=Gb$)G2v&~i#3pMebG|AU!0A^Xd{Vs;zZHW6iD`tb^D6-6Ef@7K9pzQ>x`i0 zyoP)Z3ft=!iVGS{cEF+_QCe`2{|6%F=hw8%;LSNRSdZK9V%M;gj_^MFoW`u9DdeMk zs_%eD>IIoIEAD;a(5j~_P&K*g--0rpzm;0nYM5@x@m%ZobX#3)fX=JHi-DjTMD@!? zbh%<6vDq2y^267Fuw|+r@j{D+8$ZB&dY%u15b8Q|Qf$%6b8iz*;govOG;#S~)N{l% z>Uyn&b6%eWep$w*B!uj4W3`l(MtS?EblrOPI`v6{pG{{fJ5w_uDVE=#iA)fH`zTEw zwPxZBt|VULF%q^7i;R;}7Y>mFwX4_bcR|;zi9~Sh@R`7ZSXizFmbXjsBZYb3mOhiHmD;C;* z9@p?ox-!}B+?72LdchSJk-zfb&w!NsRj`=9$IXjw?wNwH+O5mE4TS(H(WhSNki8q| z@RnKMA zDBEc4NI=O9_SSWmZQv-**6=l;Ti|y3faJj*RN^iP4wgFiBWij2&LiA5cCq7^&)Uv^ zy7S!-;Gv>cAbir0EV;n~u40ONmB@4=p+M5s2@^YzebH)ORW=hX($eqNBWt?B(Dz_| z%}C%ns@r9w#XLRgsolO4aUb1rnQ;J0znSLe4_C4__HUdi(#hsYmsx?emf6u`${iCL zM9Tu$=E2!Fst@caqS)!XkrKHTg(lG~nK%Y5bDo6)btH1w2<%Xm}9xeASS zaLHR!3?H7kXa<(vQgz@Llyc_M=hbPvT#XgLE+?|pz~w(*Zeek7loR;Y{-XE7vjx=p zM9Jd%g_sFux5?B~z4zF2gix{FWboKT%~SV+CU|f|AgZGO4$lO`?waRGK?7U^>ur@B zi>KD^ywKoH2=B+sd)H1BhMI(kSo^cF`IrT-olIhIxkPp@+H@3MPR_HCBj#LnHm%4(f?+7BWQ|JSF|!h@KqP#`7VM-vP?E+3eHD zb3SvivsDC`bH@!c;?kL-oNhnx|@=0b7HtaSqyF~=1F zN5VcCA=Z#3;ZHW2K&#>VMvWY)bE;qWmKRT`V&-mpW(Fi9%kO++gXu()#kuBI9qvuz zhtC6>UsaeWg-*1?hMS8iynAy1*QX%ilwT;c)|QULv#|_9}@vk|ozBQYbQR z*PkN4MusY;>lTC^>yM{Snlo=F!`*h zFtBjA^q}|INSr2|-)JZMSNwXXXsvEgAt7e@fHfC0f%TqPwvQ1TD+rERihxj(5o$Up zEg6MYTDA`r3LToKXS&QdwpCEy<|Fe{D`NVcYBg&>mrh5Bn*untW#0jc1CP6SeEXA_ zeVSjO*IaJJG7J-jKWe;)BIKbX8^*;&RUDNJ6mBM==1Bh zdzJE?(^Upgu1&O?8;KHyRcfMC{cob;yvh zwstEEyD=xp_fKSY)Oi==zOH*8&FUK?Ay3wHnNqw4a{QW|!IW)m`Uy}~U67({Q0mB= zge0?Mxr<)8@-_y4y7y_{3EMpj;-3Z)e5%UNrgA-Wbp!_WUxP07$^rr7R7i93Ted61 zke(rb>V_jx#A`bBrnd+guA}T$WU5OP(upBcu5r->^0_!8sdH(X9~X?ABl~?HPH_qMiu0U)}Wll#oiG(zCecN03^QV}j>4mb$TDFN7 z((lX&q|TGA8803LkH1!vd@J-JLNG{(RY_@I;a+`jygx`mb6K3+m*v7cpsUMibvD2oz&xSWndbA~?0P>(uCkebL>6#YgL_r@!CSd`) z=>eNe7el><6&6rbxb{t%sckra^jhFM$yMdlgL5HcsPp*NgpAey`9s8ybD-fcp?pKNQqO@fCI2`vp)iq`Z@Qy5C@(Xh&A^8`zwm?k3`=&h6)>KjEZJB#750mzpj-cj)*-5kQf#axyyUAszJJqhhZwhw7@)4(lVb(E*?*;}L z!6(dHDy_7zT0$q!scR&FbT9FD#C|Td<@tT32+fdKiKqf06rm2gN9Tb-rnabFT20A6 z$RBC&liBc1w;iQ2S_brjr!qsh6g%|6=O0o0pxRNveE~J*ivdbu`=_eu} z|I3Re?h}J=u8j}k1;r~y#*S(VFzbH37gPN;j;0E8O3i?gf2cwJ0rvUfH>f-(o#ZDV zLu$clJ8%bE#~L2jdv24)g1I(iPT1vla@6|bQDIxvq+GnYiNGPW;{lF&aG@(fh{l<* z*X9gjT2`BYg@Vv-#vhWrriu9W4v8%yQN8=J{4B%Od4QY1 zOgjP`kvl2P?>u1?u+t}dY!bF;DvGm`BLjwQ&y6>d$k!cvZpwZextB7T7HO8P^`Ke3 zrC(pl%5u`~r%(u08e+HP4WOw&CZ15cTiDm;2`a*wALk9N; zewEa$$vG}(L9m`R6rv=*BAz-8b+q*z-#?sMRo+?4`jT817tLI6#piNdF?qX)%kQ_G z6+e)PC>W8gnNgtcvdnLr(=nG0Ql33s%YQQutNr{h8YapQ-DiY2Hx}4{R13wFn?3Q{ zBvR}+3!2XZ>Ji2L4`(5!HyT%RcwJtlG}Z+bP{e54{!n1Y{@b#}zUt)crj=KDslgo& ztX6M<=8yyk78g6mSu=^;la@k&t9Xr`yuezBF(5^YuCf|IEA+0h~w1 zrU*%@F$oB7;b;6Y;9Qaa6n!=S4gL8s8;bRp8qrP3pfa@h=thLrn=OyK80)=duC%e~ z#R&nBysF#&?GG+}4^cJ&8zW(B!nz}Eq>E&}GKuob(WityATFfaHPUltr(+VmOXovd z5i5pzTQuDm5;oRW#EjowDS0fug0Vk8n`f8$s7r*Qy}SNSMfD zKKG$5SsT$c4fXnQsZ)HV1;HBC5*kvh6Sdv*jEU_@VhKuP^?SXh%E$zW^T^5{(MPLx zvqh$8rF32|Q>ydl56A1SlR1C9#zB2?uz$D;vQm7aL3;hscmBl&c6i(Gmgio(ngSMa zg8VM9dkYe*!SW0)Zn4^zyrK6N21f!2!j3f@M%;&1lW;^D89qZ3UL3wjL_M)Yz&^j; z)SL91@P%8&vc5ADUP;NHmx8Rx?YhBnF%R|l8g{~sr#kqx-9K7a&g&;bb(K- zj-ZIaPb6g88!7OeSdJ;l1Q59F=)*+fa?Br zde8Oeo9W?)tmBTKuVY$3m?wsMyMA}e$GO;^ng+F+QVL%nS{t=W_#?;PQ6UpV@b8FH zt=`}%y??Fp=*qGg?`4LLHz^hr>&NQvMcVUzB+ihjGH`nb0JEyRW>-ALylpVHddK@+ z&orTy3DBl`+oa$ibVqtr722KLxWx6P*b#Mh@L0q8NU-;>?5?Xw2C~sUS!&r_Zu|PZn}|Q9 zRpZ87_i4SeVX;!yPF@h0{NjzxCNFjSQCAPKKA8z2e`72d{5X9{_gol>qv^*CEJg+c zNUyE?ypuyvo0@X;+JUjJmTFXBQ_6elocGvd9i6CC?2;76-YSS4`NQGqqRt~fc5dcx zBj?A)rJGdIrKz>XLd_9RgVK=X%;iH-Nhr)i`ZsYj+Nlo^LJd2*{%!Rm5}jVOUs8gt zp}$i@sKpOa^E5$uDOfzPpR81}LS4*o{Mh$jh>Gri$rRyGzTn}=lKOW3@RdJl5P~(= zz{!7V{7CH-1gzk`e5y1C{Gc)teqEJ%n~s`B54%oSB6r9JQ3!m>@^UJKtPi7JR%L6e zg^Ne&uiZ1lf)Tg6eM2ir%Gn1%pAU9}eHR#Z;d>^}FjYQ{j$ONX0?CaOpM+Z=dn$Fl znT^N(c-Gf)Cj!FfwLTJeu>H9JY;YKa7@v$NZYEJSGI20SS9%sUi{b|3W zq94j4WWoeT7`b#y;O^m2Y*aLg#wmXC%@S}6P7lZ9g#Vck4XGJ@!E!YdOelrt!nHF7 z1AGx{{ccrYr6np0@~D_dNgq2tLI^#y`+DFA^U{Gp_a&$Gd80)+x}nfBv%BGOnh!at zkw)7?oc77J9*F@jBT|@%>;b{&0>{1dJJ~G;aK$$spagDw7H;{_Igy%-Jh{8b2yC#} zL@^5vQ2p*ra{KSDj>HO>OFRcP4U{Lu^Rg_`FS<-(B9#W7ze*R#yh4VjU7`Q3!>Lt)^kT1xpXdozG5S&FRM^>b%PyCZ^ul6y_O7m5zM~tu;0dXI3$lEj zyliIQS0G2YI+AAcUkmoOrM0}MStMPJ-d<4QV<`yR!xZgu5TnSc02Oj>PBEbqR|{p- z%<75nH~S(&EZc`9Z|K^ji@y=Kng#%}g1PwJ;E29teOR{)h1sJFZZ;V!|A3fmQ_dNS zqZx4UnIqh`{zi?(TsNh`>SIu&vIYN#N&KwuBYb1Tu;`=~!tn$mx&HS1N zg1Q7}AMMme5I;++Qhx040xXEZ09(WK$iC#p-#=KeaWmILQ<%qNds9?43`9L$+HG5cj?}iX+}%f^^oCEg~pF`Uy|=d21^(Z^&1( z2}7zb&eTqzh!{QcULoF71>Uf?TWj!=w%%cZM}PXlvqLO10yo^U=M*08{`AbaCfmOqH?9zM@9-V}cC+=zoStpE26y z53oyI8Ke-&#&Z4*AKOR<@5=L5U=!_Vpp?N@(tnqW* z7i^0^zfBr_>O#HmzPwj-6P7FBDE+A!-vR{+{(9x5g5|*^Z5nO4_+0P@!8WOe>)YRo zv@+DKxg>WKNfoEqmX)9HHA(h0Eo;N& zZUa~PjttGv9`c|9y=m(Am0iX#LN`LAjaf1g5`<1;T* zy>sJ`=vTf-H#6-LkA2d#XJhM37?cW?*WytZcp`cEIrf12iScV?wm6HoX=tYDX0|IM z%^qyy#OxvI1nuPPg6_g&9h2s$Z!3*s`V}M!yi=zx>Pg@@H$6p&Co{Da3bS|RwG5J#}L5p}bd0KIbW>C#1m2^ekY8dI|Nq3o%mML03!`_ubn-5FzYuB`e@9Ys+qQuBi?6d^@A zQ#voqxA^k&9xbx2;P!T&PQ>93j!0q64CX$DOvvTMw{NM2&zkjT&$^X;{F05=pT)lE zBbJY?&Tqec2%UeVWEuSRyFAi-d#QN}-LW%zf~|3ewKI}kiT@PL;#>V$a?k-fW}|SF zairXo1poO(zCbwY_*xIN|nRK$6iCge=R-8pUuZYhuwsAdJb%6xN!!DJ{1{a3&VcjmuF^$dS4JI&l8fG zG>3mG^8UVA?lg1CJ3whk*bo_#gP-K%`0~7S_%MNymCC-bzQb zBWAXCFH%nQ68#Y?nNlnqkZ0`3pO@?xnEbu#&$pUo^GP5 z&ExN*HUWVW83@}O^f_awdXv*>OM^E=osfDC!e4u*C#fjjoTk2_i#eZ|`C|Zq$rfku z!0S+Q)@*XwY#$*Qm}C^L_$Z}c?vN@Nfy0~kD)Ip~X9VWZ!#n%4C=%su1y(D+vzW(G z>`X@mHj!`N8_9jAQUH~9{4ur355aSYZh0Q$rr zWTbfH0DWbgimZ2=X(6LBu$}_}sPCZmw1%-hYLOteKi0pjsJmMA>dzjKdhl&RVEwfsj771&07M$$6 z_kRGoKt;d7zvrZd?h0(wjCzF8{xZKy4s!b#(|3+r5~RaiDd%H7y+h0k&cVYm1voHR zOwOc4o~K+ZM~g9K6+j{>Q-LyLdr|jHlP!k$wHg3ilfYdhL`0B{2ISy4XyQT@Jt!qo zB2d}|NJ3@^WxnU+jNQ`g+aq8U%dr z_3QO2aH3{jU$V+}*W>%%?As5!pEJMSTQEry1ns9V_|(@xK>)-FGrwFdz|@+Tt{Y-$ zkU}4`SB=@e07v4x8{MwF0ss&Y1vHEWGQOt8ngFPWV!S^QfEDBj(B7HK53m>qI__QP z*R~!jgPR5UHMSWjtg8z%Pz?f0lgR5(m>w=z>0${|CP>Ei_SOFPUB~y;4}!oODd_v? zYxp-Wp928bGI-iT+rsbXzR)yD62x(gIF7ON(8qx+kN+n=SeSG+g8(If&_<#*1uX96 zyzMf-7ZCJ0X7;TR7zhA?(8756OaQlF5e77vFD;wzy%tXT!C0!ZPYcl5wHrqtD`uzs zp;)hxHXdU(aLi!wNDF;vITo1&F|!R?#dNQ?%@t$+kN4mH*Q8Zg&V;^&H2k=V@p}P) z@8jm{MZP+5=GU(?)1QqeK8I-bka7fP`Fjb}jqL7r9d+sshQUjmDxl0pE-|hw)?y<{&zHgVRn7ry+-Z4lvL zu`(0@b*Dn}rbPpQ5DUA};>cw{{hMnA`ka2STtm?OXG=n@5fo}VzaQB3MpQT?7$%VI zD|E_K_jRt7+WsE}4ejV#{Qq3c>y|wqrtP(Xhnu%wvHjfB&(;3X6JN&oQ=f;B8D!F8 zfj_RKFSN7LIc~S-AizyH^Gr=i#W}d(ix@ijbs&pD zX&WL-)N|F0ZXN<9orYmk)BCOOwy58W{fz{b=H1PBFUQE&MMuoM#j zv@!qy7{>8FSf&*ed)O5o0QFPHcyndXD%`n`K6bPX06vYxY(ygXz4WDyCP8@wAW5X- z7x#3W&AWRX30k%PzU#TK0tDA@uw3Me@N*r0jj0E)<*CmiY#mkaAxv68mS~u@m2yk+ z0v6+$F~b7$=!div09XMN0Pv~+QT2Gd)<}tdJwB|z=D8spityW z4R^4+nt{$jRu80;!RY1!QPfjdV?*l+`G2kjlrX`q!19nRdnV^iO96mvIU7|?4%5SMn8lQZFF-LO zlf_KpGoa8?!e?F>&i2%SnFIyElplEEY9eG=ie$sZ*8Kls?0-`>1Art+AZDIG^T{uv zDF7fqQs0Q~z&3R2TM^ecBd$-Fy$7lSc-#*M4^I8k3W9hV(Y=2Lw2lJNAgDF~WGO)T zn}-3@gYGd$52p*h-ye{W9ZhmqEp|7ZgV@b#zw>ZJcQT%)K*9_jZl5vdVF4Z}B#0RSFg*PTh*F3&12U=J1SA4LN>J8C7`HIkI*P&I z9*7`9+}MmxV>>zn=cC)$22mTZV*7P`KL-OJ5G+O;aQzbLt{0%S;W9+`{wbQLz6BXY zsD+UMZqwI32b=)|ofq~wZYnyAZ)p~0_z>e^N8*cOXxJcBYM}#4{YL{yR!HuGZm>`Q z(1jC8Br6^8U_V?()#K?U`&<;b;9=ZiuHL66>hdbu%BCGTSdgnBKuL`()%*V~ZT{a4 zo-xk9q=S0shHM3ozrvDd;x$LP5>YY?d4Q$ zs;j{n(oxZ?q_pGlC&5hs1_aDh;MXZ~Gz=%cpUIE>QZm56y~{F7k!;w9AYVzh6#L(& z0YvR%K+;h)vVxFwou&Gwgh@uBzJmlJZDXkOEeuWHg)ADz%*YjJ5AQ=Vu-WYFqd%Hq zH3;aoxaxfs@iy!0qbM?MiqF3pXBwL@e&2@x>L9E&RPc%6!=mpCo@D~SE1*R2#kD(E zg6B-Ebvtt>F71suK^ia0S_$0p`wR*MBt( zVg9TPQpuuyGRgZO1SmzAb}`odBF0XA6|LcmF+F}QIzv0H_5S+9!;a_E9zLheXC_>V zw_Jl$wO_!-d)^BqU5Hu(!eUeu%f1Qr6SlxWr)jlbqq8%38G|!Lz%!f2wZ#g}(W$3x zcJzm7NC0VuHY;%1O#lLbPAn%^Dj2Y`CUa>4JiC!fN)p=P-t3$q4hCT7d>V+(=K&^W zI!H;7qK0hrqLTf;*x(-*1RAZ!p@2wBFV67}cv-k z5HY4J5}iCOA7fJ8OTv7}zQ#JvbDR4S?0$AGpd!Bs9buPdSqxbp1}$;_zsl8fX^dw3 zab=5ARvryK5?nz@$hXWS*x!DklfXU zRpdq|YKNoVPOM(9qh7BA8}{MMB|ia~b|H}!4-i_((fy|)`K<1A%{ceBT_bZbu{0vV z#typ|701Q5qjhoWr}m!@xppj1v(gs?1oH&|azCAfCSkoHccqClr6=9f2V6bW466U@ zbA@d=M<42Z9O11YW0xaILZ%6l(TkVO{;$VRL8M9>6h!$}=vIYcJw|iLw>MXbBJT{< zJgFRpGFHHl#TY&IIc$0G4?&ZUs$GWT7)g?NBM|2zSK@0Ra6us1bS+vtZiei(a)+Dx zl!LpA*MJrFHwu3TV{!`&^mCx%l-Wf}xc3r;$?p_XW(k(q6MPmC4bN_qVM*nwrS z|D}|ux1RvXSlv&n$kb~blyJR}+DwZv{URlhB?=6P5OtrzmIr?y^%J+76?<9}s9KNE zi{_&ZOz!%AP;&y5#ULhqg;2~%tRIE`FFXuL><9P#=wxAYvS8VCf{7><<+nrF8i6m} zcWz;%pUjcd=@Y0{O?%QpOaSW!hfc;v7jW$|lcUB9rytm9{z9z6%d0Z+N3JDc(du4( zJ4fG>Vjd}K$i^=6hT$%Rs@BgpTaPJ8F0%?Z6VsY>8LW@A-@s@ud9wuT0|jO|5ac`Y zZg}J`P(Sr;3jh{s3TT=O1Zs^Y&g}XDb#JcgTgB(bU1h%tza%#06|sPt!L=em!X70A z7bZ}s1uno?_nA*`^d|Kf1>O00=NN1xpEoVW2S5Pu>2IBRLP}~cAqc4tRK<){X~cNC zko0_ZK+WH~{pcK9T7a9+CslzgjY0L1zS;jJCtw<**?BC#rFtg(WhNH$v$`7J7`W3= zI}x>MkoQn-E@(%g(A#l|5E~AD1kvexN&v7BQ$SM{2WfUs1gA2M%)? z{{UD2VSjt{cDEcV<*`La@eDpHg%EY10rkjSzG$>@RQv;VutA(Dq zaH(U(=(14riT6Y99m$!#SbEE}2brmm;~>DqeIG*BK5cvfS(YtG`g8KFT;w1yv-w5{ z8ME4eF&?+qUE7;y6n0VxBzRfHk?{+lcy3-3z?2F5*v+>{9wGoqDo&i3&hjOa3kQLP zI05yyf`3598J=)$rPZejbzILmd;7uIv_?5BG)G_{X#!19*Akf(9UCj6D2TW=+Ck`~aMMfkIjv zXpLW`77a=D(h|YyB)}s(9TndN1mR(NV?Vj7y09;`Mh!DZj44pQ*7_#5{P~lXaovo# z`tN3$lNPE0n0o`DZbDDk4PPyCwE)lg{M$${HXyAiUt=5V|K#w!2Mowbx9Xwd|78$C zj_vcVuv<_|tLFdPkEw?6uyD?F+L7s)0EN@f$b07h@U+QF%U=ygDsDj32GBTl7chI& zG6Ck=U$7UsT7U+DthpKK&~~*+2wC$uIp{JVD>1ptjMg35$4PU*pwK*QkP)SH_dc#x zvhaSs?-~HVr+NBQ?d-5hUTpy2MBc-)^ahi7nlFmYAo%OU2(aHS?9&Xa zGK)-V{y%}N4MU9X^1dl&-Yx4f|KDhH`=2vJ-Y(O8mzhltK)0LhNm7&7dKEmC`#}Ui z)mZ(0c@M&4hG2SXx>0b8L1i4F)L4s|D~4XKnL9_lDQ> zsC51rF57FWvq>X6%3Uo;=nrt`-|su^B~} zSG*URfUW5`4Ry5xji4kU!Vuw^`xZ3=P({Azz#s?^*Cv3l2E9Ru@nx{7Ot5yB>dhJ7 ziVG-?3#H#?Xn}l_6x}PLtP$AP&Y=w~kjxa|WcDE7KCu340DPF6&utI2?!gitZvUu9 zJ=nA$k^WsUhFtc|W4bdr_M?gdmL(3W-n%1W^PLsP{CanMAiei)`z42+sR% zYXx0D?f+)`@j?PavqG`w0TJ_S@o`}^6^AkG9zqG^-5C~r0|1m|fasd{2=<%t`7zZ; z^Ci!P=2o` z5||%Yya`}5fMZkXcXo``v35LxD8RLpP;Bhvng(QDr20^jK$fP+L>zv!kh^`D5)>>SRg!T|l6ET!eL!3i#Fis(PB%JMi!KLZtg z;xar>Ba+CH4zkU=mgQZCZa;+Wr<4ysc8dC#N9_SDIO%R%i^9v-dNl*yx5e1eJ3|** zK%UoxEps5z<+#Vye5@yH51mfFg+c>xof-3@#cBZhX7Wq-&wlfo^B4VQqGci_$*oO2 z_;a(o|AjiHnL+RICW(-AW|3^V0l~;l3jnkR0N4P)Ni%^P{Iiq|K;2Js_7N0QbgZGe zW&Bmw`9LO?&;0jFJf1dp9w~v0fNcB#!X-F5=iByxQU!jdCG(Kx%wN$9jwq%um^f^9vy%gqmNl=Q$>|?pwsR6(S zJZoGK|D7MZUVWWb^7gYr^?A_q!diuDuHqe?ufMcRo^-FbsNg{L-Jj5J;uJoTbGcMH!AOXnf zHr>8)2)8bU{t{C*Ztkv8w?M^8?79nohr^kZl#W2%9(gfRYc4f|=8}gLwaIOS|E^(yi*n z8m_~yU+S+kwAyV*gb)Gd5dm^-{6hLOy{bqfejXOUlD98mr&%!pMd{^!(DuK;XYOu&8LI#QTz4_v z#~=RFC%*H4eb>nGNYIvrR$%!_gMhBOXD~8AAgDo|cH4;ez6wEoa9)hR+~h8gjiLzg z{?{SheiPD@4+5v}M=<#yqRvSKB1ISm2t$ED1PFvMVdz2_3juHkr$-a=F_n}ADS;$S z5O+Grq9Jr|cq^ju-B!HAQhXjoHOkDNWf>anBWkZg0*XB;Tu^h{ku$F&t@UBS)NXu) zPP1O|lHZOqyRYB!c#9IaR{buna)W~i`TT#1N8bJE6OX|^1F#?vSgHnKfZ+73{PO0J z;QQt`2f7MWzBkVwJc_V=0)fa7fDj5o5C#Z>5F$_;S}H(bL)&$vA(xp_4dP5@$Wry{ zZixu#=IfAM@&?pKwptF-#YQ`Fs#5=@lo&ew?OgO`g;vr_b17*!y}%CUJr4G@#OCe` zFd^@>V^OvP5k+20(Dwp{9GVEoB;mx2{0jPD{{u^SF92*UAba#g{N>Ff1K+oH0)jYk z#f1$>?JQ#EfFyx5o<(=d^N}?+0zhf-0kAXzGkefSCtnrueFXULD2k9}HDvV*k&W+$ zloDMjfte>DW{*P59zihsB*OM#gq@QRGD9FF1Z4iA0|pyo z9@t@X3_%Wv&BzwUU`IB18C#pRj5M0j%$?=lzFl3v_eXVgS5;Tv8A)?TcSiR+r)RpW ztJmA#Z>wKb0bW7gKZBgcj5prS&)-56;HQ|+3w}W_OAEOjTMzHATZ*>nyzdslG9j*d_APCrd zG*sq)9Q-)3901_t1b}XSM4!KF{H|xOub^Ws0KhQyGr}Nt6^J5`SH|SIe+&>M-C8;4 z$%mXbsb@O{f_@HN0O$cnTTlrhAj<0@2BbiUgg_W^u*OlKJ_@ff3>J)mP41WX9*lv7 z;{Xv@!~rmf>Hw(N2P!RvSh5zVt^$^AgjecC$;xn?OW)r`e6>_+56kRF0*w3zr&|L< zJIhZX+gztQPbE!!Ks>cOX?(PfGp?6hY=-j8lUn!a*cb1PWc$Ck{wHJiz-<8>H%``Lve2OdAcn#B*n!i8fL|=45*@=ihrf_`g7$qb)M`{=L#;(uZ9`( z8^b8p9+9L>hQdpZ)c(cMeoYW$>zNvz;)(Lwh_v4BP$zA+wYf943A;?@HSxV=RmOn zUO5YmzVoF(sGf_Ud}c-yy7B^C#Bd1*TOiB?onY!%S8u^QlFvkb+hS4c_PyKBr|QjR z>aQ&XmLA;>gwv1&Q{4`;=6@>E&7OgJQjbwL&wX$boUCd&^>aJ>*yXLctC|1!%#V(J z4|7C*U^bZt`NuH;KBN#S0Vo6LIr_;>w=XHP|8}A`)P6861i;KPFaVxRX!1PS(S-S6 zUO^t<6@Wq&yl*Xn>Uspd>kwAgg7>U8(tYhQ?D7_ub#St95!oicYu$CcEdXro-i|Cs zo%oz{gkhLWKh~TY!cM)|k5tS)x20Eo?gN3m1` zaRylw#e-Tf5R=hycts#;q7aOsF#2m$3%y`|31QDF1WPucS>1qUbuD<$s*FHz`O9|i zz~i+9TyVJw`uUAVZejZ8o!8~M%vGz0EAXdG|1bSLQgN-JEU(*xTv@2fz>u1Q7wm#$N;{IG>^6Tz{xFm|2UI_b<-2Z_ zWa16e{6|W7`CF-T#ZmmYEKL<4>sZsI&rbA}=jZGD93*$T0LRBwB7h4Zj6i??&7<#r zY^Yg-)cPE$061aHX$$~BbmPy)hd=ZuXWrFcX3y(fArRYPOk1~hr9Z5ek;MQ&$iChp zlr!Ui#V$huh?)?*jzUmFq4qeI_$8pwgRtiuH2XH9*}n;*e?7w9GXa?7bZP%Q)7&mQ z*?{7yMl15GW#yA!lO3O;2oPaXpRshFM}6?m^k>WuZO z#FVrgSCTL~Eq-{%1Cyi3S^y`7lMw*wi88GLzuFtz{QRd>o_Df0*IwwPj<=1ZptRhW zZ$4gECa3(!qBu!A1mMY;a##T*IKTrG8sjLAJ&J0f1o#z%r2+7@mm*qsnK3+=ad$aE zI~VcIPs<1mE`!g4@k|w(Fn^ z0#_5ATG!F3f*>#1M<+k4595qIUy<)xnf{diQfW@U^5M-6ItqDBeQq*4_|z)c$jG_t zWXP|MjtFRS9DVKQ4&H^V_CL7`;KaHE>(JkxE(G|&@#yO(dG2|H^#hWzjt_IufnPmsVgUf)U%R(<3*fN8Its3v(>{t!J+eM7Wgx`l zkF`#gaEgeK9gRv$5mndZ5>qFKkq9$2nly<8L4Zc1A)CiEL10hG)hXm}MS4Bhr^p{R zCb4SQ=ixO*CHYm`e@y0drY52< zeideO-$|wa>X-``0B{I_tG|78&zqjV?7sdodlp%ibjKkv<8qRN^u7b?mB&>nemFAf zA~xq?R3-uhZz5W;1;nxqFuJL(lOzm7M2!h7-T4uOg?=>qHX-O)i)PPih+@AneRi=} z1QDT7kUwo+PX0^*M%O*HDx1yuZ2_PbB?OcJ5YtDodheIuj}HPQK+Op-O2_}VXDK#& z?#1_rl(+H4P2rs!(89F0&qzcN+W-I`Y)M2xRI191Y~DFh#2E+z!iZ1{#Ey?`9odIi zv0@I%56oQ*K>atYfS(Q4KXJu{y|;8S_jS@{%d~yTYFd`G8z=5Tc2be#n_=q1Cxin} zYncS(%7DYflc1?1D6pd_)*eT%R|YFo5cHgbpt>HsZ#{V58UV}Wy=dpOTNq}O5Twwm z{lDc~wa#g$A?H~D{^VYqz55Gb_2JlUnv~>^UnD_qrlSlIRbr3!wCTUtKS+Nu%GR-u zOAk&1d@kWIhe(2d0@yy-_$2b%{yWA30OU1>m7T{*hUlmM}CB* zLwACOQy@MKgmtJHhD_~jcHBvR6~huR>zhRm-sJ8h%|dK({2W4Q|9VKf{^|>dcED}^ z&k5#I000gv;K2jIbc54LSPFB)k zTNd`ZeqI;(Ip-)(3}X4v_fQ%i1Vv2{ugm5>k=&IG6tajCl&wze({I)eQV;=oByHUp|7)J0S;F{Jyp_! z#2h_X8T?6mavTd_T3kRiRS_7XC`7n?3%p`^#sM>QvQSt@aq!t_;;jPf4Tse6Z0Qvp9P=`f$;Ie z;it}DUHtow<^C*?en`6U$r7^1TM5~j6$BJSh$4Y#`9)6h>lT2moeR?kv>tFGm7?)A z2!IfTNHFmJO(<%b+=k1#U`KbNa`b*Qd(J_#xE#DRfY7S~ekqgwtKVxY0pRlaS#S)c z`a$$g?ZT4ropKgoJ`E-a6xBgIh$HwKX-U25v`m@%+7-=pO)!wNJm)xPENK3qv_BVw zUBlsZ$aePWSPKBiS^An^mV)|kW3tEM*c}R1vRr#8T|zHQL@Z; zB*Op##7c;kJ_SWbo_%sgs|ipDfu5;7G9boSlKm!cD~&-!Q3&!1i26662)DWJYJv;H z5K9hkM{(#Ll>CxRT=Gf~g$ly*N<@Ain!Rh}Bq_bC5P3cFD=bt&ei>kDRw&i2mV-5G z@F;>O0+goqqsYfltRF59wb3eh62hH2LR7UFGWD1H?}@}z%Rwm>&4BP@$(ab#e;NG zRG0OI0EM6Ua@}A+LRyDaFdO3M)|o#L$((;K2#+6W zUJKLoZ;SsAw8sTd|8*e{{`U{;xv6&D=67_y6`(^C0vf?H^A0kze(E5o&ys=jCc@=U zo0b2sYiaO0N|U=l@Bj*-8^Y;j2|`3@4s4mRdC~UAz3Cx%jgh$DLL(+x{2Yu)ivXVV z%Nda5jtLPri)q$U?5h*=V#y>Y+z=v)1w-6t0!o9YL{?++nOfZ}aSMr@`YlO4n>zCg z-S>a~N1nV1()_o{Kd0IsXpaQ|m;!)9b~_Fq9co^)}! zX%+;MrsF7X|BueNaMu36S}#uRi^so@(i5j4000CMaiNxW=B%q+q;!8`-jn`%Re;kp`_12CCgI>HGw#W?@6*hrz1WL8XWAeuXY$!I8 z_8dg%qCF!~`c90X9g*>ZSX?h9JSDD+{ti|D3WCbrH{T_+>zP7`^xLw21FKF4Lbdw` zTnxYPV^7|UY=8f@Xn&wR0zg5x0+JSiA3xf74|VQuVIre_Tpysm&)k;ZFd+&#M4=DV zzb-Rd&P)XDnS3H{_ZI+}c?gm!0)hwNOV$D9{#@aru3e<<<8*D|(Fub{&O{YP!1lq$dofSGze2kN zfNcdN!N8Yaci=~p&FEK#Fz-m@+#Iv^*$m%)Q8l?n5L?Oa~Z1ZBCb&<@kS3eA|F(NC7$T+Xt3ecV{c|`errXIc0;AD)y&l2IG z4z~&JBDU6{$0|?$8CpN{Ls-wzc^_OvgeE6U2IBr#f9}u^kZt;F>&>@&I$tFK5;p(< zzu~8~za{e%=y2rSsmmJB%1F(lC(t}29W6btQ;fZoruSPT;F=nZ5rKq&KmpOxjm{Z) zT>igW%2RtlydiB+^{p9XOrIm8c}ckdNXil`fGpw?w03(-z_=``#O2VB(~dQ&yYDTn z)45-nH2r1p?@M>r-VKc-Xj8ktjdr^LYBAh^_kHu|IB zBJAJnFu_|drO92gD{PJlEC>)Hg7C|r{tdJ8|Mhz)PdoqG$Y5U8AipmMg6|E`j7^npI~GR`?FlY^2x z`h524^oq>93Eq1yP+2x>|6dBA5S7|v09f4NCVPHE^OHbE7{t%clyFf(AU-w~3Gx`0 zM{spL>;29A8|c;qa_V#@1OZJ>2ss6>{ru4Xh8g*v(=NZQFdr^}BEOLyd|-^%?|!`g z?uF$FD75;>Ol|FhBRun2($upCzEFc-xJLMino}s(1|bO=IWI>fAVdUy#?y}9|DPU$ z7mNZVK$?I_*R^NS$jN{t8&S1JWc+!U#81wxt*1?emc?OQlPp1$^E2fB7M%$q8TAh% z;J!VLcR#p4m_WAKZ(fAJd{_Vqb}S&g;u8n{qgEH&JKhyw`iGod&9eeL2Kc24`lbhQ z*3qr#8UGEaK9Y>)qek>eCce-FL23GcY@a8<^#9X^gn%H1XxRn1LwF~5lkxv|$B91z zOwEO0YhlvqZCV1^q0tEG1e>}5u?Ve>a+>niwv+f|-s=L=`U*TY{m1LkJ%4=N!8;(e zzp?=4WVGMeqFsqVI`m&f7Xlst|DCrEzwPsXdDbrh1`i#YA*errp7m#B1gh;$sNXTdB>k~82q3S4?A@gF@E3~X9WU4xZ z!2&}h$M{DW5w5;{zEG#0GJ{=g8aETfbeVgP7J^OMFUq~cuwgb8Pn2R zI~K{;>fAI62yx0RKoCGU0fbYi)Q_S(`d>hy0#@ijqq+f&>IO`e*PvNgiGWI|G!G%8 z4H=;KOBB2bUfl#y?8|6)UHjYp{-cPaQhO8v3=H}6>#6JNC3=8Q-AzV=XGlySV+eNZ zm~_Iv>^>z(SkC?h1l8u>&z%04NaBSbzul;QsG?aNo@b zKDOcVrM=$oGO*6H0t}{WTHpS!TLCf?UYf^TfY1bE9)#zEc_AR05Y0(c>PJx-y&ua8 zJ)mMA>OE`GGre2t%_Km_jC&y>M4Y3s^l1jc)l}wyBtC%5033z-5WMDy6eB{V7@Ndb z8lSXl0*a3sv6D^r)Z0eT&*3JuB(-iuI4yvM14aIT6Kaj<7ngi=|4qn``p+BYGX|hb zHX|SiAbjO#4!$vp5OjR2K<-bZX(~qrf@TH_4&qH9tb>JhP}BhNIw+`trVgQJcn44) z21Jl0kZNZqg6I2~9(abcb-}f${iVrWpfJw=CpnyU>dU9skdLD$@u;7U91GwI{F&>T z^^n)xM>8C|K%qtbn}7Y~Bd-V0gsJ`KE%2vfJ_P_^{+dZoK>*>7U5)Xd4%Xi)NVacx zrVw!56q&`z&!-V8Q$el8go>hg0L;2f{1Jf+&_!WOv^*eJ?x+0-6z_83Eg$sJ~^~ z!_&ubicNoolbIa!L}45FYMXua=M#J0@VupKdduu-GKxLlw>BFv&FW`Xxwg$@gPGi; z?_=@69(p-T1{^UB2ul6_=y~V_@n5^w)Qz7>)u_0~`f#6f=WvDj^Xz1Dtj6 z>p(aGMjW6B%yKWXMogY5ZkzYkIg)*b1E0U%${kpsAd)@(0!}zG!T;@&kM930r1ozj z+wMQ_I8_u=U$X}(go*%40LlO=hp*lE{c4$Q^gC4usByTGpq%!fY5(JRfEq5`5DJR; zNbA5MDAHr}_=CP*PE5+YlAON0P)5+Z7D06#f+d>}RL(}|FG)ri_Ja{@8vJKaIGObS zC+)nd6+pTyYTTVH!87Z5md>n>%d4}nq5S?vNSF%5p7Z{0_ay)t00OuLz`Q^FsjvWa zxaiGBr^NSPyruej84v7GA)qV)wVnt7d)p#3lt9pqmrn^m$qY*v*wJ%>w7*HDi{Jo- z0I$Pu452*v1gfL=p?_pMdZ(X2p?(-#2rQX;6unb}a*Tl_z!=|glFi35mo!&M6M%4& z|1>7PLPS#YhY^Vnes}aG_w5NrA<3@?|4wO;<5W^hS8YCIi$r1xeCy4tFMHurt2g)_ zlauXsoDi_heXYzOy((u;;gC)yqG|h#*{{1DuzY9D_f9G>IbFHu$#o*YF9L;%6c#)H zg;QYhG}~$Rp8RV>^Ic|nUfQlRaFgdg*z1c6kpKctXoLbk8=QW_mDdm5iB$7G#h|SKry76DZ}12NV&<19pFS{pXff{YwkJv;;Z}Ho@Z}vVD2ABVA|lI%V7iJ%v}d z0%Byk&!)t8_Rur9O-Wo)kMcQ+HPgm=f(jRCsZe&1}97f;?ebgxBCj@ zlix8M^891I^8j4X)rT>95abJMzV61ME5iumQ9Sr%XG3X4we2w5N!6qz&aSr8BP=2% zx&7Lrb*Le$JROh&N%vfx{K-+y0G>JzwCf>T$B{vpHEK_}lA9OknSMb?$KG`F;VWVK z`>p{#Px*`K)EIyQ0bqki!sZ!O?(~`N!YOYwwt3N~aSyf&#}|Pw3^FQ zpUGEO!o)7utK_%`rvViC8=>svv-P2=*S!0-qYofI*{5U34|KKw$l%}Zo813Do>Cb+ zccAzZ#^O*~#|Qyi0L1^Du>h^i3JU7wGM>m1f+dpSk4Z@cYCG=EI~yPv54^`C!!XdALkeWxVPe>PZ10)PR)|NHsGuFEg#9a`B} zxU?gMfGq%kOp5?>2n3d_$F6~8{_Ezu9wUh3eMo(SJc5%&VVmIAdgA{(UT(|byG|b{ z@&}x7|GvgMUv}N0e@CkM^G5gWD0Hd-U^(jmfSb109(ma_tF<$#h39vs5U_7QHRUt? z0(2`t&k<0&RY?-;)9i^1fvp&Tu}>W{TQ|UgWK4qDR9?K$HGjYf4;={JbHyhP-Uc(p zw{0`}&Luik004&FoZWZBUA3Jrdq#EojB4TH&JhB3FfhmTcg6x@eVfRNG$6<{tv{p2 zPyV?g_c`T8F*$a3HNJvP{)Z0+S6}+^1Gm7P<=0UWe-}Dg0L+LR?y5cT(x+F)R`eBK z0CZAdFze4J>^Anxb=kK__x)L7ukt!PdDj`aI=EK~siXfOAsyK4_$azW4D)ys;P zGjxIwFg3hcrf-`!$+TX9$}IpK(SAVF&@L+=cLVvZfWA+=&CdRQ=LLGV-Y_C;AFRLW zWuHED2NpQ_frTvq4BWC~;<4wPSK7IDdFhV;u+9+zc8h@eW5ouT!y2HZO#o@8A4AqW z2eMjS7Z7X)f#K5l%w6|1gCIGeM?((h#eeXdslRwl+SIq8$qy_d0RVt*yKi#e>ZRVc z3sx7e@EGe+`t;NYg4tRDiuR7+AncKK^s~>#8psn0j(uH?pFz^AFC;X=Xy{AZYk&H- zuMXdbY?9A{BtNit1VF-otq)C)OfnhJ7T0rJh2-CY`c~%! zD%jWLKqC|wo#NlQ@albUL)xRyPVZf?CBjG16yn5eT zkap>{hx6*_EWg=cF}MIZ_Obkb{f}#RUvfcZ@2aJR7eh<1onLDpFCgf$0#g4!MUKV? z99lo8UT#?zKGxSZI00`J0>1mvBbOc zf>p)e^E@^%|8W638EB^1fR^+#Yd=4yUf0xbiL@&((2)NA&TGFv`l@%`Hu6hkNAF!! z?uS?Q7hhTMfPz0?tpv6J(8{2X2!wQ;z*%MR zwY-C?S&Uq z_OIwKTnw-RV>A!efSm)NmAe9hdE{-`3(vL|Ty?qtdf=+1ZDI{cUKzhm@%m|EW^Kd{Ki4=f%Rz=qB+eXvn|{(&NZ(mn58 z^EaDUmEYxio>%kH{qjtsy9E3Lp|IoG8{N#~7w@g19vw*JeuW3T_4uMGbLWmtTL=;WvI{>zF=Z=S)dGi~dEQ4imwqBcRCz!blw2GaTOV`yV~E{nhiP~5V*)cfhzuDJ5N73Ehgsd!s_FBJr{b`Ru;An1OJZm1s2 zksxp(iO(Z}=|Jp!Vz~L0KmF{`H);(Lz$ASujepu}eH~o^ki~2Tfsspa`jwcvMB#&hFAu zAOu1{5E4>IPe_1-B$OZ^O$9`ys(e^K8)5@QiULZLo(6>8JJOpViuA5@q?4X(ugT7T z-nl!=rV{+z=tJ+)r_WAB#H}#VgW8k=2Y=Kvmk2;(^-ueA^0!DaS=G-5+aO4}N zxKNABnbpbrr-lR!-9N3~=H>rB_m=-eS;Cj!b*TBm@|FqT`b<#YPg|Mw&YV##JV!NC zY|$L8a)2!Wpy1 z=$M1EjWVie3U(TFValAZu02z;XZPAi8~5%sXVBSMKFi0;>Q@g`Y#F-CD{qW4QJL9( z^ze`R9_)5z&xb3{z5ee04`q9n4|UxmUtF|#;2pzplHVO}c#g`iOUj z{W+!G*ms6b*6BR=*E=j9__A`}UrT4SaA}t_c}BN8)7HH2lQ!J1w#(99wO5Ypw7uG@ ztFP2<{7K6-uYEX4)zbGzn zpSHg0s2dya#xEMZ;R?MN?OMaQo^S0vX-M-b8leBW{>PpAIxQG*(!X|YURv_LyLlg; zsy6bu#5Wh^4e?&K=+YYnLz)n^(kHh0cCppF;OoEQ-urIqf|1`PM$TU|J*V*X1gEHnhkDPGI@2k-7hCAO}lIb#T;^f!9yFDU%+o6xTUJo$KyYzJm zdudzF@Vq+vrbg_^Tv~}g9aT&=W=KY(!orySPIPqZ{8Fcl&kg=Ah^`aq97m_j$%p>Z z@toBB|KI-oCX@NHe)HS$FTegA)k9xmbCb?vj{i1S&3tEM<=`25b}af()U4;uX+iSy zwE6V3`U9`4dilF3+#C3NbpLvc_jiB%>7S$}TnW!q;}e~D7Butz_QD??-G+}=)N0^Y zwSF@f(h=PGr*L%aqh&-0sIpmoH#*%RVkl4g((zgfAOdi`dm zDrz?hB0X_-jq3HkCJ)d_=fK2ja@RTy>h_*633zjvE`e`gnvsD9Pmc};<~K7}Q|HAo z6Xh-*UIa(gzstkNecmO!hrFs+fQxgpcF+4vxO~Nt-;R6(&OwAfPC*C9-~Y}v0Z z_NcyV^QTJ#w-$ZmplzeiAB{U`0NjJ=1n(mV@8;=77PU}n@fmc$Z%>;Jf(C%qEq1_D zu?KF^edN&h25&E0@hHAK$~|!7yeHhF3HO$ZjI0H*CRU#Hh;P&UsJ#cjP_r1@5tnO)Q4axFsgmW3`?Q+n&cduh5lG2kJ-Y)8n?V z2V@gRRc#RD^0;%GO!$+EJt>C9ro zcja?=h_uNAw~;~~9Og{)Tbc14@A03bGSS@F$tC3ZC-M(m$*+TdLG$}%$9^li=6X+Z z51H<_wty`9z5*6JfGuVSXjv0H#X}y4c^?4&k70(7{1TT%VV#u z*K^%~U1+_;NH)Sq^pIr2kq%EfSNP4!(^RS5Fvu;sccuLT#Bp8&=B7R=@4>_7^R?{C z?M%*Rtyaq>9V}oSSDIL-buH@S*+@J9y-&R`@za4)Qya#;XJ?8qB3k__| zi40~knfST$qLRI{P0xP(O~r0yYgkcH5kG}3Kx;Oe`H5#>ACyWZJ9Ryiy|G!#`xJBL zB!%T zuEBfAB;e}2g68!dO19{D9y|3{4pXVsT+Rh9jxA^c8vr|q6W90-_c$K-3|TmIDT~t- zz7(G;Y;9J#`G`O4%YCEt?t=#+*n5(%ew~dLhm~*&ShEI*&JuVV@Dq1 z8sF!ub!`3VY&LOUHhXJR0qeO&%U)Qcr_;c?uF|uYS1Z}d|6WV~D*K+d(vmp|_*4`;{kfjj67y$_qGXIoC+=ez@dp|jw> zBM#u(;NdqjJ4^0T+rzEZ zYo%;}8~M96nnZ><(n~y7vJIp@9b+7f*&^M*TBU1QJozwfml@f|Kjm^;;D|r`zJXw9O+dOZ+tGrd%_*I2tI6Uf&+YkjCNh2CYzAM zZI{3U^ZTz?a@e4s%=~=)Ckq=$*N$}f_YOU~pPk3&1MwVa$Z2;ZhdsZ_#AyKhF&6j_ zpAoS&=e^BGD#?3}f3lvr1SNKNqa0pI9U$DR)_Z>F`;Wq(^PXf2HU_lDn4mp$5%LJ0 zfIrVI*R#WyGq?^2JRrmOGRXFAH?cRiTG*R(zOmKJUMCu${r(pXyK!IQy`$W~o?N<> z$@;9*vCf1)`iBl6cChoF;HZfA9DlNbwG-cew`NSgQZb=xV7qEwJ-!-V7SF|ZmE}GB zT<|IFw@hxg9dUsT7k)-Sf_a-XjxKEGU3v!5;$uyZ$aSWZqZpYMRTqrU)|!E^WX^=uT`%$LY6 z+IcVZo^a=SZ{xj~_sX?lz`x7q-;j?}3V-Luk<}VhfWIT}5#NH|pu5QFKo_Bt;63=% zeT|9rS*s~!1ArrN1z*t$zYpIF{2l3qd*J)*IG@dWtuu1lBJ{o(?<>%IJ1;r@UzCZz zTVQ*_|EuBU>3>DMhaNiez8m5G!djZo*BaQ7D;cHca^MGh4qp#30pj3{tQ<}&=m%&6 zS_m1ywML_1>rUlx`4T?RWAQ$f=0V{9{AXXegm*8+|60v^RBh1ZllRKPza;PZe8+h& z<+V8PN$%~uC){5mU#9nZ6I=LuaT@@fz|(WL3)sRVS#0dyT=xD?DmHMVmSP+Y`($e# z+xtf*r;U&UJOep_e?4HMj@x|9H$v}4JXo&Y19uz#wL5%3_OE{_`&TQhv!ZrHmlx27 zU0!U@3EpEI*jOIl!sgT5BY6LuP45Nofj|725j%_f0l)?PU2;-oxBIV??T0@AUjTkU z@3mU?2jzw!BjNxp5I6jAAfL}Q;63;Nca^}BcWn|L z0)N&Kf5Cgl__oEuhq+wLcS7%BpP>7oK@XAv=)fyw*Z}Zf_yL&z;ScmD{NWeE2kJ#~ zv+Q_wDIW+iz`~bL@CC^k>sVH9ekmUiwsP3^d`a&ecn=;` z2LES2+q1jcGeKp>KfvEDAijE&K4V9tFPwt+JjNs4hkt=s2ebzrpo4-A@Izq>?D9Y~ z03AA!JPg}b+y(%D__Onm<#TyQ9Edn*&=wP$b6CmlXXSC;<31c{VKYu&&tNf&^pc-z zS~Vgmfx5{`F|lOHs=|rZsd5&j=b|48#+~=s+}p|0C!CKLGL| z=m5KbI3ST|(2Zh&Z1Qu&oCcgA+rQDf%s<#^U{ilpv27RfC?Ar;Z5(t3IOD`K(EDq5 zvRH4*4>;<*h;b^zd*s5MeOk7zl`y!J?E~*|xQ9P4t5VC$J!0CmV)-vY2k066OW0d6 z7r+lHP6ugTaHK<CTew4p2 zGyg4QLFj~#2l&Jy9)y4J#`=7=`eYWnd`HR&3f=-gaR6_85BY{Y0KXv@kcCOVC|Lr@ zO&nhnDW2P?FvcMs+3~hr`_ENts<=1sCD|`E?+Lse+ZxXVx&*wHl2(ykaXJWjAe{hA z&X9+Y!f#u02}xRMe>3I5?^t84&%VElVCihr~q%ESqwo;H}8_UZfa) z_3;e0>1?iD->==z=W}I;6-GAgKo+0lL9=r=vw1E7dcbB@46%%f>N|>>#=KW*^&F~i>;Zg+p;{qCI$%pZ_k?>fKev)F0anUqPjL26c&znL(4$UFA9+=`y7i-HT)$Et z&Sic7kPZeGNHhqUXOQ#)z60R_-+|!7t{_ zi1`M#?xeIf2>n<~aV_i|>LWHD{fnKxdY>))^)BnXI+xF_PsIBay~)`>{yD0jE*0yQ z#IvH$H5vxF_`Ndv8_>QYe9QU`G_cdbW+R2~Fk*WK<$iLwjo5zTFP_Io9<$9N70q`# z{#oe#lkncN$H@QQ0>z5*uOX2 zXB`&hv+#M++NPuL@FelA7`M^8%afY|{r-HknMV*$t71e5bHUJHtR1O4v ziphh6ULd{_K9oJaCA$Hcc@*8zr|$^Dy{2dVS}}beYpxSGKB}$L>SYD_hV>$btzH2= z7Wh1ATZ#@g8!6}@^d7k5-txx5Z$2NaT3)qwL(f_<{r(Z$1#RlJeS_>ly;=dUju{o5 zuCG*GTzPPd?@Q7_#F=OzYt85s_m*sf)AXi>y~d1E)bgt3(f*yMD)R#8lC4*}!E#rh zC>PJL_8ntq-?;pD^+DiNk`5Kcx41WS+KnsjA&H$Rr{z*7@#)yQlDJm%*(0)B)oL~C zdIb%d^gXS8Y5SL4}mmpTcr|D!gp zEc`0_omZPda`%u9)vHpj#WSQ$Jkero)R+T%V$;<*nA046c;F{a$PDxy^Iwbk>g=#l zKksh(>bNl;f$?!wYd_;&GpuuU&-QQqN9lNm#DuUy`<+u862FMz8cuQWd^{a|{@dK*5hdx)WW`EC5hTlid^-_9QxhtD#`(BMH^Yn9ruyc-%xw7fg&P_#5U4tLSs;vb!= zm)9P2;)mj&YHvyXS1+#>aEeyoAzFc_XayYvUF_{R3`BH0h?WR{3oX%=cT5c79TMGn z2gC>dAT@SA(T$vMG*Wwf&uo0<*Y-bnPegM%2h%Cu6EQA;KKz4+*BkR>O{d(I2QFdq zkPS=``jd2qtY?bA#Y~RhyxyGmUu6S*#@~{K?qrI@ELQ0`xI-qBT&0e;tD^|STxRmXrJ73P z?)dDJTn8>!%Uhi@+sE_h`clLwEy`k?M*QRBx|Xr#qnJNc!vP(xu2sl z`pwL_+H~^GRgFg;9^&!*=ZypmEl*kG%@*hXqx^`V|BjVd$oLoy-d-BrbkdD<|2YNu zd{04|*&2{$W&vp?oYsI;Qz7}iwv(>$9siBrV+DS+ZlCA#{j~+OuP+LCwACJ)E+dlBseG27uGILS}7kk48~Fca+M`u6w@_gLs8oFsf{ z9m?c0@k)B#p5qz=){qUkPtA|_n{!r{ppxXg@yOo?5xsM4;|e&e!pFA9)fMCwO5g^3 zz?&k_g5E=r_3W1i1^|bITqgIOe)@08llQoNvayWIOBLFCG21RD68$)x5hozeAo9nE zBkXvT&xew+7y7agU916A3*$5X&l!Y5m0>h?lTo{#2#3b>|3X0rI%@b%y|bRnN~#Hb z2i@)C3)=G<3W|f!BDQl}&jXH*&s1;?K41*i^oJYtZ#$i80DwlHZxOKI<0Fr{FOHRc zD$!lxJN525E-$G@taWgji}4+4k2M_BKSj}rcrJ9liTGf$$92H7l6cSbdGszFLu>F?`NS36UI^_Pv{wC-M z_*My-B7HEEUCPVw8aSs3aA-2-WVvz_aZs|8zCS)lt4MAh(%#Hkr>ofA%v^$(_GcU` zU?B@EZ1%4?^x4erW~*4@GCd2LZ($+x&4e%Py_xx^nmI3^=bR1|>jvqwiP4-r5Aa7E zDDJc1I~>jCS@^v7>}R{9$%Ywi@E6lpL3=LuG&brng3=7^r}Kc{LUl*^EMlRB{cDqw zS&Xz7*JNa~epj&x2UINmcmZ2{qJZkKu-{6mxd|fvab8egcAHDMh;eK!pSNj_GdBEi zV>Dp(pQ|i2M@OHO^uup@hM+y>{*rz1oHx&dlMFe!@1YPRvb zlCKq0840r%nrNe#f&UJkFsq4KjT(0BdM@j}N=JM#as7vG@Elaxaz(Ik9;5;Os1wC? zIUq^HWy-7XkI#}{kW~@wVMCgxm^r;VE!VO4=>MZ^Jg*`csU8FX7a0lGLOM$y_!iaA zQU$b`_7djO+A!A6C7TOgl!FKNt!VDgqFOiZ^Z8D?Vb_E3T@pSt?+v!myiD3dZUR#c z?AyKBTvi_BC|RLVOAtBK;{xm=6Vq$e>`qobJ4^eW0O$Se0{%UI#=$Wx)Uk2)e~ z_sz(LJik=QGBPsQmHP$kT85HfqWU-qe3nz7W`i~x*ozyA*lU|DR7YxIuh7|JeG%cH zWw*144|EjS9=J+@~{4wiz-D96kg}e?N_0LlM zw}t9nsNV5`?Oq%FSMKGr=T{o2p3=-~W%wQd!U22$51;Vb>pzkjX0i6lYV({ZT$RB7C1=# zTG&w1Rf|ExVZ$G#M#s`mYS^X=O7`d70;(mV->hU`0lQ6ZZe(fLpp6>VW_cm+2X(oq z*+xAjr@h0RCedENMmA{7$svG0YzI@s+29W@1AZ>|1UqDquV2_`pFm@w{+HLouOaW$zT5=zPu;BK}q@}(6=>1Mg!9qIm_iHFnyUmK~e@ z)aV<$nTGVJQ^4$edDw`Z+>h{gcXAC&RbK}DMEfG}4}A&Ri@ImAF9`B4@BsaLuOS_P zk09tu^T4D-Dh8Ob4;1rQ`;~9VL$Q zz}hnfti!58E<61;8QFAt$499a31(b(_(js;sHqnR+w`UoaRshnd%{R2VUIx{#ORPEz9+%9F9UY873tsfLx=-t z@1YI0%NZIr`H+V1$^0vm<}Qn#eh2h8EG#2CmknB9KryJ9_ighN%A&mlKk2j2x97S4 z7QS7A8SuAB&*d`I>b)6_sD>d+=zy5J1Rj_JI6nvnfd}AjzQ{s&npiT;uYjM+HChlBlpZ%vlu=~%zq4gOF zpB71(X^oQ0c&$xtc7cFB(An{9fnE708_t73fd&IPj zhwbKh-auQdD_|FGv@L#bm6AChJn&B`o%aEMIUY0~^xHStz&6plx9(94zxix7o3M|3 znw9x%Kl$~LoBfx`wov^3{ubJIWz;j1LC@a(Nkcj%*~`*CS}EH@c}0T7M*GO0AIiOe zTeR)wUgt8^e&ibO=JPZee$re}Di#1wfCqR1*@{muU@hmX2p2tlmSW=X_rn&M*}WVU z#V-cdahZm{XM-^3zSuz;n_;3(KdyfFEtl3CXs$PP#iIm|!6scuut>?BcVKDc}NIg}g|s z1r*nxxXV(1%V0fLD2di2FBJD6CyM-{UGC`_(NBrig1nypv^zfnrsg&qkLyPr2_MXq zg;UP7JLOJeQ!>_JZYLZ{+Dm(TY2F|oS@;R%*c|v@X29NT zMh4H{z9Qw49|d-?-#gCunaf$CPt_WP!+OjyHa?W84<&JdUVzq+L4J~r1kK^w!*&X} zFY#Ov`HvRJV$jS7>uObz^5@OQ?XOVgivjNNp>y&tvUtKhj@A<5=H8kKc_p2;VhkF$ zSd3f(4m&US+(EnmtpPLo06yRkcx8JIeObt6TVWG|f4n)9z^L*XjU7Ds;1j_v(CE4T zoUF4+(uX!vPYsNougQjf5-&h2#A=Vk128(y9S;66o-L$)iXbl`shaGN@uzsMIl;i> z(F@Q0E!YJPgMK&5y8Nc*x$Cwc&TiZ~`CfYDe7%|DK{l4=3E%;qK(@-ohv<#9vLd1} z?j^XT+7)`?RiEcPqgV$+pjl7#U|fRr~P>O zu#H4Nk}JYR!p91n_$kpBG`9av@@<9ugr#ZnB4^)AkNA88&&#%_z7r1rvuoMC_Gx6@ zZ$4bVZZl*;qxc`szeRKQ>Zp0DtKsu>#!%WD1bGLH;^g~<=IIO(smd$O=Vq>oo_u~t z#K7^~7XxkDUop$uY?bn``20^FJ@*^rT^~I3!7*N3RJ3cGVd=r~6Mya8dg|E$vD5w- z5;N_>kk~0_`^S#|wNuO|^MfKo!-~}pB;IE7_B*5)@Sldctp2+$%#^)!iYeMDi{nz( zz2dtz`ApvFC{wga&3x)IF2;D0Hs;IKvMwvs^6q<>ygRJ{c00lpU2z^_isyGSd50xx zdGlc_pDN5$fJDVdDB$v@K!e)CTh-g6)i^nwL3_{1DG)7LWLLC4WSFUy%9EU&ih$?= zCnu?F$;ru#&u=<8Y0*YHIc1`)|FAua&m=*jU5wAPldEK#i0{dxe_HKg^jF3>0uIrZ zgje7p@Zxy3e~7oBgP;rOx{j&W zZ&pKk&^~VTVJ7#RdC&g2Sf`cz5VEGg{(PfPcScez(PXOSIEDSuyq1V^&d59S8Y23R z>Wog&+WO>1pKK!ub#m$oKVx;iy^l%`>*PJ*4_Wvo3!j&1+%VrCGd9r}JkJ3iOj-*; zEKT(#I4QP~PWlb=T$0w}JMI3)h9CbFiZMgi85B*%Rj%g5d)zTu0@*P<=QHu@XVe$1 znes8MRGV+1`KOTPd8>nu<>+fk{sOOiAs>CN+CXdHpQ5igniHCgK3uNs;GSpxy+zhv zn#bk7Q|~PxUjlfcPn>+tgO3Vd59{_Nd_4gNTJHA|-1MA*)`)M-r|#u_sqY4FuPGOX zgaQd~qTM`+#t&ly;0r$!xe2VH@Ysy#F8t*(=wX9{YBuOu-zm4}0mpb7ZE@{*1g(%_ zFj~(ZhWm++#rDtwSB!-^hFDtLobhV`&riaaNB*h|-}fOs(x@+5UjRQbX5g~o@t)6j zS2({(m%>TTbT-`W{vO8mrRNtM&0}Y7<+Hd&TFL_}*}Xi9_X#HWsEEmN;$HaL5)SrO zT4zmC>qu9_0fYD0b9TLGZqsklt+lqX?QtdOiuj~yvXP}8#Tu86b)omb&p1r^Ldv^+ zwMWA~-=$$=_N&?8%^H#m1CKMyh{2>h;dCB*IYpfmyq0W)_qemoDF;pC@*EY1A7jIB z^iIZUWFOG_KJqv}U)Qm753qKQOb)WGSZAcXPLYxAzoMjfuFxKC$9P201Njcp%_buc zbNkTrhwG?ktpa-ZP0#$^Ha5o{WBaDi+6&QoD&>3kUDdJ-C5_1!YAB~f>ma#GExVej zB|hkQ{*LE;365lXKOSOR)P_J;xQr5CC}!gLQQg%zZ~*;8@7!9ar@Lr5L~2gmWEjYpizKLw+ImSl7dQaoW*3?g#Wf-$E1ewv3&)tz}bw)3Kkg zX_-R`n%6X;FB{zfgUFXFpLuIB{1y8VlB_xg*`!*ABJc~e z$9e>4h`yzFctQqLy#5H|{Cri-*T-Moh7jy-305~weAwM;c)}>dR z)iMk59)~3Hc>gDjO=}v9PAFN2r5e6=fpwkI^AOqgWSxc9dAa@dopx99b8NL^5y^Q} z)5+~W_cs7L`T!5TDc`r2-bIc12l$`83q7!~`6o0ad$0?7_USGi&mUvG6R?-Uo%*IZ zZVi|odE}u_+v3OT9FDjtry?BJI)%)F7MKgVQ@#|o5bq6+qxw3Np6u?Q2G)8Z@x!EK z+x}GYJU94O0(UNVguBk?n`2=Zzv%>N&c`*5=(Unh&|=Qr&+sheMT+?!z{Q8=!Ny5c zyGnT#_!CF3<+1a(@>t7sJ=L1!ve!3Ab&AMimB5|%5pl z=c5MF27}!X;W=u5v(GJg2&XwSuk;(n9*o=pCcN`nn z@!#x}1(T0BiF`%CfVD!BN5}%^WIG(_8~A}IkQdl?)L=qRZFUy-Le{CaiQt);!Trz9 z)OXWQca-aY0)`HA&d6G1OE9*Yb#qu)8r2Tb7{~?M-~c=v7W54`fG>?}B{+D!J#t!j zCMZ>B44(EE_xWOIT{Ljwi3-QY_&5@iFUw+g74rBaVf=y6sN|fDl*{9FT0DDIiGACzK=r;#>{1LUaP!T-sQl-Y0AdvpHp*;&;Qas=kKmM1<=(+bN zho>q}g{EmWw2z-;oP0fg>RE8ARuh`6JQ+Uw!Q_ZB2f2Qum#9sDZ{I`PCAspJ#~;ef zJ5`+IZNFIBF!qNNF)gQ@@7RLQmfs(575nMphA%nBpY%-g1-W(~*AcHLxo(q|EpN4- zRe4rde*E23Ztf1o z;7laka2}+!lW~+%DC@*;iMIO|+nz%o=<62siM}z0HBm7ZV`A(eCnqOQI?;+e#mvXp zp&yb|APc6`cl;l&ev@z3$BAov7c}?r_U%L`XS)Uba5+9;R`yhi8GrVho^_i3x9DkH z2h7Z#>NoLHe8`;aa^D9@DDZ>U9A(XuvizG)y19$=yUcab$%5wE1IyJw8{~YC6dY0=x>A98WMZTsX`HcqH1N6<;9;lY%O!Ji74gwz0 z1}7_Jp>uQms0RIvlm|CZ-riuP_cd8NEZ1A#-lDeByhW#h;(O{d#X$LTI*}_!pGjGM z;VBQ{44jki=KJIQwR~K<4|b>p%?10f6tK@ICcBm;`Jx@^-R4;1!@L4`ZG9FsopO6^ z=-gbM_oetl<~QwbynnJ@&FvfYhun6XrFwSgrk3rwre~Qd6T6gcWY=9lb)WcNEWi4boE^ApkdbdB`(?mWU=wqeWYagu@yEL1AuYSPn+|!^1Xc9W# zV1>Wij{fJIwSlG(8+H`_G!PVx4i;q z+^gS=`U7miL^qm`tneG3r}yj5B0tq+DP$Qc1I4a{?`<73(>vqVUXcF(0Q?)01FZMh z`n%&5JoUOu(2NKBAh(ojvC{wDvZAgBKKREwbxdWjumd;r{C%wNZP&A0jfwr4X<+TB z-UoaG9H14|_3rci;i^kevRX#EItjV}*`>LX-_5 z3u=>)2ea!)5&5-i!jkj3JVWO~Q`EA^lsx~C6!jVZR0FL$L8qi#26W{^lE=?>s#vep z6fe`B8sGp~B|Ho1|7x6xPR;X+NK==x3sGqW9YRx7XK){fm0+;RB*hN~_YT>wJbI**RT1kJ8J_|bsF>uSs<8szoZ9zeUIvxH9^zwu8W(W zJOFUOm z+iJd2);e7&i=BDZwdLG<^;^ujSHIPatFEmVsARDV9@?goeH1E`PDYv1>6X){{2b?0 z+X?5R4soA&4t=06%vX5YhfXnXCGt!TeNo2IWb{Q@;9?#3sqk~d4>#4Kny+B*ap!{@ zez4J9JQBE2qiFJV>Gj>9<DH*ouSH{ZzeHOPIK+2S+6 zi^q!=;6t{51)gpC<8l?8 zqF!l>$1TWT^O{Vuv51*LiyWXc9zEGF*^AOoPMAo+1UilQS@7(H_`Al+W)bL z>d0aL5&v(vphn#Tk3kUgAU4EYj%NdGx#qB>ya{BF5GPnrui`%4Xnl2^+B$@Mj;6;w;*~oF~c8aw#TlvR#tj@TA-c*k?ocaT-H@n^Fu0ol@wJxr4*hj9-dfw9mrgC zVN=fp-#>rNxA|=7)@aGAx@A?;8EXM};IJ%^v%w33MSW7GY~ji`3cJVqDs2^vdEeH^ z9&*&%+W9|*l8G=Ydd>5BObA;CJ&dlkgsiRe++sbyV4UmWtiwaLc)_6{crOwZMA?wP z9{vG2ZfCn5O0wBm!BDuJ)qNzb^qI21H_@yTAz znvGD90D`(k`DgHeT9scEjIJWbdKg}d1do=Zj~{LD*Go#1Hm_fxn$kH8H%R7iLY_En zrv=F-hbLg)ID2{BEE$p<6Vs>)%7M|ht^^z*v9rmPJ)iVPS9=;7&Yi6s9ORN-T{V&F zaC9CUQ4hP+E!tl@^ZLuu!5$rClUHfL{ooP}|LWmpTqvACQ}bP1#3rj*{jJcH&1H#N zxrTq2E`BW|;;FY_Lau<9!PNf#<0m>f9^BAe{Vv*)-}kzAepFC+ReoBJQvfD!E!{cm z^#0{ddWKe>eA!F{v$1>jX*)TnV}K>Rzfj)mc&~fFs<9_Zt=*hszAzO&&t;S4s8~c7 zTeoxsd@v|7g5YG>t`D?7WNTsTfFGrVpHnfc)K*3FRf!t)z zWt&E)mygHQQqt@Q#t{6B>kU>dJ;JFVPS2W%AlpJv)QaPaAtI)|M#LN^RxBkFIdBDV zMCjh}YRIZ#z}~@$I2~c=+DX*>LD-5T+6I`n|1ENVjaa#upa$Bk2SJ?V7d3inJah?j z)v?J*Q&Up}M#j--DRa6sIS`$MD&pitw$J4vaI01pGuxcr;l=FFtLgfWgL{viThZw?Ll%h?X+?cyxf@)eHAuvIA zu#kXPzg0^ZG@;F&9_1mia6_E?z78Qo0 zoSMCs>fkbPMqKB`4lyxt_qN%KE28dx!vvloNL91RLM@w#iNhi58$aoOn*nP>R?5K0 zD%GqW{FxyKQh|#yF|dudR*Qsr$j^MNx}Ar)ZGQ$9OgLizgS9*Q;rQXLkN@y5x|)5Igb0^|dp>pl#n>yDU^V7@LIuqrOuY zmUJR%#OM!NqZTcJ^0&P8S{+;`X`8+L`9)8|B?UWe-#ptF$x^5J;h?Xks-PS(aGO8& za3a~T(9I+CopN4q%}jHuq~c6ojFfp0w*be(Lc~W_12#k`jVd82X*(AI7t#n++7W0ivn7ycC4*{NQm`%IQcLN-}d2{+Sn{O@9k-x=jJ*#+%{lMeuh7p ze>OnS9RATx8Ir~E5i;kfiYq*_VRplx>uYCSA7Kzjn>1f z>XYLndf2@D`@6+blD>)b>3jVVGPzuGfVa(QN}tNz-ZV8+ag4zD6fD>s#1)y6G(nF77xwB=2Jfg*T0igw2O@<>uuRnzO} z_07L5b=rc7=)p;ShQnChqHW>)FP51;x@fY*60q^h;Dx{5fZVwS64gi=iZ(}vq)*G0 z10jAl$L7a6sf$9{tFdWL3cM7*@lfV;VFKD^1QitppIA+pvn8#V;|y4${DpBORhhM& zIPl}Pz`O}OV6ouQ{qUJ>xOEgU2?apgF_NaY*5^p#&-uA(jFj4W z{^AoUAGmSgy)MWV6_iObW@nE+gJ$R>4V~2~jy1lj1iz*hW1Q)tP1u65Gl*ep$&&Lf zVREYGc!*rjg_;rr2pYpkILnDn{ug9PN@e=^2oxzmPX!hcKhb{HqjQ_*HFgyC@oM9P zK5Ur8!84(v;`9OO_OeVQ-mbQ7A~`xeapluZc;)=R#a)=Yp}1gP?_)ou*%`8iWIe&R z3N%WE1Sc2)Y`AaVos#g9iU6}{W(GaaPG}#i*5V%fQjV&g>9tKJUcta)Zdc4OX%K<& z-B0aLGJ_Q0@x~Q*!=UHGMK`iUsiHD&!Cr`c3V-UZ^C2s@*p}!qP(=7* ze{wU+uEsKnPsMJtRn9N3GIdHp6){+YKdi0I2Ur~y&8Gbi@50IRC#hb?IYtw!$Zfc` zK`~KH8fCQz>XY_|yL$r<*Lui=jmxNG@)$zl15wJ${2Sa2pXV#}Xb~O=>bZ{6w z$Bi7;+U?-&$1tW0Hj$p_wmXzmIT~{h9^)jz$*tez_}+Vk4@=nN>~2$>B(l1?m408& z(b{VUwp}+yy@E>U5kA-0PN*1V3is8h%jT5Q^liQ-;4f+28J~yG(|12^vr?qVaRt1V z#dA6)+Y{+%PJc2h*Z8B6K2-`7nj||fr+3`w_C2!XmVuDs40$Z&@ne|s`X9TRCYZpi z(p$BQx0pwyz?b`+lO-iM0k5j2T@9}}&@nIwt~qeX#YtWC5D@lq%V}UTf9ZZ&s4tF4 z#89}joPO&JL#v%PU#??%7JVDC_bS{Judiv|D9)cHs-x$ThAwvc6PPYy&z)c7JtwEP znXBu+hisR(PO+f&_Wme%VQ+qMOq+H0@5F#Z>}BVH`0ZBz2yUmC;MgC#V6@zSp8=Hd zque%CuB7>0@)qx3SH7w$Cf)WBzVdNijgqWINRxyd{m@>BYU|2XIe>epGDaz0$5G(L zQ{+wr@A`bi#3^iPi4wxWf1GpR8yzy(K~BXp2pWi&DN(=O;ps8WEXG>Lhzt$tZf^GU zbvb)vWG4H9z^woxRkpUCtjQBW840o4rHch7Xn=@g$I;UqQf8?U&5|^Ym@{&0k%_A- zk=q5vFM0>RbA<2D#Z#KpDfDq5$M*ddUiUqfQEHXE-8x|eC``Z;v*&SJeBCD@;wuhm z^LJ@_$$A|L%B21e)S=#jsx%FpiUXM(_#X&c_eqKMXeI3>E7|t>mD&F38ZJ9yx=giIguCBr2lv~t4a+{~=UdmKsD`f`_bT#q zVW6?{wJ|%FeMnUSjXhcr8_iSXD;#) z#L*nCwV-)+gmn??i6N6mDuGnOz{skD(jw>Y$HvCiZ_jqK+T$I#mzae*d;`-+CIhXh zDE>C12SYNETpKs%2 z$~d$LJ3KcT`yPpq<>g0J2vFV_azZj@&<$roVsE*mK_6nkh`Ikx@BCX2YC2Be1l0%Y zFwOlE{6fG|JAbh+%61A2*lc^A;;#;fb&C$uy}j$Xh^#P2_Z&5dY_jt(3EA*!*F(Vv zB87R+?Z0kKDfyFIf6Hg0hc*wC0xcbT1~yDq+f={^J!F-YqdIze05kZ-NkT3Y*_%eU3l)nYIS!{c3K~Ps=f7=XoqM1h>~{qRmP1hFRHWz$ z_csYpoA$^6zniTD0pWy>ljr0@m3cQAF(@_;HuiF+q5i`typXPiBd-}8yv2KYePv|j zwIGbFr>%_>T;1-~`9$LVu(Udn%F0-Pv@;|gkJ9TxM}WcW;cLJ0gVk?W!kb?JiX8=X z#SK?JWeiubZHIpxYw9Akb9f zfj;&gCg=^q?jT{K%?ajW`4#`Gh5iGV;qcPhHFl1m3nGr-t!Sh5mOb}Ul;_pes(^>% zzj99rF@2|z-HUedzF+S|>no>R6lZ?T&qv|-pNiMLjmfes!>*@WBBGHdA7%eOslaLZ zP}(R#fZV#wf{Z8}4yOP<@;_3e8O|Kx0HWCbzdbzP~<+dr@>$7bYL)-Btpcv<1m`=tym5z@xbOLyiu}| zkr2H4Hu1Z$5;b1i)%SW91ZP;33Y~iz`6&-~GUM-Gb53pBE$`XbY<`H(^kJx@u_=;L zdHA`0fQ&L$YT}rFKk>wo_t5k9N!UF?{PjHL7nmGNRL-Ju0;s*l)Y$~wvh0e{ zeLvgd^nnNx>TJ#nYiCH46Y3;=qmu!$=gywl+J9s#;rzYVT2aC4dr7x?pWYIZ#nbqG z5ZssiAXQ*(`YgD!`?@;#ldKMRHkNQL+J-auIhaf-s+c+Bc=JvYppGHCK3^+hr=E(P zJ5~+?Ye|4VQM^tJ;n>9O>I#U=n+l9f=R+@|>)$e+94?BT_@F*t2NoSgcStReBiKvb ztab_z$n!s!?L6&wi8iAWfnj<1@{8Cv$__&!%(`b6^zc9w$b~AW>_2E%e(mv=5ID9F zx2)a=dUqL>-r~AFw=u+%ndrF!K;rLj0?u3)h#0~8{+`50bbH%M4OWJ}qJjc>u96s3 zV!@vKkc?!-{)g7eMSNmnu?}4@6ft`|p}RY9@BY5hcwYDV6Zz?>r>_njAAzW~bQid> z_bt8Ct5taOGx}$%5r!OpVKT?AD{cjakHtDn+y>O#*+<_26=d=8@zJ~*Gc+C9q;c_! zGw)+yFz3g!%8FPjX_h{k30NO3EI?7 zVGYfpef6@ByzQXc$*2`7W;c~3sd}Bk%rlPH8Rrj3rw>nxiz4!lmM8y*j82Oy8SSI% zN|j(3a~9fFzGnVoM>0ZLW{|3!P7!XJs;c^}Qk?&8il08jn~gJnKUFU$_&)J5 zWEW*GD>CF+EPO!GO^rKThB~xuQFpYu(|lNo7l!@yLneqp@-t8ws7QOq5Gv^Dz=pH^ zNH%(^2aWnQ@ntW#?-XxeBWh-UaQq~YCokZbZ$M1*h4jdC7r?wPWa;VYN<1CL>WJ$; zdENo5UU>aiJZjH!C3rR6_lmr(f0H3|PFPKwK|4Do1bhGf!JSTO984!^cXoH{zkNei zB`BnWT%WArlrschR z%j2yZ7Biw;`TEtpft7Fb6P%8k3CVf zbpIT=iYebgZnh!@k1N4G9*zw^=0ZrnUf&CbR< z^A1)K zGGgoFIU_@g1%p<=_}Wq(oIrBu&mW?qDMEl`xGpl$1>d#lS~Tif6|1lJhQ$4uZeHs9 z{g--rKUKAVXlo=%e*NtC@M{7|u|k#brK3M}{nl`Gt}4q$05t%!dc=bLmq)2Z)BwdO zt0V`DPTfnBF8R)dJQHbaj*=!!ERAG>)eljx>1x#(ieVh9qpoSz?kD%GP$_Xj24 z7=F7Wo?CwSVyf3*Ps$o8T_GvYp4q!UWA1%9CC$bu7`o*2l8dz>K2HycKm<4| zIj3BM{We0~Vd(`J`Kd}Dy_!ylVo-r1yk>vz;9wvGso49nez^Anu|kU$&;q3dgmTgF zV+L#OhE=6Op>(doJvR{0>L2sptp~5P4bVHrv2|4|y8PK_L>?T93sQ?zm?$%4DDh$_ zGZhMT7>Hunzx=dh7-dgSe=SDumUMl6Rajf=G;m`d-emt8;D(XI$^*Tp^N+%`BMig$~W>fUy|u1ir)|7qyN1?VXPWYYIyw1i(T&x zv&-bV?KHB9)YaK$K~={+@)W3P-INo&UNHZf>wj&wapl{Y5m$8kwTMo$dxIbGlSCi= z;+IkS5)b7swnRYV#wHOQ(dvn4XXv^&=z0Cg^6fq+<2kUXbUPSK1rp$~pLrFP_@VZm zSW`9t{S;FrI9%*%u?^jks;{dHwxs%2b-@3hbh8mf_8nhYFk!~L44}X9E^ITN0L@{p zEvsN)&*YLA8%(mVfpJhE3mU)Vfhkl7-c}}oJB^h2d|p{K$lMty&bXWwiJ$rgj9AV8 z8w8ZabhJ?>(&@(YQAUtwQ%<3fZw%E&}59-cbR?=JAu^0je62bJ%zaN+IQ zmZ<=!`?WV-tb5+g9}pL8$NrS6MgWl<+(HLvHEJAd2vyZTY3QHX8v69~34QkV#+k5{ z4zHHGl{ujL%arp%YixtxPYsz(RS<9&r_o*?uh^x%WI?2|%i9Z?J=sd9k|T|X25 z;@7KQJi`kaYj$uHJpFDM7m?)mDLzyl6UOfio)mhpAF#uPdlI?{sPeUF0{sf{F>p;- z$JJ`qZ-H3zr1<##&iyR z{BJP=P}zywl{lzVWOK3wwbM?^ZHe3sqt?iR>Exn^Gxw6H(b1%&3vKz;_Bo4^=z!bT z&;}d5p~^{eZ~qS)c?Bn8ovns*C*T;((*(-Cr3JT?;yEjMrf<4|nlo$x0^Np^quJp$if^NuCzD7>I?kFWu93@eVX5H;vo7+JMG}MAUq!qVFli+P} z@zR^;+}vycg;IhjM2mR znoN10jxJtNZ_19uBFYjV$YJG!ehMSh-HJLnvBC?XTH0Eeb_JM_)6m{TJSckbD_Fw> zWjHw@CcmUC%!U&zN8jGjzHx&V|0S}W12k}AOh@2s^~i)5Lm=n+!xgV-ax*&&8ag}s ziU7hi#(at>B`w|3ISso0Slf9HnVXwqP-?D29~tR>5n?>5J^xCd3B^p7E+_6|=IAKSO_k(9BUqHKij zOsuS zcAoSmJ)D~8qb-~L39Lt2lT^@;WHQ`K_bl1bNVgi^;sC4WR?J7T5T zIs*s?AiaP?b?WXZnp_d^5Uvc=(7Z1N?Uq!C%IxtFy>S%{-ld<6d>?_)8 zE1n+>0!tl#kJikpmWEA^S3rhE#K(@&i`}z^ll#w--eQhJXH~SB;o>eHU)0hpf?D?U zu5%AkzbqOx;Ap$OJCP^JkcNn2(zxU@6%xmN6t)H~nxeC^Dy{Au$jdWyCKAG264Ts_ z2H3`dC>>0SZZB$P`%m!KD*xKqK0-Nq#6U88Pl59`gJM1?x}=Dy{+=d2NGHvSHER%! z`Uh&_upO7sS0BO8`(&~G{H{&%psFf)Yu8CTS_RZ!QyVqv6+mAupDAN<=&&AE!oRt(RmM*+|VsPcTZ1p7=(fVQq(Bs>nHG4?+ojB`^?)k zh5D}>7Dqn{DB!!nn{gZl>}ki}PG5nVLQaYrFs;QCX*$dg7S;OeVH~@dO-Am_2LneU z?m-%t+w|JBV}PPkP*A8dK`$YM!Qjr>{XNwMM16&3^5qhGTg_4=Fn6UqDot9V-(bFp1RB(Lxv>48kdxc1M~kFtK@1;h z_y`bs09$KKim8YD2$E7MGDTyz`02~d{E4K9m_H~&v;mPcAg??X=xRFg?K0M(B^g71Io^iB>86MC;52~Cf3?@ zpy&tjm4#wv%9N-wKQ?|*&WjqiYCJyj?0C|c+4FG6$(LJzj^qR?w6_t7&%d=TV!kI4t@Q^vFYT|KnEI1qLOyL z+tyw$LPA@=nk!+lhp4No-);sy*^MbQhQ69wF!)Jr)v=OLQ{xCYrKUH>U3*6>DEaeo zCefLt*k$J8Png_@9KESB)PSnJe&!wu{iA}*ISxRp`>-5~ z0D|&S8G!H-@)HkF2ryyy_cehtv%LPdZ0-FU4wF9w0F!efFE@B)L03WZ)u~{Vb1Ozz zm^dL3(SO~oJ^qVI{v<}msE?Q%lBKQ`e~K6rk+fivDBv80pYJE;1TSoT2M54UI{p=aK_0grjZs4l;j;mI}3 zeRrbWiQFcb;D6m+oa|l*sEk`AVQ-;aeU6nmgc5=~e}otbyd)W9fW?&HWk<>lWkZAQ zhFr#S#6|}lA&Z~wK(jE>vQ+Msc7^#S558V40MLE^uB7jGc8mqG0npPxg`0cMg_ae7Zdu4_~X$Fg994|H*}q!A2rpXG6vpKwHVImy!BL`yuQ4(jW|0)2i6jr&`T@Zde|^pktOEz zPD61(&uUyQOkaOgFXnwU#O5;>Wu1Sp$4Q~yT_jckKAaM{j<#VM_Y0ys`k~26F2IW> zPFXX=KhbGdnYd9G9PpptAsYE?Bk%0&0+bhUsh$Itw72Fl8<@7nZh4p9Ym@+ty??#; zx;@>)P`XgXqAf(Kv~h9Wmn!CcXYX6X`Jegq+>P5fV2Y9LhOc9{j~mQ11u z6mB+f5RljSVKMz7RVDuXcgq0A*mAD~d(6lOf*d1J!GPshJckr_B@dNIzgQa^+2Wn} z*=UdWsuw283@P6MrH&z~sNmyq8>Av{u3-%w`5nE;rHjA4;mywOsXt=rp{#pg0ZBO{Ig z)MH{|`455g&nS}(00Zk&^t;o$p4-P}I%}(&S_2le1ZeBZaYgvNXQ3?-Kms<;kc-~W z5zQUqwFlUm5h!Kg!!|_61LDRSKDk9al&8BD-#3K0p6r_n1xmL_Z zi%sa=*H^V0LvM_GfBu7LY;|ln69T2Y@>jmpDBb;f2u?6WEOJe^+U2t4v@p{iNx1-K18dZwxK<$>gQzy}O8` zdmX1WGi03~KvYpdc%Fn}l)l(>Ld5zLXL?cOTD_Wu2pt2PudG_eeovp1qb6a#Z=4m<1O`^0JK)v^YH@)=L{zO>V|D zw7@jRJAfu~YuakS!Z6ovP49sOmbzT!0%+JprfdfAScdoZ5GpZVgNh4Pb>BddNkf9krfdwk zTwn1f4E*_{H(M|ctprk0!)Kqi@c_a!ZUrb0XwA%1m%sOCfCQ9Qs;cJf>%au7`NcoH zoQmRf1X6&tfjCJ;cv;K{v$A#OY75!fao_pL*^>2s7ceQt#wXuCV9kyO!J|9V4T;qm ziD8A2AmBe)^7Fw6w!aUbhXgGdl=1{){ndwq6_VdxG8|@njReWDKkblewVBN;tWui&DBSk zJkvS=atC$RlcWazx6sExRs$BVfqT?SyjEFcD2Ov{Jih4b>zisZ{*2Mw>VQ>#wI4N> z)|#5R+dkbaLOHuWIiv#dfEWV6^T>l_cv%{;2;0!mk!xXb@xUI^ax~5RZ7Ww-Jix<$ zc~(7K;)(6+qd5H2gb@zH5xT_yDTpj~S>uF;czESHVRVwOUoSZg`>kH&VeD)(dh4zMR@jlLFuZD+&cubFC`8X++8{P3(>Q7c%vJ(;$+of4>WE+l7%mo@L zgWBvBG-vSzCykASP$6Q_IyRBS%zax}+u!7Wvx*2LzsZr)DP~qkqy$Orc*)_PPr7QI zKv6hkVnIP7aEdvxnXR++w%t52LDClcJ)~kZBG3Lmm^s*J|9J@ZqfOk1a`Z<2XOb!v z;xnN9`T1te;`x!6pFKW#1D9i*uV3$E?;urF_)=z!&nilhAlPKlS~s?t1Csg;==VOt zoj>U$nMguhBCOoxXm+WMJpu&~51sjQM&3X)htju~MbYPt{Hj&KQ??~R>T)jkm$txg zlSxJ{n~4XuSlPp{T?~*mjA_JQ_a=>HGIzFt8WJ;osDBhq%U6xvniNTdQ>@vG$Ea~< z`^n9GYqxO{LikEFUH%&bp~vZMIOcECT_4inM3KZLryi2y1nlN3bP6r%(GMS_=waAs zfd9zGC4^*HMs8y8rIVtV%+V|0-b*-tIFrM=id@5KEy3a7`ApBu)D$;qR`V2wmZ=8g zb)IV1ieKbf`BU5qKQoWzi2_ja7Awr@=QDkY{JzG$WRqCXR^(f;9~Q21TAp3xveTkR z?^Oxjb8y7h*S|OLn4ML@vI|B!upd`L)KS(?*s6Ei#jcY2+%|;A7<#aST2oVFX61<* zN=~>Ua^1VTly_M>kB4vl?$daKP1TCya9@3 zRgGk*@zvuKxTu5GWG5`=8+stfNGFBgeD!(Z3p*c`1B4hgxlR5&@OX>t;2!$F4Lr(+FU}YO2IE$Dj+Z6ynb) z_Z3C!XT$lT!ud|0xg^1=4U0|2KWN%)OJqoZGUm?>TqZl6MEZJ>2nh|g&hsIPi^JGE zAT#+vDWz7>^puoDHR56+{v*4+#@yb1jD6C;k>~noW&ZlcxK@TX<#SFB=U`Ss(niu1 zRiadD1~a3c!-F~`Ve35)PaM$A+ie@bCGNs$KLw}8mL0MPvSg^sJg=^WSz_TNK;$zq zE$!9geUkCkme*tVb}Xl(P3p&tN=?u=2S>|B-O77u%~zN=9}8M)H>7Bs=m6=`)Y7Ab z;e3H%vcB`4an(HSd|2;7@ch8o)W@f-oTZTNpLvW#1H}WH9yFL~bjY9O#w~IFA`s+p z#N!<@Jb)weG26+P2eA)IH(T|0N^Y`%Z|~<*s6Np8QFbTu(Izi|8@bTpB*JfSMa>g%*G=j(6eX@LVf zK(Ir?D*h;dE|wAq1%5kjKC1Nse5)LO4+z^i39$96$EY}@%{;h50VK9UMFosso$eR8 zMW>2TkY9e!^HnV%nf^)z+H%0%5sw<-)kI#1Hz_fRH>wl++)!K6=n!*JHy z4{F4Dmxnfy1_`Unv2=2o7+xGP6=$5S>@gcC!-9KvZ=9BPaB6A(Bl*_WRn=D4hpR|% zUf|wS;l_>t3(&7&5beTPd}B(4LV0bZBG{IFv^C zcG1Bd2Mz45^7C!?hkJ&*f}`x}N) zAu}>E7HA-q>_lcD5MZ8stvPV!Cs}Cm!hvCT;94>>0>Od;;>!Htzio}JC*6L;?fzI_ zhs@5R8ThT#JF|zA+ zdwkO!x8iqg0=%abqmTLQJYDeEM+!n1ArOB0oRuY3t`Q34WAcRj?EL>6Z145{q@@k- z1q^FLb{2z;(l&eu_~P`{x#U;9N-dXdm*d68j3G&IU*5{V-hugkh6bzM?cCp)hPz=G z!T)m8CjloNz*Wc5gQ+Ip;g`P{GQD1s)3y~LbZlI#vpzXJx%UqVDoEwFAEh6qS@ys1 zJ6)U%Ot>pSPq~WcNklcVXj4+0TwiXZAMG}D;zB6(w^;hFPs|?4t(DM?o4T~6M%NJ9 z)WnqhgJ2VV4(D@o%`iu;nE}Q^mmjit7?Q%fX-4Kis^4}2-(P>KU}$|fX5Hw1IF{VX zQ4EGAE7EQSd3&1u^DEhDLeRA75bV@o*m&Ih*`;JX+(9k-s8Z}Eq1yj+^Md$reLUc| z_F!bg&-G#M>jsQcYXZdan$Qvl2P+f`M5DeJU0eO~;P^ENINLzrub@%@Q`veK;SJiO+=Z{-p($<$iLFX4% zqGJpTc=~pJp0Pn&%gPTl?gcXPB$+B^X66+kwqHRs!R?PsZb2(S_j4kEObm)*748ou z)6Cq8lr(8a_n1?%vatadk#8RUB_Pl(m$R?3JhPIl&~prs z2g@H-j4kR*uV(qg`vGI2%-Y)LoYDWmenWfkiLMgee|tOQRC(?GT`4Eg9Uc~2lY8LZ zu>@s(bCUJ)X?6;A%u<*2Uycybbtk~2qUR5X0wKS{m5w(-R}rj5*4nI$T7MZlUr}#k z(R>im*Nr#ve}uWVRb3?$#+^uL^L{j8t1I8ZCk|m6l_}wfmeBFKFyO|?O^@T{fdHA9 z#l?_-higg#3tNZMu@*$Z^u{u?b3RgFn%-8j1|s0&<7-uB=|SPKXWpBW6S+b+BE$}u zvyf~(e&L?U7VDGaTKOV(zecy%Axa={&+xdI|HOwF0<`qn1^rJNbra`M-hPB|@?6=i z!$nzOIE0JaXEy^!Ng^C33MyX5B}$p;j9OtS<}SJ4^T;P7^cO;}58s9?t(Yo!`lMw; zj2Higm0%2Qxje3{Juw4e{r&WP=h&jhgSN&Luc588NI#_J{!$-n3^m`@ zDHpjAweo0Ur%qfTkZV1)aa_k>J*J;RGz4Xfli~eZfv7lR+PKuL$va-LMGo;JOl&D2Z>FB;$YW=ZXY-8tTj=}EK7z6R`#x`%&h zE?o`%Wd~O&`J>yX<4(_1$6Yt8SKq%8#Yu{Aaq+n&GVwSZPvd24Wn1cg|NHm%q_+{_ z*+YPFLFydJm+`(ezY}Eyxwp8j0#(&ps-`3w!(h74#37+7{nzAwHV1(eo;z)r4RxeW zjwWq37W2|x^*kPJ;ROs0koH2JfiRRHMGB0V{AyN0;xYPP-{>qZC zLipdU`r8cJcV$6yMP$A03&|^AMq)cVzg>E?EX}gYZN3vd@FGH3_`CAZ=vVlGAGjAv z?w-C2v0Fd+aORE|f+b-ERfv%ssbZh5iDolR(mMDg%v~g^4CNPu!wwu2X0a6x!gqau z*wW?Ua!gIlCrt;5_~}A9;-2Xr>U?)q=L``qSL05byFIN=LZR~(y3Z4vn|HO04GnE2 zPA2-Tz*;Qx39>(G%HplfAHv+yI`78k*HiKz2>^Uj*^2#Wiu5nE86s?E-%qc0gnpun z1(H)>B4PoZr6KJGA3dvEO<59D?MiCwyffp^;;Peidrg2FzI|M2T| z?2GngiF=zF7J$dwII)|ybNky>Hl|d z&{fn@dvn50tN()Dx zGRYRsDRMO?cU-DT$7;>HR}A}36};=bq;__1moJLRHql=0ktz`@(s)$oueLBQFoHNm zdVYDE_bQq#p##z1Tcqbv0KD}u$*LLtt;5SI6`$2G@YvRD-AYI_&#ynxOCKbW8~*!lDBcRKY{^4BHY%YnG`;ZU;_!0iB)!diLGt zmqaL&Fs#W7Ac5k2+J|;pO!fo?pyAQC3M5wt8Rk$?|Ln|i~i{Fkohl4-S|?^+dKt?rgi!{pPY5r&-bSs61rC3zX}Hk_fDj(t=}P2 zS<02Q(^O{qf7PGEa#Zo@oa6XGm|j5#u*1)}*+Vh-wd?dRrg# z2>;cecWV+RwlykrkE6?nk1cpHgNKzX)nkKpQXtwx&kpD@#JJmB`i4x7d!P2#^&p%^ z=R)dLMTKsM|J_p{G9r)(pa>r@1uXB@9F|kW11Y_?gzUNStWq&`uD|De62+<#l(>Ut zs)Ob(Kx7(da#sE5g2;jDDcB(NHjQ>COUo-VZEdQ_S8+q}T1n@N$K37NjC`Q!|37za0nEXh9ccZ+Yk#eVOFjT-Bq-3G$$DwTcSi zWF^b)fak|MY2YaC%!;m&Vy7b*WMT%y=Y0kYH|#p|Cf2r5Hkd*1C0~5KlPQjRqXHW@ za$H4CQpJ+#HA7w90LomYG9yOMH860Bm#yyt)@hVq+1R-Cb@HTR2snzXP7rPyJGVMG zj{%mERh`{eE5B4>PkNN4P2tOvqj4Lnyu0r|NCq(gr>FOhopC(9yo~3kHoA?HzZ8dm z%1xctb}^p25(BH!m5jQ|3g?aQkm?v21u|uiPmG+uK5sHY={!d7MOHtiZdp57TiQP} znBDL+ez*8#0QhfEPOXs`U09*WUqD7HNq+pP=Xf-wz<=RRnfLjVyzBMV;Ew(VmN+O4 zP=1rC+a3drdn{5|Ajpr}r=fMmcqO=SnP|0t@UVcyW-y9qUZ|9YZl(s;l>%j+w^n+Z z`k91TjRwQ^k64cu>L%Vn%+P6+FiiS=RmP{83rVxhQg4{#7 zIzLFkAi+$*m6=HoKA^5 dUCv$*C^!(kdh2RjfTR8(SxF^{8n{X5{{Yrgkp=(& literal 10639 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 diff --git a/share/pixmaps/bitcoin128.xpm b/share/pixmaps/bitcoin128.xpm index d8e41e9ea441..0c4b00e93d0c 100644 --- a/share/pixmaps/bitcoin128.xpm +++ b/share/pixmaps/bitcoin128.xpm @@ -1,384 +1,225 @@ /* XPM */ static char *bitcoin___[] = { /* columns rows colors chars-per-pixel */ -"128 128 250 2", -" c #845415", -". c #895616", -"X c #84581E", -"o c #8D5C18", -"O c #925A15", -"+ c #925E1C", -"@ c #98621C", -"# c #9E711C", -"$ c #A36E1A", -"% c #A96F1B", -"& c #A6711C", -"* c #AC741C", -"= c #B2741E", -"- c #B37C1E", -"; c #BB7C1E", -": c #835B21", -"> c #8F6125", -", c #956727", -"< c #916B2E", -"1 c #996B2C", -"2 c #B47B23", -"3 c #BD7C20", -"4 c #A17330", -"5 c #AB7D3B", -"6 c #C17F20", -"7 c #B9831F", -"8 c #BB842B", -"9 c #BD8533", -"0 c #B68F3D", -"q c #BE8C3B", -"w c #C4801F", -"e c #FE8C03", -"r c #F38A0F", -"t c #FD8E0A", -"y c #FF910C", -"u c #F78F13", -"i c #F98F10", -"p c #F79016", -"a c #FE9314", -"s c #F6931E", -"d c #FD961B", -"f c #FE991E", -"g c #C58421", -"h c #CD8621", -"j c #C78B21", -"k c #CC8B23", -"l c #C2852B", -"z c #C08B2D", -"x c #D28722", -"c c #D38B25", -"v c #DB8E22", -"b c #D28E2C", -"n c #D49323", -"m c #DC9224", -"M c #DC9B25", -"N c #D4922D", -"B c #DF972A", -"V c #DF982E", -"C c #C18D33", -"Z c #C58E38", -"A c #CB9332", -"S c #C2933C", -"D c #CD9339", -"F c #CC9938", -"G c #D19733", -"H c #DA9230", -"J c #D59935", -"K c #DC9C33", -"L c #DC9E3B", -"P c #E49124", -"I c #EA9426", -"U c #E09D26", -"Y c #EC972B", -"T c #F79625", -"R c #F99524", -"E c #F69A26", -"W c #F89825", -"Q c #F2972B", -"! c #F59A2C", -"~ c #F89B2B", -"^ c #E79D33", -"/ c #EF9D31", -"( c #E19F3A", -") c #EF9D3A", -"_ c #F49C33", -"` c #F99E32", -"' c #F49F39", -"] c #D6A13E", -"[ c #DAA33B", -"{ c #E3A127", -"} c #E7A328", -"| c #EDA32C", -" . c #EDA829", -".. c #FFA325", -"X. c #FFAB25", -"o. c #F3A42B", -"O. c #FFA429", -"+. c #F4A929", -"@. c #FFAC2A", -"#. c #FFB227", -"$. c #FFB32C", -"%. c #FFBA2D", -"&. c #EEA830", -"*. c #F7A334", -"=. c #FAA036", -"-. c #FCAB34", -";. c #F4A13C", -":. c #F9A33B", -">. c #F4A83B", -",. c #FFA83F", -"<. c #FDB432", -"1. c #FFBB33", -"2. c #FFB73A", -"3. c #FDB93E", -"4. c #FFC12F", -"5. c #FFC432", -"6. c #FFC338", -"7. c #D2A043", -"8. c #D8A140", -"9. c #EEA144", -"0. c #E2A840", -"q. c #EDA34B", -"w. c #F4A444", -"e. c #F9A642", -"r. c #FBA945", -"t. c #F3A64B", -"y. c #F4A84E", -"u. c #FBAB4B", -"i. c #EEB041", -"p. c #FABA44", -"a. c #ECA653", -"s. c #EEAC5D", -"d. c #F3AA53", -"f. c #FAAE53", -"g. c #F2AD5A", -"h. c #FBB056", -"j. c #F6B15E", -"k. c #FBB25B", -"l. c #DDAF79", -"z. c #E3A962", -"x. c #EBAE63", -"c. c #E4AC68", -"v. c #EAAF69", -"b. c #EEB065", -"n. c #E7B06C", -"m. c #EEB36B", -"M. c #F5B263", -"N. c #FBB461", -"B. c #E6B274", -"V. c #ECB574", -"C. c #E7B57B", -"Z. c #EAB77C", -"A. c #ECB97C", -"S. c #F2B770", -"D. c #F0BB7A", -"F. c #DBB485", -"G. c #DFB888", -"H. c #E4B984", -"J. c #EDBD82", -"K. c #E5BC8B", -"L. c #EABE8A", -"P. c #F0BE82", -"I. c #E0BF96", -"U. c #EDC089", -"Y. c #F0C28B", -"T. c #E5C194", -"R. c #E9C191", -"E. c #E4C39C", -"W. c #EBC699", -"Q. c #EBC99F", -"!. c #DFC3A0", -"~. c #DDCAAF", -"^. c #CFC7BD", -"/. c #D2CBB6", -"(. c #DBC8B1", -"). c #DBCDBB", -"_. c #E2C6A4", -"`. c #E6C8A5", -"'. c #EACBA5", -"]. c #E1C7A8", -"[. c #E3CBAD", -"{. c #EACCAA", -"}. c #EED1AC", -"|. c #E1CDB3", -" X c #E3CFB8", -".X c #E6D1B6", -"XX c #EBD2B3", -"oX c #E3D1BB", -"OX c #EAD6BB", -"+X c #EBD8BF", -"@X c #D3CDC2", -"#X c #D8CDC2", -"$X c #D0CECA", -"%X c #DDD3C4", -"&X c #D3D2CC", -"*X c #DDD5CB", -"=X c #CCD3D5", -"-X c #C9D7DF", -";X c #D2D4D6", -":X c #DEDAD4", -">X c #DDDCDB", -",X c #E2D4C2", -" c #575858", +", c #5B5C5B", +"< c #5F605E", +"1 c #60615F", +"2 c #5F6160", +"3 c #646464", +"4 c #676867", +"5 c #686967", +"6 c #6B6C6B", +"7 c #6F706F", +"8 c #6F7070", +"9 c #717372", +"0 c #777877", +"q c #7B7C7B", +"w c #80807F", +"e c #7F8080", +"r c #838484", +"t c #888987", +"y c #878888", +"u c #8B8B8B", +"i c #8F908F", +"p c #90908F", +"a c #8D8E90", +"s c #8F9092", +"d c #949595", +"f c #979896", +"g c #989897", +"h c #959698", +"j c #979899", +"k c #9A9B9C", +"l c #9FA09F", +"z c #9E9FA1", +"x c #9FA0A1", +"c c #A3A4A4", +"v c #A7A8A7", +"b c #A6A7A9", +"n c #A7A8A8", +"m c #ACADAD", +"M c #ADAFB1", +"N c #AFB0B3", +"B c #B3B4B6", +"V c #B7B8B7", +"C c #B6B7BA", +"Z c #B7B8BB", +"A c #BABABD", +"S c #BFC0BF", +"D c #BDBEC1", +"F c #BFC0C2", +"G c #C2C3C4", +"H c #C5C6C9", +"J c #C7C8CA", +"K c #CACBCC", +"L c #CECED1", +"P c #CFD0D1", +"I c #D3D4D4", +"U c #D6D6D8", +"Y c #D7D8D9", +"T c #DBDBDC", +"R c #E0DFDF", +"E c #E0E0DF", +"W c #DFDFE0", +"Q c #DFE0E0", +"! c #E3E4E4", +"~ c #E7E7E8", +"^ c #E7E8E8", +"/ c #EBEBEC", +"( c #EFEFF0", +") c #F0EFF0", +"_ c #EFF0F0", +"` c #F4F5F5", +"' c #F6F7F8", +"] c #F8F7F8", +"[ c #F7F8F8", +"{ c #FDFDFD", +"} c None", /* pixels */ -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1 Z L >.N b b b b N >.( C > HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX4 L _ *.@.<.$.X.X...X.X.X.X.X.X...X.@.$.<.@.*./ G , HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX< L -.@.$.X...R R R T T T T W W W W W W T T T T R R W ..X.$.@.*.J HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD -.%.X.W R T T W W W W W W W W W W W W W W W W W W W W W W T T R W X.%.+.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS -.$.X.R T T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T T R X.$.-.C HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXF <.@.f R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R W #.<.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX[ <.X.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R X.$.K HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0.$...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W W W W W W W T R ..%.G HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS 1...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ E W W W W W W W W W T R X.1.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.d T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ E W W W W W W W W W W T R @.2.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX7.5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W T W %.z HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.s T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W T R $.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1...R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W R ..1.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0 5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T W 5.8 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX8.$.s W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W T R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.#.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R $.&.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ E ~ W R ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W R @.| HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX] #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ! s e t d ~ ` ` ` ` ` ` =.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXq %.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W E ~ ~ ~ ~ y l.=XI.x.) p a =.` ` =.=.=.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %.2 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5 5.d W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t (.jXVXNXuX@XF.W ` =.:.` W =.:.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ R Q eXDXSXSXDXgX#Xa ` =.=.;.q.W a a R ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3...T W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ` a a.NXSXGXGXAXNXV.a :.:.f c.tX*XE.n.9.R ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T @.@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t H.VXSXGXGXDXmXy.f :.:.a I.hXBXCXNXiX^.' W ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.g HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5.d W W W W W W W W W W W W W W W W W W W W W W W W W E ~ W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` i |.CXGXGXGXCX3X~ ` :.:.R %XCXSXGXAXNX>XW ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX2.W T W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ s t e a W ~ ` ` ` ` ` ` W ! eXFXGXGXSXVX[.d :.:.~ w.uXFXGXGXSXVXW.a ` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T ..@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX9 $.R W W W W W W W W W W W W W W W W W W W W W W E W ~ ~ ~ y F./.B.9.T t t a ~ =.` =.a a.hXDXGXGXSXNXA.d :.e.R v.NXSXGXGXSXNXm.a =.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.= HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX6.d W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ W i &XjXNXfX:X].B.q.T t a d e K.VXSXGXGXDXaXd.W e.e.d E.VXSXGXGXDXvXw.W =.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXK X.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ a ) uXDXSXFXFXCXNXfX:X_.B.q.r .XFXGXGXGXCX3X=.=.e.,.~ %XCXGXGXGXCX1XW ` =.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T $.m HXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHX5.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t x.NXSXGXGXGXSXSXDXFXCXNXmX8XcXSXGXGXGXCXW.e :.e.=.t.uXFXGXGXSXVXE.d :.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHX^ X.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t T.VXSXGXGXGXGXGXGXGXSXSXFXGXGXGXGXGXGXFX}.9.' W e v.VXSXGXGXSXNXm.d :.=.=.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W T @.P HXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ s ;XNXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXNX>X|.V.XXFXGXGXGXFXbXy.~ :.:.=.=.` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXH X.T W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` R ' $XsXNXVXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXCXCXFXSXGXGXGXCXOXa :.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T $.c HXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ~ t.V.`.5XVXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXSXCX{.e.P.'.2XvXNXBXDXSXGXGXGXGXGXGXGXGXGXSXDXjX~.y W =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX: 1.R W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.~ s.fXDXGXGXGXGXGXGXGXSXNXD.f =.=.,.M.L.oXaXVXDXSXGXGXGXGXGXGXGXGXGXAXVX(.t ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %. HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXl #.T W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.:.:.:.:.:.:.:.:.:.e.e.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXzXg.r.f.f.f.r.=.=.g.`.fXBXAXGXGXGXGXGXGXGXGXGXAXjXH.t =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T $.6 HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX~ ..W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX1X,.f.f.f.f.h.h.f.,.~ d.3XVXAXGXGXGXGXGXGXGXGXGXDXsX' f ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W ..~ HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX$.R W W W W W E ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.,.w.>XFXGXGXGXGXGXGXGXSXNX`.=.f.h.h.h.h.f.f.f.f.=.~ ,XVXSXGXGXGXGXGXGXGXGXSXVXT.y ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R $.HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXX %.T W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.e.r.r.r.u.=.x.fXDXGXGXGXGXGXGXGXSXmXA.,.h.h.h.k.k.h.f.f.f.f.:.~ 5XFXGXGXGXGXGXGXGXGXGXCX:XW ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W T $.. HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX8 $.T W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.r.r.u.u.~ K.NXSXGXGXGXGXGXGXGXDXzXj.r.k.k.k.k.k.h.f.f.f.f.f.W V.VXSXGXGXGXGXGXGXGXGXDXuXw.f ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W T $.3 HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXY ..W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.e.e.e.e.e.e.r.r.r.r.u.u.u.u.~ |.CXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.f.f.f.f.,.d.bXFXGXGXGXGXGXGXGXGXDXfXd.d =.` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W O.P HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXO.W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.e.r.r.r.r.r.r.u.u.u.u.r.w.>XFXGXGXGXGXGXGXGXSXNX'.,.k.k.k.k.k.k.k.h.h.f.f.f.e.y.kXFXGXGXGXGXGXGXGXGXDXfXg.d =.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W O.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX$.R W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.:.:.:.:.e.e.r.r.r.r.u.u.u.u.u.u.f.=.b.fXDXGXGXGXGXGXGXGXSXmXJ.r.k.k.k.k.k.k.k.h.h.f.f.f.:.s.mXFXGXGXGXGXGXGXGXGXDXpXy.R =.` ` ` ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX1.R W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXFXxXM.u.k.k.k.k.k.k.k.k.h.f.f.k.~ K.VXSXGXGXGXGXGXGXGXGXCX5X=.~ =.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX+ $.T W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.f.f.=.|.CXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXGXFX9XA.b.u.r.r.u.u.h.h.h.u.r.O.w.:XCXSXGXGXGXGXGXGXGXGXSXhXL.a :.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.* HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXV X.T W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.,.b.fXFXGXGXGXGXGXGXGXGXSXFXVXpX*X[.R.V.M.g.d.d.g.b.T.pXCXSXGXGXGXGXGXGXGXGXGXDXpXe.~ :.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.; HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX| O.T W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXmXuX>X3X3XyXmXVXFXSXGXGXGXGXGXGXGXGXGXAXhXE.d :.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.:.:.:.:.:.e.e.e.r.r.u.u.u.u.=.|.BXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXSXFXFXFXFXFXSXSXGXGXGXGXGXGXGXGXGXGXAXNX>X~ =.e.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.e.e.e.r.r.r.u.u.r.w.>XFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXZXNXeXe.~ e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.=.x.fXFXGXGXGXGXGXGXGXGXGXFXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXCXfXoX:.~ r.e.:.:.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.r.u.~ K.NXSXGXGXGXGXGXGXGXSXZX6XkXmXNXBXDXAXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGX0X'.S.~ =.u.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.r.r.u.~ |.CXGXGXGXGXGXGXGXGXFX4X,.k.D.Q.,XkXmXNXDXSXSXGXGXGXGXGXGXGXGXGXGXGXXFXGXGXGXGXGXGXGXSXVX{.,.f.u.r.u.N.J.{.5XNXBXAXSXGXGXGXGXGXGXGXGXGXFXMXH.W r.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXo.O.T W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.O.s.fXFXGXGXGXGXGXGXGXSXmXJ.r.N.N.N.N.h.r.r.f.J.1XhXBXAXGXGXGXGXGXGXGXGXSXDXjX!.W e.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W T @.g HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXB X.T W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.:.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXuXM.u.k.k.N.N.N.N.N.h.,.e.D.>XNXSXGXGXGXGXGXGXGXGXSXZXjXE.W r.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W T $.- HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXl @.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX2Xr.h.k.k.k.k.k.k.k.k.k.h.,.,.|.NXZXGXGXGXGXGXGXGXGXGXZXgXV.~ u.e.e.e.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.% HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX@ $.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.:.' >XFXGXGXGXGXGXGXGXSXNX{.,.k.k.k.k.k.k.k.k.k.k.k.k.u.~ `.NXSXGXGXGXGXGXGXGXGXSXCX>X=.e.r.r.e.e.:.:.:.:.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.. HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.~ s.fXFXGXGXGXGXGXGXGXSXNXJ.,.k.k.k.k.k.k.k.k.k.k.h.h.k.u.O.2XCXGXGXGXGXGXGXGXGXGXAXhXV.~ u.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` ~ :.:.:.:.e.f Z.VXSXGXGXGXGXGXGXGXDXzXM.r.k.k.k.k.k.k.k.h.h.h.h.f.f.k.=.V.NXSXGXGXGXGXGXGXGXGXSXVX`.W r.e.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXO.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` =.~ Q a a W =.=.t XCXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.h.h.h.f.f.f.f.r.y.kXFXGXGXGXGXGXGXGXGXGXBX,X~ :.e.e.e.:.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W ~ ..HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXI O.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` a z.-X_.B.q.! u C.NXSXGXGXGXGXGXGXGXSXNX'.=.h.h.k.k.k.h.h.f.f.f.f.f.f.f.f.r.w.5XFXGXGXGXGXGXGXGXGXGXCX2X=.:.e.:.:.:.:.:.:.:.:.=.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W O.P HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ t ).jXVXNXaX2X1XBXDXSXGXGXGXGXGXGXGXSXmXA.:.h.h.h.h.h.f.f.f.f.f.f.f.f.f.f.,.d.vXFXGXGXGXGXGXGXGXGXGXCX1X` =.:.:.:.:.:.:.=.=.=.=.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W T $.; HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXo %.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ` y q.fXZXSXSXFXFXFXSXSXGXGXGXGXGXGXGXGXFXxXj.r.f.h.h.h.f.f.f.f.f.f.f.f.u.u.f.W B.NXSXGXGXGXGXGXGXGXGXSXBXoXW :.:.:.:.:.:.=.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W %. HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ` e !.CXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX+Xd ,.f.h.h.h.f.f.f.f.f.f.u.u.u.f.,.T :XFXGXGXGXGXGXGXGXGXGXSXNXE.f :.:.:.:.:.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W R $.HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX~ ..W W W W W W W W W W W W W W W W W W W W E ~ ~ a _ aXFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX7XV.s.:.=.:.,.u.f.f.f.f.u.u.u.r.~ s ~.VXSXGXGXGXGXGXGXGXGXGXAXhXV.d :.:.=.=.=.=.=.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W O.E HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXg $.T W W W W W W W W W W W W W W W W W W W E ~ ~ e G.hXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXVXpX*X_.Z.x.t.:.` ~ ~ ~ ~ ~ ' x.*XVXSXGXGXGXGXGXGXGXGXGXGXDXuXw.W :.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W T $.; HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX %.R W W W W W W W W W W W W W W W W W W W W ~ d T qXgXBXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXaX>X,X[._.T.T.E.|.:XNXCXSXGXGXGXGXGXGXGXGXGXGXSXVX Xd =.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W R %.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHX@.W W W W W W W W W W W W W W W W W W W W W ~ R ` s.H.oXkXNXNXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXDXFXCXCXBXVXVXBXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXAXhXm.a :.` =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXx @.T W W W W W W W W W W W W W W W W W W W W ~ ~ y t a _ g.L.oXkXhXVXCXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXGXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXBX:Xf ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W T $.h HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ d a t a ' s.R.oXnXDXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXZXhXg.y =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ E ~ E W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXO.~ W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ` ` ~ W a a d ! oX6WHCBBCCCCCCZCZBJ`{{{[{][[[[{I%oooooooo}}}}}}}}}}}}", +"}}}}}}}}}}} ooooooo+m[[[[[{[{{{{`HBCCCCCZCCCCBDL~[E%oXr{{{{{{{{{{{{{{{{{{H@OXqCNCCCCCCCCCCCCZBJ'{{{{{[]{[[[moooooooo }}}}}}}}}}}", +"}}}}}}}}}}}oOoooooow`][{]{[{{{{`JBCCCCCCCCBZJW`{{{ZoooB{{{{{{{{{{{{{{{{{{cXoOhDBCCCDCCCCCZZCCCBJ'{{{{[{][''`rXooooooo}}}}}}}}}}}", +"}}}}}}}}}}oooooooo-T[][[[[{{{{]LCZCCCCCCAHY({{{{{{p.o$I{{{{{{{{{{{{{{{{{]0Xo%MDBCCCCCCCCCCCCCZCNK{{{{{[{[''{T-oooooooo}}}}}}}}}}", +"}}}}}}}}}}OooOoooon{'[]]{[{[{{UBCCCCBCGI/[{{{{{{{`4Xo5`{{{{{{{{{{{{{{{{{~:o.3DBBDCCCCCCDCCZCBCDL~{{{{{[['[[[{noooooooo}}}}}}}}}}", +"}}}}}}}}}XooooooX6^['[[{{{{{{WBCCCBDL!'{{{{{{{{{{Y$o.u{{{{{{{{{{{{{{{{{{G@oXeDBDBCCCCCCCZBBDJ!`{{{{{{{{{{'[[[^5ooOoooo.}}}}}}}}}", +"}}}}}}}}}ooooooo@D{'[[{[{{{{/ACBCHW){{{{{{{{{{{{{mXooZ{{{{{{{{{{{{{{{{{{goo+zDCCCCCDCCBBZHY({{{{{{{{{]{{{[[[[{A@ooooOoo}}}}}}}}}", +"}}}}}}}} ooooooo9`'''{[[[{{'HBGU(]{{{{{{{{{{{{{{[r o*R{{{{{{{{{{{{{{{{{'0Xo-BACCCDBBBBDI^[{{{{{{{{{{{{{{{[{['[`9ooooooo }}}}}}}}", +"}}}}}}}}ooooooo+F{'[[[{{{{{!K~[{{{{{{{{{{{{{{{{{/:XX7`{{{{{{{{{{{{{{{{{!-oX6AZCCCNBAKW'{{{{{{{{{{{{{{{{{{[[[''{Foooooooo}}}}}}}}", +"}}}}}}}}oooOoO 7`[[[[[[{{{{[{{{{{{{{{{{{{{{{{{{{K+OXg{{{{{{{{{{{{{{{{{{A+ootACBBCHT`{{{{{{{{{{{{{{{{{{{{{{[{{[[`8 oooooO}}}}}}}}", +"}}}}}}}ooOooooXV{[[[{[{{{{{{{{{{{{{{{{{{{{{{{{{{c ooG{{{{{{{{{{{{{{{{{{dXo@xZBDI~[{{{{{{{{{{{{{{{{{{{{{{{{{{[['{CooooOOoo}}}}}}}", +"}}}}}}}Oooooo.3/[[[[[{{{{{{{{{{{{{{{{{{{{{{{{{{`9Xo-!{{{{{{{{{{{{{{{{{`5Xo:CL!'{{{{{{{{{{{{{{{{{{{{{{{{{{{{[[''{^1ooooooo}}}}}}}", +"}}}}}} OOooooXl{[[{{[{{{{{{{{{{{{{{{{{{{{{{{[^IC%o 9[{{{{{{{{{{{{{{{{{T$oXt){{{{{{{{{{{{{{{{{{{{{{{{{^!{{{{][{[[{lXoooooo }}}}}}", +"}}}}}}Xoooooo$Y[][[[{{{{{{{{{{{{{{{{{{{{{{(YHAAd+o k{{{{{{{{{{{{{{{{{{VoooV{{{{{{`{{{{{{{{{{{{{{{{(TJAC~{{{{[][[[U$oooOooo}}}}}}", +"}}}}}}Ooooo+.9'']][{{{{{{{{{{{{{{{{{{{{`WJABCCA0oo@K{{{{{{{{{{{{{{{{{[y o&T{{{/Grc{{{{{{{{{{{{{`!KDBCCBL{{{]{[{[''0 oOoooo}}}}}}", +"}}}}}}oOoooo m{'{[[[]{{{{{{{{{{{{{{{'~KACCCCCCB2oo:^{{{{{{{{{{{{{{{{{`,oX6']Il3@.V{{{{{{{{{{[^UDCBCCCCCZ/{{{{[]]'{m oooooo}}}}}}", +"}}}}}.oooooo#T[[[{{[{{{{{{{{{{{{{[/IFCCCZCCCCAb%o r[{{{{{{{{{{{{{{{{{I$oorB9$oXo&T{{{{{{{[(TGDBCCCCZCCCBU{{{{{]{[[T#ooooooX}}}}}", +"}}}}}oooooo 6`[[[[]{{{{{{{{{{{{)THCBBCCCCCCZCDaoooM{{{{{{{{{{{{{{{{{{mooo@o oooX8`{{{{{)!HCBCCBCCZCCCCCCG]{{[[{[[[`6 ooooOo}}}}}", +"}}}}}+oOooo g[[[[]{{{{{{{{{{'!KACCCCZCCCCZCCCA0oo#I{{{{{{{{{{{{{{{{{{e oooooooood{{{[~PDBBCCCCCCZCCCCCCCZ^{{{{[[[[[g ooOoo+}}}}}", +"}}}}}oooooooS{[[{{{[{{{{{[/PFCBCCCCCCCCCCCZCCB>o.3({{{{{{{{{{{{{{{{{^:ooooo$-oo+F{/YGCVCCCCCACCCZCZCCZCCBU{{{{{[['{Sooooooo}}}}}", +"}}}} oooooo-R[[[{[{{{{{(THBBCCCZCACZCCCCCCCCZc@OXu{{{{{{{{{{{{{{{{{{K@oo@4kI0 o&HLCBCCZCCCCCCACCCZCCCCCCBH]{{{{][[[R-XooOoo }}}}", +"}}}}oooooo 5`[[[][{[{'LABCCCCZCCCCCCCZCZCCCCAuOoXZ{{{{{{{{{{{{{{{{{{g -tG`{/-oo,CBCCCCCCCCCCCCCCCCCZCCCBAP[{{[[{{[[)5Xoooooo}}}}", +"}}}}ooooooXt''[{[{{{{!BCCCCZCCCCCCCCCZCCCCCCZ9Xo%T{{{{{{{{{{{{{{{{{{cn!{{{{G@oXqDCCCCCCCCCCCCCCACCCCCAHT`{{{{{[{[[[]rXoooooo}}}}", +"}}}}oOoooooc['[[]{{{{IBCZCCCCCZCCCZCCCCZCBAJKooX*T{{{{{{{{{{{{{{{{{'9Xo1){{{{{{{{{{[^PGACCCDZDAAAAAAAAZZCCCCCCB~{{{[{[{[`0ooooooo}}}}", +"}}}}XoooooX1/][{{[{[{'GVCCZCCCCCAeooOoXoOoX6'{{{{{{{{{{{{{{{{{!-OX7GJJGJJHKKGBcddhhhhhhhdddhhhdhhMACCCCAHT{{{][{[[[/3.oooooX}}}}", +"}}}} ooOOoX$I][]]{{{{{JBZCCCCCCCC3oooOooo+.d{{{{{{{{{{{{{{{{{{A+O++@@#@@#@@@@+o@o@@o@@O@@+@O@@@o#cZBBGI/[{{{{{{][[]I@ooooOo.}}}}", +"}}}}}ooooooXB{[[['{{{{WBCCCCCCCAM$oooX@@oooG{{{{{{{{{{{{{{{{{[d oOOooooooooooooooooooooooooooooo>MAK~'{{{{{{{{[{[[{Booooooo}}}}}", +"}}}}}OOooo+ r[[[{{]{{{(ACCCCCCCAho.o=9h3Xo*!{{{{{{{{{{{{{{{{{`4 XXXXooXoooXoo.Xooo.ooXooo.Xoooo.qW`{{{{{{{{{[{{[{[[r oooooO}}}}}", +"}}}}}ooooOoX,/['''[{{{{HBCCCZCCD9o3aMKL-o 0[{{{{{{{{{{{{{{{{{'FVVVVVVVVVBBCVVVVBVVVVBVVVVCBCro+XC{{{{{{{{{{{{{[{[]^,.oooooo}}}}}", +"}}}}}Xoooooo+J{'[[{[{{{WCZCZCCACscGY~]FOo c{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tXo$T{{{{{{{{{{{{[[[[{JOoOoooO }}}}}", +"}}}}}}oooooo d[[[[{[{{{'DBCCCCBAI~`{{{gXo@K{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{^3o 6'{{{{{{{{{{{{[{[[{d oooooo}}}}}}", +"}}}}}}ooooooX3/['{'{[{{{YBCBAHT){{{{{]7Xo,/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{I$o d{{{{{{{{{{[{{{[[[/1.ooOooo}}}}}}", +"}}}}}}Xoooooo@G{[[[{{{[{)DGU/{{{{{{{{T%o r[{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{noooG{{{{{{{{{{{]['[[{G+OoOOoOX}}}}}}", +"}}}}}}}oOooOo t[[[[[[{{{{)'{{{{{{{{{{Vo+.n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[woX-~{{{{{{{{{{{{{[[][r oooooo}}}}}}}", +"}}}}}}}ooooooo%T{''[{[{{{{{{{{{{{{{{{dXo@I{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{^,oX0[{{{{{{{{{{{[[[[[T%XOooooo}}}}}}}", +"}}}}}}}oooOooo g{[[[]{[{{{{{{{{{{{{{`5X.<`{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{G@oon{{{{{{{{{{{[{{[[{g OooooOo}}}}}}}", +"}}}}}}}}oOooooX-~['][{[{{{{{{{{{{{{{U%O y{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{kXo#K{{{{'){{{{{{][[[~-XOooooO}}}}}}}}", +"}}}}}}}}ooooooooc[[''{[{{{{{{{{{{{{{B+oXV{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{]9.o,/{[^IG~{{{[{[][[[cXOooOooX}}}}}}}}", +"}}}}}}}}}ooOooOo,![[]{[{{{{{{{{{{{{{uXo$T{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{!-XXr(WJZBI{{{{[{[[[[!:o+ooooo}}}}}}}}}", +"}}}}}}}}}ooooooook[[[[{[[{{{{{{{{{{!3oX5/''[[][[[[[[[['[[[[[[][][[[[[[]][][[[[]][[[[[[[[[A+ooaGBBVH'{{{{{[[[[{koooooooo}}}}}}}}}", +"}}}}}}}}}}ooooooo*I[[[[{{{{{{{{{[~Ic#oo-9989899998799989999899978999997789999897899989879,oo@cZCCD/{{{{]{[[[[I-ooooO+o}}}}}}}}}}", +"}}}}}}}}}}oooooooor'[[[[[[{{{{{YGCZroOooX......X....XX..X..X..XX...X.XXX...X..XX...XX...XXoo>BZCA~{{{{[{][[[`r.ooooooo}}}}}}}}}}", +"}}}}}}}}}}}ooooooo@Z{[[[{{{{[{{TBBZ5 oooXoooooXooXoooXXXoo.XoXXXo.XoXXXoo.XoXXXoooooXoooXoo 9ACCW{{{{{[[]{[{Z@ooooooo}}}}}}}}}}}", +"}}}}}}}}}}}OOooOoOo,W[[[][{[{{{{TCB8,2,,<<,<<<<<3,,,379777977779799797977997799953<<<,1,112,jCCT{{{{{][{][[E,oooooOoO}}}}}}}}}}}", +"}}}}}}}}}}}}Ooooooo r`'[]{]{{{{{{YBBCCCCVCCBCCBBBCJT/`''`''`''''''`'`'`''''`])!IFCCCVCCCVVVBCCT{{{{[{{][][`rXooOooo+}}}}}}}}}}}}", +"}}}}}}}}}}}}.Oooooooon{'][[][{{{{{TCCVCZZVZZCBVFI/{{{{{{{{{{{{{{{{{{{{{{{{{)TGAVCCVZVZCZCZCCZW{{{{{{[[]{[]mooooooooX}}}}}}}}}}}}", +"}}}}}}}}}}}}}ooooOoOo#J{'[[{{{{{{{{WABCCCBBBAL~[{{{{{{{{{{{{{{{{{{{{{{{{`!KDBCCCCZZCCZCZZCBD!{{{{{{]{[['{J$oooooooo}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}Oooooooo,R['[[[[{[{{{{~DBBBDHW'{{{{{{{{{{{{{{{{{{{{{{{{'~UDCBCCCZCCCCCCCCCCBF/{{{{{][{'''{W,XOoooOo+}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}Xooooooo.6^[[['{[{{[{{{(KFU({{{{{{{{{{{{{{{{{{{{{{{{{/THBNCCCCCCCZCZCZZCCCCL){{{{][{][[[[~8 oooooooo}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}OooOoooo w/[['[[[{]{{{{{'{{{{{{{{{{{{{{{{{{{{{{{{`!KABCDBCCCCCCCZCCCCCCCDW]{{{{{{{]][[{/q ooOooooo}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}oOoOoooooy({'[[[{[{{{{{{{{{{{{{{{{{{{{{{{{{{{`~PGCCCCDBBCCCCCCCCZZZCCZL/{{{{[{{{[[[[[/tooooooooo}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}Oooooooooy/{'[['{]{{{{{{{{{{{{{{{{{{{{{{{{/YHZCBCCCCCBDCCCCCCCCCBBZJ~{{{{{{{{][[[[{`tooooooooO}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}XooOoooooor/['[{''{'{{{{{{{{{{{{{{{{{{{(WHDBCCCCZCCCCBDCCDBCCCCBCJ!]{{{{{{][{]{[[[^rooooooooo.}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}.oooOooooo0!{[[[]'{[[{{{{{{{{{{{{{{'!LDBBCCCCCCCCCCCCCCCCCCCBZL~]{{{{]{{]{{[[[[{!0oooooooooo}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}XOooooooo 4I{[[[[[{{{]{{{{{{{{{{`PABBCCCCCCZCCZCCCCCCCBBBDGY({{{{{{{][{[{[[[[{Y4 oooOoooOX}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}ooooooooo.-A[{[[[[[[{{[{{{{{{{{(TLFZCBBBBBCBCBCBBBBBZFLW({{{{{{[{{{{{[[[[[[[A- ooOoooooo}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}ooooooooO.@g/['[[[{][[{[{{{{{{{{{'(!YIKGFDDDDDHKIWQ)'{{{{{{{{{{{{]][{[[[[/g@Xooooooooo}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}.oooOoooooX6I[[[[['{]{{[[{[{{{{{{{{{{{{]]`''][{{{{{{{{{{{]]{]{[]{[[[[[[I9.ooooooooo.}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}.ooooooOooX=c^{[['[[{{{[{{{{{{{{{{{{{{{{{{{{{{{{{{{][[{{{[{{[][[[][{^c%XooooooOoo.}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}oOooooooOooo6S`[']''[[]{{[[{{[[{{{{{{{{{{{{{{{]{{{{{{{]{{[[[[[[[[`S6oooooooOoooo}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}} ooooooooooX@wK'{[[[[[[][{{[[{{]{]{][{{{{{{{{{{[{]{[{{[[[{]''{'Kw@XoooOoooooo }}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}oOooOooooooX#wJ`{[[[[[[[[{]{]{{{[{{{]{][{[[{'{'{'{'[[[[[[[`Jr$XoooOooooooo}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}.oooooooooOooO9V/[{'[[[[[[{[[[{]{[{['{[[{[[[[[[[[[[''{[/Z9+Xooooooooooo.}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ooooOoOooooo o,jL`{{][[[[[][[[[[[][[[[[[[[[{[[[{[{`Kg,o ooooOooOoOoo }}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}oooooooOoooooX.@4gH~[{[{[[[[[[[]][[[[[[[][{{['^Jk5# ooooooOooooooo}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} Ooooooooooooooo O;qcGT/`[{{{{{{{{{{{{]'/TGc0:o .oooooooooooooo }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}XooooooooooooOOXX .O&30icmmBBBVVBmmcu03&oX XoooOooooooooooo.}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}ooooooooo+ooooOOooX..XX.oooOooooXXXXXooO+ooooooooooooOoo}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}ooooooooooXOXOooooooOoooooooooooooooooooooOooooooooo}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} XooooOoOooOoOooOooOoooooooooooOooooOoooooooooo }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}XooooOooooooooooOoooOooOooooOooooooOoooOoX}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}XoOOoooOOoOoooooooOoooOooooo+oooo+o }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} .oOoooooooOooooooooooooooooX }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} XoOooooOooooOooooX }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} . .. . }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", +"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}" }; diff --git a/share/pixmaps/bitcoin16.png b/share/pixmaps/bitcoin16.png index 5537479095c62d1fd4ab69ea7cf90b6596dacd39..1f459f006a2db5db195084774af8d21bc4d28fcc 100644 GIT binary patch delta 930 zcmV;T16};P2Db;0BYyx1a7bBm000XU000XU0RWnu7ytkRX-PyuR5*=YlS@!rWdMcG ze{&xsH%tNz6p{-qnWT`EA~QM+q-_!^4o;mq3PTsVa9>~5(RC(k9j&kKUFgCNtt+Jv zZF3h$)9Oq}WI}Fg!Xu$=7>Rk3oAUoIw3YF!&f?6sIr9%cYF+zkyG#afQ-jgRK6bf;X+mSJoX!_9Qb_IurhpqNrJI4U*>=bA+nJ8tn`?u?Q z{iCViR4g10)2Dz?D8${m6?w&O@B4V};@olH#A!kZheo3gj^kkMutL{$sA`m5`|et< zP}urla&qeXaDO;V2>|&0z6ra%|C@I&Umh43aAI?F3yDMm&1M6VB*AEGLohH2K@^e6 zX!z{Pm29D~`MRnu|3U(RfLRp9uP?oMX(r$gV&}mFNRotK@7=}p^fa2yCa&MOfx$s9 zy1TpJbRNgen+v%5)z#~|uD`)kN=IC7SMcnavyf#I`hWZSu(7cLi^T$q#R4s(!7R%d z8g!$*y&cs`6%!LaEG{kvlZoUA5705M$I~GQBDBnX?EP6nHkZZ7sgnSJdaaIZE{oLq zIs{&Xfj7YG8G^^-?MNn8$9Rr2xEzW?s# zT0?Jd4*-A>FrHGXzi$$FFok6?V zjC?*%DWho~6n9qR@xA@oxg#gN9x(bCHk%EtR(}iK-A6I=>I@hd7-d+BEWzb+V!yeM z)p&dl2Z-@TV>y}4<|0uwdhz887f5k;7impHT1$iHc`(XQZ!}P=)gbT!2;uPaPfIMD z%|)zMYk~lPFW`GlIqLZKt+(HC4-I)h2+$@;D3$)g!$*%$DOX{VO*nR}AL;ZuzWm~I zZGZb={0ih*f*`y<;Ou+h#0jrWQ4|9JY;SKLq|WS?bT0)&MN}OM(^1gC=*lV+*LH2v zB+d8tUfTdg-8|gabI-Zl-{C(JfZdyK&s;x0SeXA{urz;ppnr7z{X>P`-N_7K1A_mN z1X45OhldtEJbtzL$#LKN_^|Ox2Tk*%K7Zj--}KDe2Zn$YAh#0#X)aF=p2>Gw1%d{~ zs}lMyLReU_1VUOEshGbPOza<Qv2%->U z3_5UeYb!Km8fiN?e|-y)3+X({UBWgEuoJDH(MDqo$kp2VPdW<2*7G8ldPgr||0$GG z*mtiHzkhudt8s^B=RvfH!)B1Q2|~iy?XRDLLddigC(rhGQzJ?+xIGK z&zz@eZ%6&{1(sg{zmD&FEYESALjlo_nDu`8+66wcn`Sp3#9{mAWm9 zv-~AawM@J*hjA+ep-&hZuHACa{W#aGY=Ja;CVyAVXY5f+0I_7K6ItDeb@}OLIi c #DF943B", -", c #D8913C", -"< c #D8923E", -"1 c #DF953E", -"2 c #E28B23", -"3 c #E38B23", -"4 c #EA9023", -"5 c #EB9023", -"6 c #ED9122", -"7 c #ED9123", -"8 c #EE9123", -"9 c #EE9223", -"0 c #F39421", -"q c #F19423", -"w c #F39523", -"e c #F79521", -"r c #F59422", -"t c #F49623", -"y c #F69622", -"u c #F79623", -"i c #F09324", -"p c #F19424", -"a c #F19525", -"s c #F49624", -"d c #F59625", -"f c #F49725", -"g c #F79624", -"h c #F79724", -"j c #F69725", -"k c #F79725", -"l c #F69726", -"z c #F79726", -"x c #F89621", -"c c #F89722", -"v c #F89723", -"b c #F89724", -"n c #F89824", -"m c #F89825", -"M c #F99825", -"N c #F89925", -"B c #F89926", -"V c #F89927", -"C c #F99927", -"Z c #F0972E", -"A c #F7992A", -"S c #F79A2B", -"D c #F79B2C", -"F c #F69A2D", -"G c #F79D2F", -"H c #F89929", -"J c #F89A28", -"K c #F89A29", -"L c #F99A29", -"P c #F99B29", -"I c #F89A2A", -"U c #F89A2B", -"Y c #F99B2B", -"T c #F89B2C", -"R c #F89C2C", -"E c #F99C2D", -"W c #F99C2E", -"Q c #F89D2E", -"! c #F99D2F", -"~ c #E29335", -"^ c #E49639", -"/ c #E2983F", -"( c #F79F35", -") c #F99E31", -"_ c #F89E32", -"` c #F99E32", -"' c #F9A033", -"] c #F9A035", -"[ c #F9A135", -"{ c #F9A036", -"} c #F9A136", -"| c #F9A137", -" . c #F3A03F", -".. c #F7A43F", -"X. c #F8A139", -"o. c #F9A23A", -"O. c #FAA33B", -"+. c #FAA43E", -"@. c #FAA43F", -"#. c #EF9F41", -"$. c #EEA244", -"%. c #ECA34B", -"&. c #F8A440", -"*. c #F9A541", -"=. c #F9A644", -"-. c #F9A947", -";. c #F0A349", -":. c #F5A648", -">. c #F1A74E", -",. c #F7AA4F", -"<. c #E4A458", -"1. c #E4A55B", -"2. c #E8A95E", -"3. c #F2A950", -"4. c #F4AA52", -"5. c #FBAF55", -"6. c #E4A860", -"7. c #EAAC63", -"8. c #EBAF68", -"9. c #F2AF61", -"0. c #EBB16C", -"q. c #F6B568", -"w. c #E3AF71", -"e. c #EBBE89", -"r. c #E0BC93", -"t. c #E3C199", -"y. c #E6C59D", -"u. c #EAC89E", -"i. c #E7C8A2", -"p. c #EACBA6", -"a. c #EBCFAF", -"s. c #F1CCA0", -"d. c #E7CEB1", -"f. c #ECD1B0", -"g. c #E5D2BB", -"h. c #E8D2B8", -"j. c #DFDFDF", -"k. c #E7D5C1", -"l. c #E7D7C4", -"z. c #E5D7C7", -"x. c #E7DACB", -"c. c #EADAC8", -"v. c #E9DCCC", -"b. c #EDDFCE", -"n. c #E5DDD3", -"m. c #E4DFD9", -"M. c #ECE0D1", -"N. c #E4E1DD", -"B. c #EDE3D8", -"V. c #EAE4DD", -"C. c #ECE5DC", -"Z. c #E2E2E2", -"A. c #E5E2E0", -"S. c #E4E4E4", -"D. c #E7E7E7", -"F. c #EAEAE9", -"G. c gray92", -"H. c #EEEEEE", -"J. c None", +"16 16 128 2", +" c #3D3E3D", +". c #3F3F3E", +"X c #3E403E", +"o c #434343", +"O c #444444", +"+ c #454545", +"@ c #535353", +"# c #565655", +"$ c #585858", +"% c #646560", +"& c #656564", +"* c #696A68", +"= c #696A69", +"- c #808180", +"; c #828382", +": c #8A8B8A", +"> c #8D8E8E", +", c #939392", +"< c #929393", +"1 c #939493", +"2 c #959695", +"3 c #969797", +"4 c #979898", +"5 c #999A9A", +"6 c #9A9B9B", +"7 c #9B9C9C", +"8 c #9D9E9E", +"9 c #9D9EA0", +"0 c #A0A1A0", +"q c #A0A0A1", +"w c #A2A3A3", +"e c #A3A3A3", +"r c #A2A3A5", +"t c #A5A6A5", +"y c #A6A6A6", +"u c #A6A7A6", +"i c #A6A7A7", +"p c #A8A9A8", +"a c #A8A9A9", +"s c #A9A9A9", +"d c #AAAAAA", +"f c #AAABAB", +"g c #ABACAB", +"h c #ADAEAD", +"j c #AEAEAE", +"k c #AEAFAE", +"l c #AEAFAF", +"z c #AFAFAF", +"x c #AFB0AF", +"c c #B0B0B0", +"v c #B1B2B1", +"b c #B8B8B8", +"n c #BCBDBC", +"m c #BFBFBF", +"M c #BEBFC0", +"N c #BEBFC2", +"B c #BFBFC2", +"V c #C0C1C3", +"C c #C2C3C3", +"Z c #C3C3C6", +"A c #C6C7C9", +"S c #C7C8C8", +"D c #C8C8CA", +"F c #C9C9CB", +"G c #C9CACC", +"H c #CACBCD", +"J c #CBCCCD", +"K c #CCCDCE", +"L c #CCCDCF", +"P c #CECFD1", +"I c #D0D0D0", +"U c #D3D3D3", +"Y c #D4D4D4", +"T c #D4D4D5", +"R c #D5D6D5", +"E c #D4D5D6", +"W c #D4D5D7", +"Q c #D5D6D7", +"! c #DADBDA", +"~ c #DCDDDE", +"^ c #DFDFE0", +"/ c #E2E2E1", +"( c #E1E1E2", +") c #E1E1E3", +"_ c #E3E3E4", +"` c #E3E4E5", +"' c #E4E4E5", +"] c #E4E5E5", +"[ c #E5E5E5", +"{ c #E5E6E7", +"} c #E6E6E7", +"| c #E7E7E8", +" . c #E8E8E9", +".. c #E8E9E9", +"X. c #E9E9E9", +"o. c #E8E8EA", +"O. c #E8E9EA", +"+. c #EAEAEB", +"@. c #EAEBEB", +"#. c #EAEBEC", +"$. c #EBEBEC", +"%. c #EBECEC", +"&. c #EBECED", +"*. c #ECECEC", +"=. c #EEEEED", +"-. c #EDEDEE", +";. c #EEEEEF", +":. c #EFEFF0", +">. c #F0F0F0", +",. c #F0F0F1", +"<. c #F1F1F1", +"1. c #F1F2F1", +"2. c #F1F1F2", +"3. c #F1F2F2", +"4. c #F2F2F2", +"5. c #F2F2F3", +"6. c #F3F3F3", +"7. c #F3F3F4", +"8. c #F3F4F4", +"9. c #F6F6F6", +"0. c #F6F7F7", +"q. c #F8F8F8", +"w. c #F9F9F9", +"e. c #FAFAFA", +"r. c #FDFDFD", +"t. c #FEFEFE", +"y. c #FFFFFF", +"u. c None", /* pixels */ -"J.J.J.J.J.J.J.1 > J.J.J.J.J.J.J.", -"J.J.J.J.J./ ..| ' ( ~ J.J.J.J.J.", -"J.J.J.< *.{ V $ r U W _ - J.J.J.", -"J.J., o.J 0 # <.w.$.F N H % J.J.", -"J.J.o.T e 1.r.k.x.t.S z B u J.J.", -"J.^ [ Y ! #.z.H.M.n.0.d n m 2 J.", -"J.X.) | =. .h.B.5.f.j.;.v B d J.", -": Q M ` &.>.A.V.p.c.l.4.E n d = ", -"; I b A Z 2.D.s.u.F.a.-.} C w & ", -"J.l g y 6.m.G.q.3.b.Z.,.] D 8 J.", -"J.3 k c %.d.C.v.N.S.y.@.L a * J.", -"J.J.j z x 8.i.g.e.9.+.W t 6 J.J.", -"J.J.+ s h G :.7.O.R B s 7 . J.J.", -"J.J.J.O i f P L K d p 5 J.J.J.", -"J.J.J.J.J.@ 9 q i 4 + J.J.J.J.J.", -"J.J.J.J.J.J.J.X o J.J.J.J.J.J.J." +"u.u.u.u.u.u.u.. . u.u.u.u.u.u.u.", +"u.u.u.u.+ = 3 k k 3 * + u.u.u.u.", +"u.u.u.$ k | .^ ( 2.&.k $ u.u.u.", +"u.u.$ S .H 9 3 8 t { *.S $ u.u.", +"u.+ x *.Q ^ f 2. .3 N T 0.v + u.", +"u.= *.w.7.T b r.! r | 7. . .= u.", +"u., 2.E Z r I r.I ; m Z A 2.1 u.", +". k { P J t &.r.E 6 F { 2.w.k . ", +". k w.2.p E r.*.f [ 2.( K { x X ", +"u.1 >.V - m r.( 0 k e > F 2.1 u.", +"u.& { *.m U w.w.2.2.>.g *. .& u.", +"u.+ p 0.g 5 k v c u 7 0 *.f + u.", +"u.u.# V #.&.2.( K N H .C # u.u.", +"u.u.u.@ t .0.{ ` #.{ t @ u.u.u.", +"u.u.u.u.o % : t t : % o u.u.u.u.", +"u.u.u.u.u.u.u.. . u.u.u.u.u.u.u." }; diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png index 1d42116ef1199d86749d17f1740121a659262f4a..cd83384e257334c766d17a257e3845d680493d00 100644 GIT binary patch literal 39906 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ν2n&n% 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