Browse Source

Merge remote-tracking branch 'bitcoin/0.16' into HEAD

0.16
Adrian Gallagher 6 years ago
parent
commit
ad3c330972
No known key found for this signature in database
GPG Key ID: FE3348877809386C
  1. 2
      configure.ac
  2. 2
      depends/packages/qt.mk
  3. 6
      doc/man/litecoin-cli.1
  4. 6
      doc/man/litecoin-qt.1
  5. 6
      doc/man/litecoin-tx.1
  6. 6
      doc/man/litecoind.1
  7. 115
      doc/release-notes.md
  8. 1
      src/bitcoin-cli.cpp
  9. 1
      src/bitcoin-tx.cpp
  10. 1
      src/chainparams.cpp
  11. 1
      src/chainparamsbase.cpp
  12. 4
      src/crypto/common.h
  13. 1
      src/dbwrapper.cpp
  14. 2
      src/httprpc.cpp
  15. 1
      src/httpserver.cpp
  16. 13
      src/init.cpp
  17. 1
      src/memusage.h
  18. 6
      src/merkleblock.h
  19. 1
      src/miner.cpp
  20. 1
      src/net.cpp
  21. 8
      src/net_processing.cpp
  22. 1
      src/policy/fees.h
  23. 2
      src/qt/bantablemodel.h
  24. 3
      src/qt/bitcoin.cpp
  25. 1
      src/qt/bitcoingui.cpp
  26. 2
      src/qt/guiconstants.h
  27. 1
      src/qt/paymentserver.cpp
  28. 2
      src/qt/peertablemodel.h
  29. 6
      src/qt/sendcoinsdialog.cpp
  30. 2
      src/qt/test/wallettests.cpp
  31. 10
      src/qt/transactiondesc.cpp
  32. 8
      src/qt/transactionrecord.cpp
  33. 4
      src/qt/transactionrecord.h
  34. 9
      src/qt/transactiontablemodel.cpp
  35. 2
      src/qt/walletmodeltransaction.h
  36. 5
      src/rpc/blockchain.cpp
  37. 2
      src/rpc/mining.cpp
  38. 11
      src/rpc/rawtransaction.cpp
  39. 1
      src/support/lockedpool.cpp
  40. 20
      src/sync.cpp
  41. 2
      src/test/allocator_tests.cpp
  42. 2
      src/test/dbwrapper_tests.cpp
  43. 2
      src/test/net_tests.cpp
  44. 4
      src/test/rpc_tests.cpp
  45. 23
      src/test/streams_tests.cpp
  46. 2
      src/test/test_bitcoin.h
  47. 1
      src/test/test_bitcoin_fuzzy.cpp
  48. 2
      src/test/test_bitcoin_main.cpp
  49. 1
      src/txdb.h
  50. 1
      src/util.h
  51. 5
      src/validation.cpp
  52. 2
      src/validation.h
  53. 10
      src/validationinterface.cpp
  54. 7
      src/validationinterface.h
  55. 1
      src/wallet/db.h
  56. 2
      src/wallet/rpcdump.cpp
  57. 12
      src/wallet/rpcwallet.cpp
  58. 2
      src/wallet/test/wallet_test_fixture.h
  59. 1
      src/wallet/test/wallet_tests.cpp
  60. 65
      src/wallet/wallet.cpp
  61. 14
      src/wallet/wallet.h
  62. 7
      test/functional/feature_pruning.py
  63. 94
      test/functional/p2p_sendheaders.py
  64. 1
      test/functional/rpc_blockchain.py
  65. 23
      test/functional/rpc_txoutproof.py
  66. 46
      test/functional/test_framework/messages.py
  67. 12
      test/functional/wallet_abandonconflict.py
  68. 9
      test/functional/wallet_encryption.py
  69. 6
      test/functional/wallet_listreceivedby.py

2
configure.ac

@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 16)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_REVISION, 2)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2018)

2
depends/packages/qt.mk

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
PACKAGE=qt
$(package)_version=5.7.1
$(package)_download_path=http://download.qt.io/official_releases/qt/5.7/$($(package)_version)/submodules
$(package)_download_path=https://download.qt.io/archive/qt/5.7/$($(package)_version)/submodules
$(package)_suffix=opensource-src-$($(package)_version).tar.gz
$(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410

6
doc/man/litecoin-cli.1

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH LITECOIN-CLI "1" "June 2018" "litecoin-cli v0.16.1.0" "User Commands"
.TH BITCOIN-CLI "1" "July 2018" "bitcoin-cli v0.16.2.0" "User Commands"
.SH NAME
litecoin-cli \- manual page for litecoin-cli v0.16.1.0
bitcoin-cli \- manual page for bitcoin-cli v0.16.2.0
.SH DESCRIPTION
Litecoin Core RPC client version v0.16.1.0\-dirty
Bitcoin Core RPC client version v0.16.2.0
.SS "Usage:"
.TP
litecoin\-cli [options] <command> [params]

6
doc/man/litecoin-qt.1

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH LITECOIN-QT "1" "June 2018" "litecoin-qt v0.16.1.0" "User Commands"
.TH BITCOIN-QT "1" "July 2018" "bitcoin-qt v0.16.2.0" "User Commands"
.SH NAME
litecoin-qt \- manual page for litecoin-qt v0.16.1.0
bitcoin-qt \- manual page for bitcoin-qt v0.16.2.0
.SH DESCRIPTION
Litecoin Core version v0.16.1.0\-dirty (64\-bit)
Bitcoin Core version v0.16.2.0 (64\-bit)
Usage:
.IP
litecoin\-qt [command\-line options]

6
doc/man/litecoin-tx.1

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH LITECOIN-TX "1" "June 2018" "litecoin-tx v0.16.1.0" "User Commands"
.TH BITCOIN-TX "1" "July 2018" "bitcoin-tx v0.16.2.0" "User Commands"
.SH NAME
litecoin-tx \- manual page for litecoin-tx v0.16.1.0
bitcoin-tx \- manual page for bitcoin-tx v0.16.2.0
.SH DESCRIPTION
Litecoin Core litecoin\-tx utility version v0.16.1.0\-dirty
Bitcoin Core bitcoin\-tx utility version v0.16.2.0
.SS "Usage:"
.TP
litecoin\-tx [options] <hex\-tx> [commands]

6
doc/man/litecoind.1

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH LITECOIND "1" "June 2018" "litecoind v0.16.1.0" "User Commands"
.TH BITCOIND "1" "July 2018" "bitcoind v0.16.2.0" "User Commands"
.SH NAME
litecoind \- manual page for litecoind v0.16.1.0
bitcoind \- manual page for bitcoind v0.16.2.0
.SH DESCRIPTION
Litecoin Core Daemon version v0.16.1.0\-dirty
Bitcoin Core Daemon version v0.16.2.0
.SS "Usage:"
.TP
litecoind [options]

115
doc/release-notes.md

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
Bitcoin Core version 0.16.1 is now available from:
Bitcoin Core version 0.16.2 is now available from:
<https://bitcoincore.org/bin/bitcoin-core-0.16.1/>
<https://bitcoincore.org/bin/bitcoin-core-0.16.2/>
This is a new major version release, including new features, various bugfixes
and performance improvements, as well as updated translations.
This is a new minor version release, with various bugfixes
as well as updated translations.
Please report bugs using the issue tracker at GitHub:
@ -46,100 +46,71 @@ the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not su @@ -46,100 +46,71 @@ 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
===============
Miner block size removed
------------------------
The `-blockmaxsize` option for miners to limit their blocks' sizes was
deprecated in version 0.15.1, and has now been removed. Miners should use the
`-blockmaxweight` option if they want to limit the weight of their blocks'
weights.
0.16.1 change log
0.16.2 change log
------------------
### Policy
- #11423 `d353dd1` [Policy] Several transaction standardness rules (jl2012)
### Mining
- #12756 `e802c22` [config] Remove blockmaxsize option (jnewbery)
### Block and transaction handling
- #13199 `c71e535` Bugfix: ensure consistency of m_failed_blocks after reconsiderblock (sdaftuar)
- #13023 `bb79aaf` Fix some concurrency issues in ActivateBestChain() (skeees)
### P2P protocol and network code
- #12626 `f60e84d` Limit the number of IPs addrman learns from each DNS seeder (EthanHeilman)
### Wallet
- #13265 `5d8de76` Exit SyncMetaData if there are no transactions to sync (laanwj)
- #13030 `5ff571e` Fix zapwallettxes/multiwallet interaction. (jnewbery)
- #13622 `c04a4a5` Remove mapRequest tracking that just effects Qt display. (TheBlueMatt)
- #12905 `cfc6f74` [rpcwallet] Clamp walletpassphrase value at 100M seconds (sdaftuar)
- #13437 `ed82e71` wallet: Erase wtxOrderd wtx pointer on removeprunedfunds (MarcoFalke)
### RPC and other APIs
- #13451 `cbd2f70` rpc: expose CBlockIndex::nTx in getblock(header) (instagibbs)
- #13507 `f7401c8` RPC: Fix parameter count check for importpubkey (kristapsk)
- #13452 `6b9dc8c` rpc: have verifytxoutproof check the number of txns in proof structure (instagibbs)
- #12837 `bf1f150` rpc: fix type mistmatch in `listreceivedbyaddress` (joemphilips)
- #12743 `657dfc5` Fix csBestBlock/cvBlockChange waiting in rpc/mining (sipa)
### GUI
- #12999 `1720eb3` Show the Window when double clicking the taskbar icon (ken2812221)
- #12650 `f118a7a` Fix issue: "default port not shown correctly in settings dialog" (251Labs)
- #13251 `ea487f9` Rephrase Bech32 checkbox texts, and enable it with legacy address default (fanquake)
- #12432 `f78e7f6` [qt] send: Clear All also resets coin control options (Sjors)
- #12617 `21dd512` gui: Show messages as text not html (laanwj)
- #12793 `cf6feb7` qt: Avoid reseting on resetguisettigs=0 (MarcoFalke)
### Build system
- #12474 `b0f692f` Allow depends system to support armv7l (hkjn)
- #12585 `72a3290` depends: Switch to downloading expat from GitHub (fanquake)
- #12648 `46ca8f3` test: Update trusted git root (MarcoFalke)
- #11995 `686cb86` depends: Fix Qt build with Xcode 9 (fanquake)
- #12636 `845838c` backport: #11995 Fix Qt build with Xcode 9 (fanquake)
- #12946 `e055bc0` depends: Fix Qt build with XCode 9.3 (fanquake)
- #12998 `7847b92` Default to defining endian-conversion DECLs in compat w/o config (TheBlueMatt)
- #13544 `9fd3e00` depends: Update Qt download url (fanquake)
- #12573 `88d1a64` Fix compilation when compiler do not support `__builtin_clz*` (532479301)
### Tests and QA
- #12447 `01f931b` Add missing signal.h header (laanwj)
- #12545 `1286f3e` Use wait_until to ensure ping goes out (Empact)
- #12804 `4bdb0ce` Fix intermittent rpc_net.py failure. (jnewbery)
- #12553 `0e98f96` Prefer wait_until over polling with time.sleep (Empact)
- #12486 `cfebd40` Round target fee to 8 decimals in assert_fee_amount (kallewoof)
- #12843 `df38b13` Test starting bitcoind with -h and -version (jnewbery)
- #12475 `41c29f6` Fix python TypeError in script.py (MarcoFalke)
- #12638 `0a76ed2` Cache only chain and wallet for regtest datadir (MarcoFalke)
- #12902 `7460945` Handle potential cookie race when starting node (sdaftuar)
- #12904 `6c26df0` Ensure bitcoind processes are cleaned up when tests end (sdaftuar)
- #13049 `9ea62a3` Backports (MarcoFalke)
- #13201 `b8aacd6` Handle disconnect_node race (sdaftuar)
- #13061 `170b309` Make tests pass after 2020 (bmwiedemann)
- #13192 `79c4fff` [tests] Fixed intermittent failure in `p2p_sendheaders.py` (lmanners)
- #13300 `d9c5630` qa: Initialize lockstack to prevent null pointer deref (MarcoFalke)
- #13545 `e15e3a9` tests: Fix test case `streams_serializedata_xor` Remove Boost dependency. (practicalswift)
- #13304 `cbdabef` qa: Fix `wallet_listreceivedby` race (MarcoFalke)
### Miscellaneous
- #12518 `a17fecf` Bump leveldb subtree (MarcoFalke)
- #12442 `f3b8d85` devtools: Exclude patches from lint-whitespace (MarcoFalke)
- #12988 `acdf433` Hold cs_main while calling UpdatedBlockTip() signal (skeees)
- #12985 `0684cf9` Windows: Avoid launching as admin when NSIS installer ends. (JeremyRand)
### Documentation
- #12637 `60086dd` backport: #12556 fix version typo in getpeerinfo RPC call help (fanquake)
- #13184 `4087dd0` RPC Docs: `gettxout*`: clarify bestblock and unspent counts (harding)
- #13246 `6de7543` Bump to Ubuntu Bionic 18.04 in build-windows.md (ken2812221)
- #12556 `e730b82` Fix version typo in getpeerinfo RPC call help (tamasblummer)
- #12887 `2291774` Add newlines to end of log messages (jnewbery)
- #12859 `18b0c69` Bugfix: Include <memory> for `std::unique_ptr` (luke-jr)
- #13131 `ce8aa54` Add Windows shutdown handler (ken2812221)
- #13652 `20461fc` rpc: Fix that CWallet::AbandonTransaction would leave the grandchildren, etc. active (Empact)
Credits
=======
Thanks to everyone who directly contributed to this release:
- 251
- 532479301
- Ben Woosley
- Bernhard M. Wiedemann
- Chun Kuan Lee
- David A. Harding
- e0
- Cory Fields
- fanquake
- Henrik Jonsson
- JeremyRand
- Jesse Cohen
- Gregory Sanders
- joemphilips
- John Newbery
- Johnson Lau
- Karl-Johan Alm
- Kristaps Kaupe
- lmanners
- Luke Dashjr
- MarcoFalke
- Matt Corallo
- Pieter Wuille
- practicalswift
- Sjors Provoost
- Suhas Daftuar
- Tamas Blummer
- Wladimir J. van der Laan
And to those that reported security issues:
- Braydon Fuller
- Himanshu Mehta
As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).

1
src/bitcoin-cli.cpp

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
#include <util.h>
#include <utilstrencodings.h>
#include <memory>
#include <stdio.h>
#include <event2/buffer.h>

1
src/bitcoin-tx.cpp

@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
#include <utilmoneystr.h>
#include <utilstrencodings.h>
#include <memory>
#include <stdio.h>
#include <boost/algorithm/string.hpp>

1
src/chainparams.cpp

@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
#include <utilstrencodings.h>
#include <assert.h>
#include <memory>
#include <chainparamsseeds.h>

1
src/chainparamsbase.cpp

@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
#include <util.h>
#include <assert.h>
#include <memory>
const std::string CBaseChainParams::MAIN = "main";
const std::string CBaseChainParams::TESTNET = "test";

4
src/crypto/common.h

@ -82,12 +82,12 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x) @@ -82,12 +82,12 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x)
/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */
uint64_t static inline CountBits(uint64_t x)
{
#ifdef HAVE_DECL___BUILTIN_CLZL
#if HAVE_DECL___BUILTIN_CLZL
if (sizeof(unsigned long) >= sizeof(uint64_t)) {
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
}
#endif
#ifdef HAVE_DECL___BUILTIN_CLZLL
#if HAVE_DECL___BUILTIN_CLZLL
if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
}

1
src/dbwrapper.cpp

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
#include <dbwrapper.h>
#include <memory>
#include <random.h>
#include <leveldb/cache.h>

2
src/httprpc.cpp

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
#include <crypto/hmac_sha256.h>
#include <stdio.h>
#include <memory>
#include <boost/algorithm/string.hpp> // boost::trim
/** WWW-Authenticate to present with 401 Unauthorized response */

1
src/httpserver.cpp

@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
#include <sync.h>
#include <ui_interface.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

13
src/init.cpp

@ -287,6 +287,7 @@ void Shutdown() @@ -287,6 +287,7 @@ void Shutdown()
* The execution context the handler is invoked in is not guaranteed,
* so we restrict handler operations to just touching variables:
*/
#ifndef WIN32
static void HandleSIGTERM(int)
{
fRequestShutdown = true;
@ -296,6 +297,14 @@ static void HandleSIGHUP(int) @@ -296,6 +297,14 @@ static void HandleSIGHUP(int)
{
fReopenDebugLog = true;
}
#else
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
{
fRequestShutdown = true;
Sleep(INFINITE);
return true;
}
#endif
#ifndef WIN32
static void registerSignalHandler(int signal, void(*handler)(int))
@ -679,7 +688,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles) @@ -679,7 +688,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
// scan for better chains in the block chain database, that are not yet connected in the active best chain
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
LogPrintf("Failed to connect best block");
LogPrintf("Failed to connect best block\n");
StartShutdown();
return;
}
@ -884,6 +893,8 @@ bool AppInitBasicSetup() @@ -884,6 +893,8 @@ bool AppInitBasicSetup()
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
signal(SIGPIPE, SIG_IGN);
#else
SetConsoleCtrlHandler(consoleCtrlHandler, true);
#endif
std::set_new_handler(new_handler_terminate);

1
src/memusage.h

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
#include <stdlib.h>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include <unordered_map>

6
src/merkleblock.h

@ -115,6 +115,12 @@ public: @@ -115,6 +115,12 @@ public:
* returns the merkle root, or 0 in case of failure
*/
uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
/** Get number of transactions the merkle proof is indicating for cross-reference with
* local blockchain knowledge.
*/
unsigned int GetNumTransactions() const { return nTransactions; };
};

1
src/miner.cpp

@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
#include <validationinterface.h>
#include <algorithm>
#include <memory>
#include <queue>
#include <utility>

1
src/net.cpp

@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
#include <ui_interface.h>
#include <utilstrencodings.h>
#include <memory>
#ifdef WIN32
#include <string.h>
#else

8
src/net_processing.cpp

@ -30,6 +30,8 @@ @@ -30,6 +30,8 @@
#include <utilmoneystr.h>
#include <utilstrencodings.h>
#include <memory>
#if defined(NDEBUG)
# error "Litecoin cannot be compiled without assertions."
#endif
@ -1219,9 +1221,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam @@ -1219,9 +1221,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
if (!push) {
vNotFound.push_back(inv);
}
// Track requests for our stuff.
GetMainSignals().Inventory(inv.hash);
}
} // release cs_main
@ -1906,9 +1905,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr @@ -1906,9 +1905,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->AskFor(inv);
}
}
// Track requests for our stuff
GetMainSignals().Inventory(inv.hash);
}
}

1
src/policy/fees.h

@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
#include <sync.h>
#include <map>
#include <memory>
#include <string>
#include <vector>

2
src/qt/bantablemodel.h

@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
#include <net.h>
#include <memory>
#include <QAbstractTableModel>
#include <QStringList>

3
src/qt/bitcoin.cpp

@ -36,6 +36,7 @@ @@ -36,6 +36,7 @@
#include <wallet/wallet.h>
#endif
#include <memory>
#include <stdint.h>
#include <boost/thread.hpp>
@ -688,7 +689,7 @@ int main(int argc, char *argv[]) @@ -688,7 +689,7 @@ int main(int argc, char *argv[])
// Allow parameter interaction before we create the options model
app.parameterSetup();
// Load GUI settings from QSettings
app.createOptionsModel(gArgs.IsArgSet("-resetguisettings"));
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
// Subscribe to global signals from core
uiInterface.InitMessage.connect(InitMessage);

1
src/qt/bitcoingui.cpp

@ -923,6 +923,7 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned @@ -923,6 +923,7 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
showNormalIfMinimized();
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
mBox.setTextFormat(Qt::PlainText);
int r = mBox.exec();
if (ret != nullptr)
*ret = r == QMessageBox::Ok;

2
src/qt/guiconstants.h

@ -27,8 +27,6 @@ static const bool DEFAULT_SPLASHSCREEN = true; @@ -27,8 +27,6 @@ static const bool DEFAULT_SPLASHSCREEN = true;
#define COLOR_BAREADDRESS QColor(140, 140, 140)
/* Transaction list -- TX status decoration - open until date */
#define COLOR_TX_STATUS_OPENUNTILDATE QColor(64, 64, 255)
/* Transaction list -- TX status decoration - offline */
#define COLOR_TX_STATUS_OFFLINE QColor(192, 192, 192)
/* Transaction list -- TX status decoration - danger, tx needs attention */
#define COLOR_TX_STATUS_DANGER QColor(200, 100, 100)
/* Transaction list -- TX status decoration - default color */

1
src/qt/paymentserver.cpp

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
#include <wallet/wallet.h>
#include <cstdlib>
#include <memory>
#include <openssl/x509_vfy.h>

2
src/qt/peertablemodel.h

@ -8,6 +8,8 @@ @@ -8,6 +8,8 @@
#include <net_processing.h> // For CNodeStateStats
#include <net.h>
#include <memory>
#include <QAbstractTableModel>
#include <QStringList>

6
src/qt/sendcoinsdialog.cpp

@ -379,6 +379,12 @@ void SendCoinsDialog::on_sendButton_clicked() @@ -379,6 +379,12 @@ void SendCoinsDialog::on_sendButton_clicked()
void SendCoinsDialog::clear()
{
// Clear coin control settings
CoinControlDialog::coinControl()->UnSelectAll();
ui->checkBoxCoinControlChange->setChecked(false);
ui->lineEditCoinControlChange->clear();
coinControlUpdateLabels();
// Remove entries until only one left
while(ui->entries->count())
{

2
src/qt/test/wallettests.cpp

@ -18,6 +18,8 @@ @@ -18,6 +18,8 @@
#include <qt/recentrequeststablemodel.h>
#include <qt/receiverequestdialog.h>
#include <memory>
#include <QAbstractButton>
#include <QAction>
#include <QApplication>

10
src/qt/transactiondesc.cpp

@ -36,8 +36,6 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) @@ -36,8 +36,6 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < 0)
return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return tr("%1/offline").arg(nDepth);
else if (nDepth == 0)
return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
else if (nDepth < 6)
@ -61,14 +59,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco @@ -61,14 +59,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
CAmount nNet = nCredit - nDebit;
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
int nRequests = wtx.GetRequestCount();
if (nRequests != -1)
{
if (nRequests == 0)
strHTML += tr(", has not been successfully broadcast yet");
else if (nRequests > 0)
strHTML += tr(", broadcast through %n node(s)", "", nRequests);
}
strHTML += "<br>";
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";

8
src/qt/transactionrecord.cpp

@ -205,10 +205,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) @@ -205,10 +205,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
if (wtx.IsInMainChain())
{
status.matures_in = wtx.GetBlocksToMaturity();
// Check if the block was requested by anyone
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
status.status = TransactionStatus::MaturesWarning;
}
else
{
@ -226,10 +222,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) @@ -226,10 +222,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
{
status.status = TransactionStatus::Conflicted;
}
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
{
status.status = TransactionStatus::Offline;
}
else if (status.depth == 0)
{
status.status = TransactionStatus::Unconfirmed;

4
src/qt/transactionrecord.h

@ -21,7 +21,7 @@ class TransactionStatus @@ -21,7 +21,7 @@ class TransactionStatus
public:
TransactionStatus():
countsForBalance(false), sortKey(""),
matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1)
matures_in(0), status(Unconfirmed), depth(0), open_for(0), cur_num_blocks(-1)
{ }
enum Status {
@ -29,14 +29,12 @@ public: @@ -29,14 +29,12 @@ public:
/// Normal (sent/received) transactions
OpenUntilDate, /**< Transaction not yet final, waiting for date */
OpenUntilBlock, /**< Transaction not yet final, waiting for block */
Offline, /**< Not sent to any other nodes **/
Unconfirmed, /**< Not yet mined into a block **/
Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/
Conflicted, /**< Conflicts with other transaction or mempool **/
Abandoned, /**< Abandoned from the wallet **/
/// Generated (mined) transactions
Immature, /**< Mined but waiting for maturity */
MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */
NotAccepted /**< Mined but not accepted */
};

9
src/qt/transactiontablemodel.cpp

@ -308,9 +308,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons @@ -308,9 +308,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
case TransactionStatus::OpenUntilDate:
status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
break;
case TransactionStatus::Offline:
status = tr("Offline");
break;
case TransactionStatus::Unconfirmed:
status = tr("Unconfirmed");
break;
@ -329,9 +326,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons @@ -329,9 +326,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
case TransactionStatus::Immature:
status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
break;
case TransactionStatus::MaturesWarning:
status = tr("This block was not received by any other nodes and will probably not be accepted!");
break;
case TransactionStatus::NotAccepted:
status = tr("Generated but not accepted");
break;
@ -469,8 +463,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) @@ -469,8 +463,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx)
case TransactionStatus::OpenUntilBlock:
case TransactionStatus::OpenUntilDate:
return COLOR_TX_STATUS_OPENUNTILDATE;
case TransactionStatus::Offline:
return COLOR_TX_STATUS_OFFLINE;
case TransactionStatus::Unconfirmed:
return QIcon(":/icons/transaction_0");
case TransactionStatus::Abandoned:
@ -493,7 +485,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) @@ -493,7 +485,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx)
int part = (wtx->status.depth * 4 / total) + 1;
return QIcon(QString(":/icons/transaction_%1").arg(part));
}
case TransactionStatus::MaturesWarning:
case TransactionStatus::NotAccepted:
return QIcon(":/icons/transaction_0");
default:

2
src/qt/walletmodeltransaction.h

@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
#include <qt/walletmodel.h>
#include <memory>
#include <QObject>
class SendCoinsRecipient;

5
src/rpc/blockchain.cpp

@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
#include <boost/thread/thread.hpp> // boost::thread::interrupt
#include <memory>
#include <mutex>
#include <condition_variable>
@ -104,6 +105,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) @@ -104,6 +105,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("nTx", (uint64_t)blockindex->nTx));
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
@ -149,6 +151,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx @@ -149,6 +151,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("nTx", (uint64_t)blockindex->nTx));
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
@ -678,6 +681,7 @@ UniValue getblockheader(const JSONRPCRequest& request) @@ -678,6 +681,7 @@ UniValue getblockheader(const JSONRPCRequest& request)
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
" \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
" \"nTx\" : n, (numeric) The number of transactions in the block.\n"
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
"}\n"
@ -747,6 +751,7 @@ UniValue getblock(const JSONRPCRequest& request) @@ -747,6 +751,7 @@ UniValue getblock(const JSONRPCRequest& request)
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
" \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n"
" \"nTx\" : n, (numeric) The number of transactions in the block.\n"
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
"}\n"

2
src/rpc/mining.cpp

@ -477,7 +477,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) @@ -477,7 +477,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
WaitableLock lock(csBestBlock);
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
while (hashBestBlock == hashWatchedChain && IsRPCRunning())
{
if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout)
{

11
src/rpc/rawtransaction.cpp

@ -290,7 +290,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request) @@ -290,7 +290,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n"
"\nResult:\n"
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n"
);
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
@ -306,11 +306,16 @@ UniValue verifytxoutproof(const JSONRPCRequest& request) @@ -306,11 +306,16 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
LOCK(cs_main);
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]) || mapBlockIndex[merkleBlock.header.GetHash()]->nTx == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
for (const uint256& hash : vMatch)
// Check if proof is valid, only add results if so
if (mapBlockIndex[merkleBlock.header.GetHash()]->nTx == merkleBlock.txn.GetNumTransactions()) {
for (const uint256& hash : vMatch) {
res.push_back(hash.GetHex());
}
}
return res;
}

1
src/support/lockedpool.cpp

@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
#endif
#include <algorithm>
#include <memory>
LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

20
src/sync.cpp

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
#include <sync.h>
#include <memory>
#include <set>
#include <util.h>
#include <utilstrencodings.h>
@ -72,7 +73,7 @@ struct LockData { @@ -72,7 +73,7 @@ struct LockData {
std::mutex dd_mutex;
} static lockdata;
static thread_local std::unique_ptr<LockStack> lockstack;
static thread_local LockStack g_lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
@ -102,21 +103,18 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, @@ -102,21 +103,18 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
static void push_lock(void* c, const CLockLocation& locklocation)
{
if (!lockstack)
lockstack.reset(new LockStack);
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
lockstack->push_back(std::make_pair(c, locklocation));
g_lockstack.push_back(std::make_pair(c, locklocation));
for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
if (i.first == c)
break;
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
if (lockdata.lockorders.count(p1))
continue;
lockdata.lockorders[p1] = (*lockstack);
lockdata.lockorders[p1] = g_lockstack;
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
lockdata.invlockorders.insert(p2);
@ -127,7 +125,7 @@ static void push_lock(void* c, const CLockLocation& locklocation) @@ -127,7 +125,7 @@ static void push_lock(void* c, const CLockLocation& locklocation)
static void pop_lock()
{
(*lockstack).pop_back();
g_lockstack.pop_back();
}
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
@ -143,14 +141,14 @@ void LeaveCritical() @@ -143,14 +141,14 @@ void LeaveCritical()
std::string LocksHeld()
{
std::string result;
for (const std::pair<void*, CLockLocation> & i : *lockstack)
for (const std::pair<void*, CLockLocation>& i : g_lockstack)
result += i.second.ToString() + std::string("\n");
return result;
}
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
for (const std::pair<void*, CLockLocation> & i : *lockstack)
for (const std::pair<void*, CLockLocation>& i : g_lockstack)
if (i.first == cs)
return;
fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
@ -159,7 +157,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, @@ -159,7 +157,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
for (const std::pair<void*, CLockLocation>& i : *lockstack) {
for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
if (i.first == cs) {
fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
abort();

2
src/test/allocator_tests.cpp

@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
#include <support/allocators/secure.h>
#include <test/test_bitcoin.h>
#include <memory>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup)

2
src/test/dbwrapper_tests.cpp

@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
#include <random.h>
#include <test/test_bitcoin.h>
#include <memory>
#include <boost/test/unit_test.hpp>
// Test if a string consists entirely of null characters

2
src/test/net_tests.cpp

@ -13,6 +13,8 @@ @@ -13,6 +13,8 @@
#include <chainparams.h>
#include <util.h>
#include <memory>
class CAddrManSerializationMock : public CAddrMan
{
public:

4
src/test/rpc_tests.cpp

@ -256,14 +256,14 @@ BOOST_AUTO_TEST_CASE(rpc_ban) @@ -256,14 +256,14 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
ar = r.get_array();
BOOST_CHECK_EQUAL(ar.size(), 0);
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 1607731200 true")));
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 9907731200 true")));
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
UniValue banned_until = find_value(o1, "banned_until");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check
BOOST_CHECK_EQUAL(banned_until.get_int64(), 9907731200); // absolute time check
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));

23
src/test/streams_tests.cpp

@ -6,11 +6,8 @@ @@ -6,11 +6,8 @@
#include <support/allocators/zeroafterfree.h>
#include <test/test_bitcoin.h>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/test/unit_test.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(streams_vector_writer)
@ -80,14 +77,17 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor) @@ -80,14 +77,17 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
// Degenerate case
key += '\x00','\x00';
key.push_back('\x00');
key.push_back('\x00');
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
std::string(ds.begin(), ds.end()));
in += '\x0f','\xf0';
expected_xor += '\xf0','\x0f';
in.push_back('\x0f');
in.push_back('\xf0');
expected_xor.push_back('\xf0');
expected_xor.push_back('\x0f');
// Single character key
@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor) @@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.insert(ds.begin(), in.begin(), in.end());
key.clear();
key += '\xff';
key.push_back('\xff');
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
@ -105,14 +105,17 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor) @@ -105,14 +105,17 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
in.clear();
expected_xor.clear();
in += '\xf0','\x0f';
expected_xor += '\x0f','\x00';
in.push_back('\xf0');
in.push_back('\x0f');
expected_xor.push_back('\x0f');
expected_xor.push_back('\x00');
ds.clear();
ds.insert(ds.begin(), in.begin(), in.end());
key.clear();
key += '\xff','\x0f';
key.push_back('\xff');
key.push_back('\x0f');
ds.Xor(key);
BOOST_CHECK_EQUAL(

2
src/test/test_bitcoin.h

@ -14,6 +14,8 @@ @@ -14,6 +14,8 @@
#include <txdb.h>
#include <txmempool.h>
#include <memory>
#include <boost/thread.hpp>
extern uint256 insecure_rand_seed;

1
src/test/test_bitcoin_fuzzy.cpp

@ -25,6 +25,7 @@ @@ -25,6 +25,7 @@
#include <unistd.h>
#include <algorithm>
#include <memory>
#include <vector>
enum TEST_ID {

2
src/test/test_bitcoin_main.cpp

@ -6,6 +6,8 @@ @@ -6,6 +6,8 @@
#include <net.h>
#include <memory>
#include <boost/test/unit_test.hpp>
std::unique_ptr<CConnman> g_connman;

1
src/txdb.h

@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
#include <chain.h>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

1
src/util.h

@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
#include <atomic>
#include <exception>
#include <map>
#include <memory>
#include <stdint.h>
#include <string>
#include <vector>

5
src/validation.cpp

@ -210,6 +210,7 @@ CChain& chainActive = g_chainstate.chainActive; @@ -210,6 +210,7 @@ CChain& chainActive = g_chainstate.chainActive;
CBlockIndex *pindexBestHeader = nullptr;
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
uint256 hashBestBlock;
int nScriptCheckThreads = 0;
std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
@ -2152,7 +2153,11 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar @@ -2152,7 +2153,11 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
// New best block
mempool.AddTransactionsUpdated(1);
{
WaitableLock lock(csBestBlock);
hashBestBlock = pindexNew->GetBlockHash();
cvBlockChange.notify_all();
}
std::vector<std::string> warningMessages;
if (!IsInitialBlockDownload())

2
src/validation.h

@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
#include <algorithm>
#include <exception>
#include <map>
#include <memory>
#include <set>
#include <stdint.h>
#include <string>
@ -165,6 +166,7 @@ extern uint64_t nLastBlockWeight; @@ -165,6 +166,7 @@ extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic;
extern CWaitableCriticalSection csBestBlock;
extern CConditionVariable cvBlockChange;
extern uint256 hashBestBlock;
extern std::atomic_bool fImporting;
extern std::atomic_bool fReindex;
extern int nScriptCheckThreads;

10
src/validationinterface.cpp

@ -26,7 +26,6 @@ struct MainSignalsInstance { @@ -26,7 +26,6 @@ struct MainSignalsInstance {
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
boost::signals2::signal<void (const uint256 &)> Inventory;
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
@ -81,7 +80,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { @@ -81,7 +80,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
@ -90,7 +88,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { @@ -90,7 +88,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
@ -106,7 +103,6 @@ void UnregisterAllValidationInterfaces() { @@ -106,7 +103,6 @@ void UnregisterAllValidationInterfaces() {
}
g_signals.m_internals->BlockChecked.disconnect_all_slots();
g_signals.m_internals->Broadcast.disconnect_all_slots();
g_signals.m_internals->Inventory.disconnect_all_slots();
g_signals.m_internals->SetBestChain.disconnect_all_slots();
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
g_signals.m_internals->BlockConnected.disconnect_all_slots();
@ -172,12 +168,6 @@ void CMainSignals::SetBestChain(const CBlockLocator &locator) { @@ -172,12 +168,6 @@ void CMainSignals::SetBestChain(const CBlockLocator &locator) {
});
}
void CMainSignals::Inventory(const uint256 &hash) {
m_internals->m_schedulerClient.AddToProcessQueue([hash, this] {
m_internals->Inventory(hash);
});
}
void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
m_internals->Broadcast(nBestBlockTime, connman);
}

7
src/validationinterface.h

@ -101,12 +101,6 @@ protected: @@ -101,12 +101,6 @@ protected:
* Called on a background thread.
*/
virtual void SetBestChain(const CBlockLocator &locator) {}
/**
* Notifies listeners about an inventory item being seen on the network.
*
* Called on a background thread.
*/
virtual void Inventory(const uint256 &hash) {}
/** Tells listeners to broadcast their data. */
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
/**
@ -157,7 +151,6 @@ public: @@ -157,7 +151,6 @@ public:
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
void SetBestChain(const CBlockLocator &);
void Inventory(const uint256 &);
void Broadcast(int64_t nBestBlockTime, CConnman* connman);
void BlockChecked(const CBlock&, const CValidationState&);
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);

1
src/wallet/db.h

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
#include <atomic>
#include <map>
#include <memory>
#include <string>
#include <vector>

2
src/wallet/rpcdump.cpp

@ -432,7 +432,7 @@ UniValue importpubkey(const JSONRPCRequest& request) @@ -432,7 +432,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"

12
src/wallet/rpcwallet.cpp

@ -1537,7 +1537,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) @@ -1537,7 +1537,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
" \"label\" : \"label\", (string) A comment for the address/transaction, if any\n"
" \"txids\": [\n"
" n, (numeric) The ids of transactions received with the address \n"
" \"txid\", (string) The ids of transactions received with the address \n"
" ...\n"
" ]\n"
" }\n"
@ -2322,8 +2322,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request) @@ -2322,8 +2322,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
"This is needed prior to performing transactions related to private keys such as sending litecoins\n"
"\nArguments:\n"
"1. \"passphrase\" (string, required) The wallet passphrase\n"
"2. timeout (numeric, required) The time to keep the decryption key in seconds. Limited to at most 1073741824 (2^30) seconds.\n"
" Any value greater than 1073741824 seconds will be set to 1073741824 seconds.\n"
"2. timeout (numeric, required) The time to keep the decryption key in seconds; capped at 100000000 (~3 years).\n"
"\nNote:\n"
"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
"time that overrides the old one.\n"
@ -2358,9 +2357,10 @@ UniValue walletpassphrase(const JSONRPCRequest& request) @@ -2358,9 +2357,10 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
if (nSleepTime < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
}
// Clamp timeout to 2^30 seconds
if (nSleepTime > (int64_t)1 << 30) {
nSleepTime = (int64_t)1 << 30;
// Clamp timeout
constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
if (nSleepTime > MAX_SLEEP_TIME) {
nSleepTime = MAX_SLEEP_TIME;
}
if (strWalletPass.length() > 0)

2
src/wallet/test/wallet_test_fixture.h

@ -9,6 +9,8 @@ @@ -9,6 +9,8 @@
#include <wallet/wallet.h>
#include <memory>
/** Testing setup and teardown for wallet.
*/
struct WalletTestingSetup: public TestingSetup {

1
src/wallet/test/wallet_tests.cpp

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
#include <wallet/wallet.h>
#include <memory>
#include <set>
#include <stdint.h>
#include <utility>

65
src/wallet/wallet.cpp

@ -891,7 +891,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash) @@ -891,7 +891,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
bool success = true;
if (!walletdb.WriteTx(wtx)) {
LogPrintf("%s: Updating walletdb tx %s failed", __func__, wtx.GetHash().ToString());
LogPrintf("%s: Updating walletdb tx %s failed\n", __func__, wtx.GetHash().ToString());
success = false;
}
@ -913,11 +913,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) @@ -913,11 +913,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
if (fInsertedNew)
{
if (fInsertedNew) {
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&walletdb);
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);
}
@ -987,9 +986,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) @@ -987,9 +986,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
CWalletTx& wtx = mapWallet.emplace(hash, wtxIn).first->second;
const auto& ins = mapWallet.emplace(hash, wtxIn);
CWalletTx& wtx = ins.first->second;
wtx.BindWallet(this);
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
if (/* insertion took place */ ins.second) {
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
}
AddToSpends(hash);
for (const CTxIn& txin : wtx.tx->vin) {
auto it = mapWallet.find(txin.prevout.hash);
@ -1122,7 +1124,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) @@ -1122,7 +1124,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
walletdb.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) {
todo.insert(iter->second);
@ -1506,45 +1508,6 @@ int64_t CWalletTx::GetTxTime() const @@ -1506,45 +1508,6 @@ int64_t CWalletTx::GetTxTime() const
return n ? n : nTimeReceived;
}
int CWalletTx::GetRequestCount() const
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
{
LOCK(pwallet->cs_wallet);
if (IsCoinBase())
{
// Generated block
if (!hashUnset())
{
std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second;
}
}
else
{
// Did anyone request this transaction?
std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
if (mi != pwallet->mapRequestCount.end())
{
nRequests = (*mi).second;
// How about the block it's in?
if (nRequests == 0 && !hashUnset())
{
std::map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
if (_mi != pwallet->mapRequestCount.end())
nRequests = (*_mi).second;
else
nRequests = 1; // If it's in someone else's block it must have got out
}
}
}
}
return nRequests;
}
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
{
@ -3085,9 +3048,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon @@ -3085,9 +3048,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
}
}
// Track how many getdata requests our transaction gets
mapRequestCount[wtxNew.GetHash()] = 0;
// Get the inserted-CWalletTx from mapWallet so that the
// fInMempool flag is cached properly
CWalletTx& wtx = mapWallet[wtxNew.GetHash()];
@ -3165,8 +3125,11 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256 @@ -3165,8 +3125,11 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{
AssertLockHeld(cs_wallet); // mapWallet
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut)
mapWallet.erase(hash);
for (uint256 hash : vHashOut) {
const auto& it = mapWallet.find(hash);
wtxOrdered.erase(it->second.m_it_wtxOrdered);
mapWallet.erase(it);
}
if (nZapSelectTxRet == DB_NEED_REWRITE)
{

14
src/wallet/wallet.h

@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
#include <algorithm>
#include <atomic>
#include <map>
#include <memory>
#include <set>
#include <stdexcept>
#include <stdint.h>
@ -326,6 +327,7 @@ public: @@ -326,6 +327,7 @@ public:
char fFromMe;
std::string strFromAccount;
int64_t nOrderPos; //!< position in ordered transaction list
std::multimap<int64_t, std::pair<CWalletTx*, CAccountingEntry*>>::const_iterator m_it_wtxOrdered;
// memory only
mutable bool fDebitCached;
@ -477,7 +479,6 @@ public: @@ -477,7 +479,6 @@ public:
bool IsTrusted() const;
int64_t GetTxTime() const;
int GetRequestCount() const;
// RelayWalletTransaction may only be called if fBroadcastTransactions!
bool RelayWalletTransaction(CConnman* connman);
@ -833,7 +834,6 @@ public: @@ -833,7 +834,6 @@ public:
int64_t nOrderPosNext;
uint64_t nAccountingEntryNumber;
std::map<uint256, int> mapRequestCount;
std::map<CTxDestination, CAddressBookData> mapAddressBook;
@ -1042,16 +1042,6 @@ public: @@ -1042,16 +1042,6 @@ public:
const std::string& GetAccountName(const CScript& scriptPubKey) const;
void Inventory(const uint256 &hash) override
{
{
LOCK(cs_wallet);
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
unsigned int GetKeyPoolSize()

7
test/functional/feature_pruning.py

@ -260,10 +260,17 @@ class PruneTest(BitcoinTestFramework): @@ -260,10 +260,17 @@ class PruneTest(BitcoinTestFramework):
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
assert_raises_rpc_error(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
# Save block transaction count before pruning, assert value
block1_details = node.getblock(node.getblockhash(1))
assert_equal(block1_details["nTx"], len(block1_details["tx"]))
# mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
node.generate(6)
assert_equal(node.getblockchaininfo()["blocks"], 1001)
# Pruned block should still know the number of transactions
assert_equal(node.getblockheader(node.getblockhash(1))["nTx"], block1_details["nTx"])
# negative heights should raise an exception
assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10)

94
test/functional/p2p_sendheaders.py

@ -116,6 +116,7 @@ class BaseNode(P2PInterface): @@ -116,6 +116,7 @@ class BaseNode(P2PInterface):
self.block_announced = False
self.last_blockhash_announced = None
self.recent_headers_announced = []
def send_get_data(self, block_hashes):
"""Request data for a list of block hashes."""
@ -163,40 +164,45 @@ class BaseNode(P2PInterface): @@ -163,40 +164,45 @@ class BaseNode(P2PInterface):
def on_headers(self, message):
if len(message.headers):
self.block_announced = True
message.headers[-1].calc_sha256()
for x in message.headers:
x.calc_sha256()
# append because headers may be announced over multiple messages.
self.recent_headers_announced.append(x.sha256)
self.last_blockhash_announced = message.headers[-1].sha256
def clear_last_announcement(self):
def clear_block_announcements(self):
with mininode_lock:
self.block_announced = False
self.last_message.pop("inv", None)
self.last_message.pop("headers", None)
self.recent_headers_announced = []
def check_last_announcement(self, headers=None, inv=None):
"""Test whether the last announcement received had the right header or the right inv.
inv and headers should be lists of block hashes."""
def check_last_headers_announcement(self, headers):
"""Test whether the last headers announcements received are right.
Headers may be announced across more than one message."""
test_function = lambda: (len(self.recent_headers_announced) >= len(headers))
wait_until(test_function, timeout=60, lock=mininode_lock)
with mininode_lock:
assert_equal(self.recent_headers_announced, headers)
self.block_announced = False
self.last_message.pop("headers", None)
self.recent_headers_announced = []
def check_last_inv_announcement(self, inv):
"""Test whether the last announcement received had the right inv.
inv should be a list of block hashes."""
test_function = lambda: self.block_announced
wait_until(test_function, timeout=60, lock=mininode_lock)
with mininode_lock:
self.block_announced = False
compare_inv = []
if "inv" in self.last_message:
compare_inv = [x.hash for x in self.last_message["inv"].inv]
if inv is not None:
assert_equal(compare_inv, inv)
compare_headers = []
if "headers" in self.last_message:
compare_headers = [x.sha256 for x in self.last_message["headers"].headers]
if headers is not None:
assert_equal(compare_headers, headers)
self.block_announced = False
self.last_message.pop("inv", None)
self.last_message.pop("headers", None)
class SendHeadersTest(BitcoinTestFramework):
def set_test_params(self):
@ -206,8 +212,8 @@ class SendHeadersTest(BitcoinTestFramework): @@ -206,8 +212,8 @@ class SendHeadersTest(BitcoinTestFramework):
def mine_blocks(self, count):
"""Mine count blocks and return the new tip."""
# Clear out last block announcement from each p2p listener
[x.clear_last_announcement() for x in self.nodes[0].p2ps]
# Clear out block announcements from each p2p listener
[x.clear_block_announcements() for x in self.nodes[0].p2ps]
self.nodes[0].generate(count)
return int(self.nodes[0].getbestblockhash(), 16)
@ -222,7 +228,7 @@ class SendHeadersTest(BitcoinTestFramework): @@ -222,7 +228,7 @@ class SendHeadersTest(BitcoinTestFramework):
sync_blocks(self.nodes, wait=0.1)
for x in self.nodes[0].p2ps:
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
x.clear_last_announcement()
x.clear_block_announcements()
tip_height = self.nodes[1].getblockcount()
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
@ -255,26 +261,26 @@ class SendHeadersTest(BitcoinTestFramework): @@ -255,26 +261,26 @@ class SendHeadersTest(BitcoinTestFramework):
tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
tip_hash = int(tip["hash"], 16)
inv_node.check_last_announcement(inv=[tip_hash], headers=[])
test_node.check_last_announcement(inv=[tip_hash], headers=[])
inv_node.check_last_inv_announcement(inv=[tip_hash])
test_node.check_last_inv_announcement(inv=[tip_hash])
self.log.info("Verify getheaders with null locator and valid hashstop returns headers.")
test_node.clear_last_announcement()
test_node.clear_block_announcements()
test_node.send_get_headers(locator=[], hashstop=tip_hash)
test_node.check_last_announcement(headers=[tip_hash])
test_node.check_last_headers_announcement(headers=[tip_hash])
self.log.info("Verify getheaders with null locator and invalid hashstop does not return headers.")
block = create_block(int(tip["hash"], 16), create_coinbase(tip["height"] + 1), tip["mediantime"] + 1)
block.nVersion = 0x20000000
block.solve()
test_node.send_header_for_blocks([block])
test_node.clear_last_announcement()
test_node.clear_block_announcements()
test_node.send_get_headers(locator=[], hashstop=int(block.hash, 16))
test_node.sync_with_ping()
assert_equal(test_node.block_announced, False)
inv_node.clear_last_announcement()
inv_node.clear_block_announcements()
test_node.send_message(msg_block(block))
inv_node.check_last_announcement(inv=[int(block.hash, 16)], headers=[])
inv_node.check_last_inv_announcement(inv=[int(block.hash, 16)])
def test_nonnull_locators(self, test_node, inv_node):
tip = int(self.nodes[0].getbestblockhash(), 16)
@ -285,8 +291,8 @@ class SendHeadersTest(BitcoinTestFramework): @@ -285,8 +291,8 @@ class SendHeadersTest(BitcoinTestFramework):
for i in range(4):
old_tip = tip
tip = self.mine_blocks(1)
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(inv=[tip], headers=[])
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_inv_announcement(inv=[tip])
# Try a few different responses; none should affect next announcement
if i == 0:
# first request the block
@ -297,7 +303,7 @@ class SendHeadersTest(BitcoinTestFramework): @@ -297,7 +303,7 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.send_get_headers(locator=[old_tip], hashstop=tip)
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
test_node.clear_last_announcement() # since we requested headers...
test_node.clear_block_announcements() # since we requested headers...
elif i == 2:
# this time announce own block via headers
height = self.nodes[0].getblockcount()
@ -310,8 +316,8 @@ class SendHeadersTest(BitcoinTestFramework): @@ -310,8 +316,8 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.wait_for_getdata([new_block.sha256])
test_node.send_message(msg_block(new_block))
test_node.sync_with_ping() # make sure this block is processed
inv_node.clear_last_announcement()
test_node.clear_last_announcement()
inv_node.clear_block_announcements()
test_node.clear_block_announcements()
self.log.info("Part 1: success!")
self.log.info("Part 2: announce blocks with headers after sendheaders message...")
@ -325,8 +331,8 @@ class SendHeadersTest(BitcoinTestFramework): @@ -325,8 +331,8 @@ class SendHeadersTest(BitcoinTestFramework):
# Now that we've synced headers, headers announcements should work
tip = self.mine_blocks(1)
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(headers=[tip])
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_headers_announcement(headers=[tip])
height = self.nodes[0].getblockcount() + 1
block_time += 10 # Advance far enough ahead
@ -371,8 +377,8 @@ class SendHeadersTest(BitcoinTestFramework): @@ -371,8 +377,8 @@ class SendHeadersTest(BitcoinTestFramework):
assert "inv" not in inv_node.last_message
assert "headers" not in inv_node.last_message
tip = self.mine_blocks(1)
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(headers=[tip])
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_headers_announcement(headers=[tip])
height += 1
block_time += 1
@ -386,16 +392,16 @@ class SendHeadersTest(BitcoinTestFramework): @@ -386,16 +392,16 @@ class SendHeadersTest(BitcoinTestFramework):
# First try mining a reorg that can propagate with header announcement
new_block_hashes = self.mine_reorg(length=7)
tip = new_block_hashes[-1]
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(headers=new_block_hashes)
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_headers_announcement(headers=new_block_hashes)
block_time += 8
# Mine a too-large reorg, which should be announced with a single inv
new_block_hashes = self.mine_reorg(length=8)
tip = new_block_hashes[-1]
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(inv=[tip], headers=[])
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_inv_announcement(inv=[tip])
block_time += 9
@ -404,15 +410,15 @@ class SendHeadersTest(BitcoinTestFramework): @@ -404,15 +410,15 @@ class SendHeadersTest(BitcoinTestFramework):
# Use getblocks/getdata
test_node.send_getblocks(locator=[fork_point])
test_node.check_last_announcement(inv=new_block_hashes, headers=[])
test_node.check_last_inv_announcement(inv=new_block_hashes)
test_node.send_get_data(new_block_hashes)
test_node.wait_for_block(new_block_hashes[-1])
for i in range(3):
# Mine another block, still should get only an inv
tip = self.mine_blocks(1)
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(inv=[tip], headers=[])
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_inv_announcement(inv=[tip])
if i == 0:
# Just get the data -- shouldn't cause headers announcements to resume
test_node.send_get_data([tip])
@ -437,8 +443,8 @@ class SendHeadersTest(BitcoinTestFramework): @@ -437,8 +443,8 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.sync_with_ping()
# New blocks should now be announced with header
tip = self.mine_blocks(1)
inv_node.check_last_announcement(inv=[tip], headers=[])
test_node.check_last_announcement(headers=[tip])
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_headers_announcement(headers=[tip])
self.log.info("Part 3: success!")

1
test/functional/rpc_blockchain.py

@ -185,6 +185,7 @@ class BlockchainTest(BitcoinTestFramework): @@ -185,6 +185,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(header['confirmations'], 1)
assert_equal(header['previousblockhash'], secondbesthash)
assert_is_hex_string(header['chainwork'])
assert_equal(header['nTx'], 1)
assert_is_hash_string(header['hash'])
assert_is_hash_string(header['previousblockhash'])
assert_is_hash_string(header['merkleroot'])

23
test/functional/rpc_txoutproof.py

@ -6,6 +6,8 @@ @@ -6,6 +6,8 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.mininode import FromHex, ToHex
from test_framework.messages import CMerkleBlock
class MerkleBlockTest(BitcoinTestFramework):
def set_test_params(self):
@ -78,6 +80,27 @@ class MerkleBlockTest(BitcoinTestFramework): @@ -78,6 +80,27 @@ class MerkleBlockTest(BitcoinTestFramework):
# We can't get a proof if we specify transactions from different blocks
assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[2].gettxoutproof, [txid1, txid3])
# Now we'll try tweaking a proof.
proof = self.nodes[3].gettxoutproof([txid1, txid2])
assert txid1 in self.nodes[0].verifytxoutproof(proof)
assert txid2 in self.nodes[1].verifytxoutproof(proof)
tweaked_proof = FromHex(CMerkleBlock(), proof)
# Make sure that our serialization/deserialization is working
assert txid1 in self.nodes[2].verifytxoutproof(ToHex(tweaked_proof))
# Check to see if we can go up the merkle tree and pass this off as a
# single-transaction block
tweaked_proof.txn.nTransactions = 1
tweaked_proof.txn.vHash = [tweaked_proof.header.hashMerkleRoot]
tweaked_proof.txn.vBits = [True] + [False]*7
for n in self.nodes:
assert not n.verifytxoutproof(ToHex(tweaked_proof))
# TODO: try more variants, eg transactions at different depths, and
# verify that the proofs are invalid
if __name__ == '__main__':
MerkleBlockTest().main()

46
test/functional/test_framework/messages.py

@ -836,6 +836,52 @@ class BlockTransactions(): @@ -836,6 +836,52 @@ class BlockTransactions():
def __repr__(self):
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
class CPartialMerkleTree():
def __init__(self):
self.nTransactions = 0
self.vHash = []
self.vBits = []
self.fBad = False
def deserialize(self, f):
self.nTransactions = struct.unpack("<i", f.read(4))[0]
self.vHash = deser_uint256_vector(f)
vBytes = deser_string(f)
self.vBits = []
for i in range(len(vBytes) * 8):
self.vBits.append(vBytes[i//8] & (1 << (i % 8)) != 0)
def serialize(self):
r = b""
r += struct.pack("<i", self.nTransactions)
r += ser_uint256_vector(self.vHash)
vBytesArray = bytearray([0x00] * ((len(self.vBits) + 7)//8))
for i in range(len(self.vBits)):
vBytesArray[i // 8] |= self.vBits[i] << (i % 8)
r += ser_string(bytes(vBytesArray))
return r
def __repr__(self):
return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits))
class CMerkleBlock():
def __init__(self):
self.header = CBlockHeader()
self.txn = CPartialMerkleTree()
def deserialize(self, f):
self.header.deserialize(f)
self.txn.deserialize(f)
def serialize(self):
r = b""
r += self.header.serialize()
r += self.txn.serialize()
return r
def __repr__(self):
return "CMerkleBlock(header=%s, txn=%s)" % (repr(self.header), repr(self.txn))
# Objects that correspond to messages on the wire
class msg_version():

12
test/functional/wallet_abandonconflict.py

@ -64,9 +64,17 @@ class AbandonConflictTest(BitcoinTestFramework): @@ -64,9 +64,17 @@ class AbandonConflictTest(BitcoinTestFramework):
signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])
# Create a child tx spending ABC2
signed3_change = Decimal("24.999")
inputs = [ {"txid":txABC2, "vout":0} ]
outputs = { self.nodes[0].getnewaddress(): signed3_change }
signed3 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
# note tx is never directly referenced, only abandoned as a child of the above
self.nodes[0].sendrawtransaction(signed3["hex"])
# In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("30") + Decimal("24.96"))
assert_equal(newbalance, balance - Decimal("30") + signed3_change)
balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
@ -81,7 +89,7 @@ class AbandonConflictTest(BitcoinTestFramework): @@ -81,7 +89,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("24.96"))
assert_equal(newbalance, balance - signed3_change)
# Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()

9
test/functional/wallet_encryption.py

@ -64,14 +64,15 @@ class WalletEncryptionTest(BitcoinTestFramework): @@ -64,14 +64,15 @@ class WalletEncryptionTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10)
# Check the timeout
# Check a time less than the limit
expected_time = int(time.time()) + (1 << 30) - 600
self.nodes[0].walletpassphrase(passphrase2, (1 << 30) - 600)
MAX_VALUE = 100000000
expected_time = int(time.time()) + MAX_VALUE - 600
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time)
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
# Check a time greater than the limit
expected_time = int(time.time()) + (1 << 30) - 1
self.nodes[0].walletpassphrase(passphrase2, (1 << 33))
expected_time = int(time.time()) + MAX_VALUE - 1
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time)
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer

6
test/functional/wallet_listreceivedby.py

@ -6,11 +6,14 @@ @@ -6,11 +6,14 @@
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (assert_array_result,
from test_framework.util import (
assert_array_result,
assert_equal,
assert_raises_rpc_error,
sync_blocks,
)
class ReceivedByTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
@ -18,6 +21,7 @@ class ReceivedByTest(BitcoinTestFramework): @@ -18,6 +21,7 @@ class ReceivedByTest(BitcoinTestFramework):
def run_test(self):
# Generate block to get out of IBD
self.nodes[0].generate(1)
sync_blocks(self.nodes)
self.log.info("listreceivedbyaddress Test")

Loading…
Cancel
Save