Browse Source

Merge pull request #523 from thrasher-/0.16

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

2
configure.ac

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

2
depends/packages/qt.mk

@ -1,6 +1,6 @@
PACKAGE=qt PACKAGE=qt
$(package)_version=5.7.1 $(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)_suffix=opensource-src-$($(package)_version).tar.gz
$(package)_file_name=qtbase-$($(package)_suffix) $(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410 $(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410

6
doc/man/litecoin-cli.1

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

10
doc/man/litecoin-qt.1

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. .\" 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 LITECOIN-QT "1" "July 2018" "litecoin-qt v0.16.2.0" "User Commands"
.SH NAME .SH NAME
litecoin-qt \- manual page for litecoin-qt v0.16.1.0 litecoin-qt \- manual page for litecoin-qt v0.16.2.0
.SH DESCRIPTION .SH DESCRIPTION
Litecoin Core version v0.16.1.0\-dirty (64\-bit) Litecoin Core version v0.16.2.0 (64\-bit)
Usage: Usage:
.IP .IP
litecoin\-qt [command\-line options] litecoin\-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 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, and potentially skip their script verification (0 to verify all,
default: default:
59c9b9d3fec105bdc716d84caa7579503d5b05b73618d0bf2d5fa639f780a011, 66f49ad85624c33e4fd61aa45c54012509ed4a53308908dd07f56346c7939273,
testnet: testnet:
a0afbded94d4be233e191525dc2d467af5c7eab3143c852c3cd549831022aad6) 1efb29c8187d5a496a33377941d1df415169c3ce5d8c05d055f25b683ec3f9a3)
.HP .HP
\fB\-conf=\fR<file> \fB\-conf=\fR<file>
.IP .IP

6
doc/man/litecoin-tx.1

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

10
doc/man/litecoind.1

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. .\" 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 LITECOIND "1" "July 2018" "litecoind v0.16.2.0" "User Commands"
.SH NAME .SH NAME
litecoind \- manual page for litecoind v0.16.1.0 litecoind \- manual page for litecoind v0.16.2.0
.SH DESCRIPTION .SH DESCRIPTION
Litecoin Core Daemon version v0.16.1.0\-dirty Litecoin Core Daemon version v0.16.2.0
.SS "Usage:" .SS "Usage:"
.TP .TP
litecoind [options] litecoind [options]
@ -33,9 +33,9 @@ block hash)
If this block is in the chain assume that it and its ancestors are valid 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, and potentially skip their script verification (0 to verify all,
default: default:
59c9b9d3fec105bdc716d84caa7579503d5b05b73618d0bf2d5fa639f780a011, 66f49ad85624c33e4fd61aa45c54012509ed4a53308908dd07f56346c7939273,
testnet: testnet:
a0afbded94d4be233e191525dc2d467af5c7eab3143c852c3cd549831022aad6) 1efb29c8187d5a496a33377941d1df415169c3ce5d8c05d055f25b683ec3f9a3)
.HP .HP
\fB\-conf=\fR<file> \fB\-conf=\fR<file>
.IP .IP

39
doc/release-notes-litecoin.md

@ -1,9 +1,9 @@
Litecoin Core version 0.16.1 is now available from: Litecoin Core version 0.16.2 is now available from:
<https://download.litecoin.org/litecoin-0.16.1/> <https://download.litecoin.org/litecoin-0.16.2/>
This is a new minor version release, including new features, various bugfixes This is a new minor version release, with various bugfixes
and performance improvements, as well as updated translations. as well as updated translations.
Please report bugs using the issue tracker at GitHub: Please report bugs using the issue tracker at GitHub:
@ -57,7 +57,7 @@ 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' `-blockmaxweight` option if they want to limit the weight of their blocks'
weights. weights.
0.16.1 change log 0.16.2 change log
------------------ ------------------
### Policy ### Policy
@ -76,11 +76,24 @@ weights.
### Wallet ### Wallet
- #13265 `5d8de76` Exit SyncMetaData if there are no transactions to sync (laanwj) - #13265 `5d8de76` Exit SyncMetaData if there are no transactions to sync (laanwj)
- #13030 `5ff571e` Fix zapwallettxes/multiwallet interaction. (jnewbery) - #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 ### GUI
- #12999 `1720eb3` Show the Window when double clicking the taskbar icon (ken2812221) - #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) - #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) - #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 ### Build system
- #12474 `b0f692f` Allow depends system to support armv7l (hkjn) - #12474 `b0f692f` Allow depends system to support armv7l (hkjn)
@ -90,6 +103,8 @@ weights.
- #12636 `845838c` backport: #11995 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) - #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) - #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 ### Tests and QA
- #12447 `01f931b` Add missing signal.h header (laanwj) - #12447 `01f931b` Add missing signal.h header (laanwj)
@ -104,6 +119,11 @@ weights.
- #12904 `6c26df0` Ensure bitcoind processes are cleaned up when tests end (sdaftuar) - #12904 `6c26df0` Ensure bitcoind processes are cleaned up when tests end (sdaftuar)
- #13049 `9ea62a3` Backports (MarcoFalke) - #13049 `9ea62a3` Backports (MarcoFalke)
- #13201 `b8aacd6` Handle disconnect_node race (sdaftuar) - #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 ### Miscellaneous
- #12518 `a17fecf` Bump leveldb subtree (MarcoFalke) - #12518 `a17fecf` Bump leveldb subtree (MarcoFalke)
@ -111,6 +131,10 @@ weights.
- #12988 `acdf433` Hold cs_main while calling UpdatedBlockTip() signal (skeees) - #12988 `acdf433` Hold cs_main while calling UpdatedBlockTip() signal (skeees)
- #12985 `0684cf9` Windows: Avoid launching as admin when NSIS installer ends. (JeremyRand) - #12985 `0684cf9` Windows: Avoid launching as admin when NSIS installer ends. (JeremyRand)
- #503 `87ec334` Fix CVE-2018-12356 by hardening the regex (jmutkawoa) - #503 `87ec334` Fix CVE-2018-12356 by hardening the regex (jmutkawoa)
- #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)
### Documentation ### Documentation
- #12637 `60086dd` backport: #12556 fix version typo in getpeerinfo RPC call help (fanquake) - #12637 `60086dd` backport: #12556 fix version typo in getpeerinfo RPC call help (fanquake)
@ -142,3 +166,8 @@ Thanks to everyone who directly contributed to this release:
- voidmain - voidmain
- wbsmolen - wbsmolen
- xinxi - xinxi
And to those that reported security issues:
- Braydon Fuller
- Himanshu Mehta

115
doc/release-notes.md

@ -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 This is a new minor version release, with various bugfixes
and performance improvements, as well as updated translations. as well as updated translations.
Please report bugs using the issue tracker at GitHub: 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
Bitcoin Core should also work on most other Unix-like systems but is not Bitcoin Core should also work on most other Unix-like systems but is not
frequently tested on them. frequently tested on them.
Notable changes 0.16.2 change log
===============
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
------------------ ------------------
### 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 ### Wallet
- #13265 `5d8de76` Exit SyncMetaData if there are no transactions to sync (laanwj) - #13622 `c04a4a5` Remove mapRequest tracking that just effects Qt display. (TheBlueMatt)
- #13030 `5ff571e` Fix zapwallettxes/multiwallet interaction. (jnewbery) - #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 ### GUI
- #12999 `1720eb3` Show the Window when double clicking the taskbar icon (ken2812221) - #12432 `f78e7f6` [qt] send: Clear All also resets coin control options (Sjors)
- #12650 `f118a7a` Fix issue: "default port not shown correctly in settings dialog" (251Labs) - #12617 `21dd512` gui: Show messages as text not html (laanwj)
- #13251 `ea487f9` Rephrase Bech32 checkbox texts, and enable it with legacy address default (fanquake) - #12793 `cf6feb7` qt: Avoid reseting on resetguisettigs=0 (MarcoFalke)
### Build system ### Build system
- #12474 `b0f692f` Allow depends system to support armv7l (hkjn) - #13544 `9fd3e00` depends: Update Qt download url (fanquake)
- #12585 `72a3290` depends: Switch to downloading expat from GitHub (fanquake) - #12573 `88d1a64` Fix compilation when compiler do not support `__builtin_clz*` (532479301)
- #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)
### Tests and QA ### Tests and QA
- #12447 `01f931b` Add missing signal.h header (laanwj) - #13061 `170b309` Make tests pass after 2020 (bmwiedemann)
- #12545 `1286f3e` Use wait_until to ensure ping goes out (Empact) - #13192 `79c4fff` [tests] Fixed intermittent failure in `p2p_sendheaders.py` (lmanners)
- #12804 `4bdb0ce` Fix intermittent rpc_net.py failure. (jnewbery) - #13300 `d9c5630` qa: Initialize lockstack to prevent null pointer deref (MarcoFalke)
- #12553 `0e98f96` Prefer wait_until over polling with time.sleep (Empact) - #13545 `e15e3a9` tests: Fix test case `streams_serializedata_xor` Remove Boost dependency. (practicalswift)
- #12486 `cfebd40` Round target fee to 8 decimals in assert_fee_amount (kallewoof) - #13304 `cbdabef` qa: Fix `wallet_listreceivedby` race (MarcoFalke)
- #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)
### Miscellaneous ### Miscellaneous
- #12518 `a17fecf` Bump leveldb subtree (MarcoFalke) - #12887 `2291774` Add newlines to end of log messages (jnewbery)
- #12442 `f3b8d85` devtools: Exclude patches from lint-whitespace (MarcoFalke) - #12859 `18b0c69` Bugfix: Include <memory> for `std::unique_ptr` (luke-jr)
- #12988 `acdf433` Hold cs_main while calling UpdatedBlockTip() signal (skeees) - #13131 `ce8aa54` Add Windows shutdown handler (ken2812221)
- #12985 `0684cf9` Windows: Avoid launching as admin when NSIS installer ends. (JeremyRand) - #13652 `20461fc` rpc: Fix that CWallet::AbandonTransaction would leave the grandchildren, etc. active (Empact)
### 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)
Credits Credits
======= =======
Thanks to everyone who directly contributed to this release: Thanks to everyone who directly contributed to this release:
- 251 - 532479301
- Ben Woosley - Ben Woosley
- Bernhard M. Wiedemann
- Chun Kuan Lee - Chun Kuan Lee
- David A. Harding - Cory Fields
- e0
- fanquake - fanquake
- Henrik Jonsson - Gregory Sanders
- JeremyRand - joemphilips
- Jesse Cohen
- John Newbery - John Newbery
- Johnson Lau - Kristaps Kaupe
- Karl-Johan Alm - lmanners
- Luke Dashjr - Luke Dashjr
- MarcoFalke - MarcoFalke
- Matt Corallo - Matt Corallo
- Pieter Wuille - Pieter Wuille
- practicalswift
- Sjors Provoost
- Suhas Daftuar - Suhas Daftuar
- Tamas Blummer
- Wladimir J. van der Laan - 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/). 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 @@
#include <util.h> #include <util.h>
#include <utilstrencodings.h> #include <utilstrencodings.h>
#include <memory>
#include <stdio.h> #include <stdio.h>
#include <event2/buffer.h> #include <event2/buffer.h>

1
src/bitcoin-tx.cpp

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

1
src/chainparams.cpp

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

1
src/chainparamsbase.cpp

@ -9,6 +9,7 @@
#include <util.h> #include <util.h>
#include <assert.h> #include <assert.h>
#include <memory>
const std::string CBaseChainParams::MAIN = "main"; const std::string CBaseChainParams::MAIN = "main";
const std::string CBaseChainParams::TESTNET = "test"; 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)
/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */ /** 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) 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)) { if (sizeof(unsigned long) >= sizeof(uint64_t)) {
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0; return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
} }
#endif #endif
#ifdef HAVE_DECL___BUILTIN_CLZLL #if HAVE_DECL___BUILTIN_CLZLL
if (sizeof(unsigned long long) >= sizeof(uint64_t)) { if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0; return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
} }

1
src/dbwrapper.cpp

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

2
src/httprpc.cpp

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

1
src/httpserver.cpp

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

13
src/init.cpp

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

1
src/memusage.h

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

6
src/merkleblock.h

@ -115,6 +115,12 @@ public:
* returns the merkle root, or 0 in case of failure * returns the merkle root, or 0 in case of failure
*/ */
uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex); 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 @@
#include <validationinterface.h> #include <validationinterface.h>
#include <algorithm> #include <algorithm>
#include <memory>
#include <queue> #include <queue>
#include <utility> #include <utility>

1
src/net.cpp

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

8
src/net_processing.cpp

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

1
src/policy/fees.h

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

2
src/qt/bantablemodel.h

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

3
src/qt/bitcoin.cpp

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

1
src/qt/bitcoingui.cpp

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

2
src/qt/guiconstants.h

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

1
src/qt/paymentserver.cpp

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

2
src/qt/peertablemodel.h

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

6
src/qt/sendcoinsdialog.cpp

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

2
src/qt/test/wallettests.cpp

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

10
src/qt/transactiondesc.cpp

@ -36,8 +36,6 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
int nDepth = wtx.GetDepthInMainChain(); int nDepth = wtx.GetDepthInMainChain();
if (nDepth < 0) if (nDepth < 0)
return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth); 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) 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") : ""); 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) else if (nDepth < 6)
@ -61,14 +59,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
CAmount nNet = nCredit - nDebit; CAmount nNet = nCredit - nDebit;
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); 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 += "<br>";
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<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)
if (wtx.IsInMainChain()) if (wtx.IsInMainChain())
{ {
status.matures_in = wtx.GetBlocksToMaturity(); 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 else
{ {
@ -226,10 +222,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
{ {
status.status = TransactionStatus::Conflicted; status.status = TransactionStatus::Conflicted;
} }
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
{
status.status = TransactionStatus::Offline;
}
else if (status.depth == 0) else if (status.depth == 0)
{ {
status.status = TransactionStatus::Unconfirmed; status.status = TransactionStatus::Unconfirmed;

4
src/qt/transactionrecord.h

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

9
src/qt/transactiontablemodel.cpp

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

2
src/qt/walletmodeltransaction.h

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

5
src/rpc/blockchain.cpp

@ -33,6 +33,7 @@
#include <boost/thread/thread.hpp> // boost::thread::interrupt #include <boost/thread/thread.hpp> // boost::thread::interrupt
#include <memory>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
@ -104,6 +105,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("nTx", (uint64_t)blockindex->nTx));
if (blockindex->pprev) if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
@ -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("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("nTx", (uint64_t)blockindex->nTx));
if (blockindex->pprev) if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
@ -678,6 +681,7 @@ UniValue getblockheader(const JSONRPCRequest& request)
" \"bits\" : \"1d00ffff\", (string) The bits\n" " \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\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" " \"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" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n" " \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
"}\n" "}\n"
@ -747,6 +751,7 @@ UniValue getblock(const JSONRPCRequest& request)
" \"bits\" : \"1d00ffff\", (string) The bits\n" " \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\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" " \"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" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
"}\n" "}\n"

2
src/rpc/mining.cpp

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

11
src/rpc/rawtransaction.cpp

@ -290,7 +290,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
"\nArguments:\n" "\nArguments:\n"
"1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n" "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n"
"\nResult:\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); CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
@ -306,11 +306,16 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
LOCK(cs_main); 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"); 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()); res.push_back(hash.GetHex());
}
}
return res; return res;
} }

1
src/support/lockedpool.cpp

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

20
src/sync.cpp

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

2
src/test/allocator_tests.cpp

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

2
src/test/dbwrapper_tests.cpp

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

2
src/test/net_tests.cpp

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

4
src/test/rpc_tests.cpp

@ -256,14 +256,14 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
ar = r.get_array(); ar = r.get_array();
BOOST_CHECK_EQUAL(ar.size(), 0); 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"))); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array(); ar = r.get_array();
o1 = ar[0].get_obj(); o1 = ar[0].get_obj();
adr = find_value(o1, "address"); adr = find_value(o1, "address");
UniValue banned_until = find_value(o1, "banned_until"); UniValue banned_until = find_value(o1, "banned_until");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); 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"))); BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));

23
src/test/streams_tests.cpp

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

2
src/test/test_bitcoin.h

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

1
src/test/test_bitcoin_fuzzy.cpp

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

2
src/test/test_bitcoin_main.cpp

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

1
src/txdb.h

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

1
src/util.h

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

5
src/validation.cpp

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

2
src/validation.h

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

10
src/validationinterface.cpp

@ -26,7 +26,6 @@ struct MainSignalsInstance {
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected; boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool; boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain; 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 (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock; boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
@ -81,7 +80,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1)); 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->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, 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->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->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2)); g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
@ -90,7 +88,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
void UnregisterValidationInterface(CValidationInterface* pwalletIn) { void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); 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->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->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, 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)); g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
@ -106,7 +103,6 @@ void UnregisterAllValidationInterfaces() {
} }
g_signals.m_internals->BlockChecked.disconnect_all_slots(); g_signals.m_internals->BlockChecked.disconnect_all_slots();
g_signals.m_internals->Broadcast.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->SetBestChain.disconnect_all_slots();
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots(); g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
g_signals.m_internals->BlockConnected.disconnect_all_slots(); g_signals.m_internals->BlockConnected.disconnect_all_slots();
@ -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) { void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
m_internals->Broadcast(nBestBlockTime, connman); m_internals->Broadcast(nBestBlockTime, connman);
} }

7
src/validationinterface.h

@ -101,12 +101,6 @@ protected:
* Called on a background thread. * Called on a background thread.
*/ */
virtual void SetBestChain(const CBlockLocator &locator) {} 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. */ /** Tells listeners to broadcast their data. */
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
/** /**
@ -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 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 BlockDisconnected(const std::shared_ptr<const CBlock> &);
void SetBestChain(const CBlockLocator &); void SetBestChain(const CBlockLocator &);
void Inventory(const uint256 &);
void Broadcast(int64_t nBestBlockTime, CConnman* connman); void Broadcast(int64_t nBestBlockTime, CConnman* connman);
void BlockChecked(const CBlock&, const CValidationState&); void BlockChecked(const CBlock&, const CValidationState&);
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&); void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);

1
src/wallet/db.h

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

2
src/wallet/rpcdump.cpp

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

2
src/wallet/test/wallet_test_fixture.h

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

1
src/wallet/test/wallet_tests.cpp

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

65
src/wallet/wallet.cpp

@ -891,7 +891,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
bool success = true; bool success = true;
if (!walletdb.WriteTx(wtx)) { 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; success = false;
} }
@ -913,11 +913,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
CWalletTx& wtx = (*ret.first).second; CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this); wtx.BindWallet(this);
bool fInsertedNew = ret.second; bool fInsertedNew = ret.second;
if (fInsertedNew) if (fInsertedNew) {
{
wtx.nTimeReceived = GetAdjustedTime(); wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&walletdb); 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); wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash); AddToSpends(hash);
} }
@ -987,9 +986,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
bool CWallet::LoadToWallet(const CWalletTx& wtxIn) bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
{ {
uint256 hash = wtxIn.GetHash(); 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); 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); AddToSpends(hash);
for (const CTxIn& txin : wtx.tx->vin) { for (const CTxIn& txin : wtx.tx->vin) {
auto it = mapWallet.find(txin.prevout.hash); auto it = mapWallet.find(txin.prevout.hash);
@ -1122,7 +1124,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
walletdb.WriteTx(wtx); walletdb.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too // 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) { while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) { if (!done.count(iter->second)) {
todo.insert(iter->second); todo.insert(iter->second);
@ -1506,45 +1508,6 @@ int64_t CWalletTx::GetTxTime() const
return n ? n : nTimeReceived; 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, void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const 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
} }
} }
// Track how many getdata requests our transaction gets
mapRequestCount[wtxNew.GetHash()] = 0;
// Get the inserted-CWalletTx from mapWallet so that the // Get the inserted-CWalletTx from mapWallet so that the
// fInMempool flag is cached properly // fInMempool flag is cached properly
CWalletTx& wtx = mapWallet[wtxNew.GetHash()]; CWalletTx& wtx = mapWallet[wtxNew.GetHash()];
@ -3165,8 +3125,11 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{ {
AssertLockHeld(cs_wallet); // mapWallet AssertLockHeld(cs_wallet); // mapWallet
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut); DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut) for (uint256 hash : vHashOut) {
mapWallet.erase(hash); const auto& it = mapWallet.find(hash);
wtxOrdered.erase(it->second.m_it_wtxOrdered);
mapWallet.erase(it);
}
if (nZapSelectTxRet == DB_NEED_REWRITE) if (nZapSelectTxRet == DB_NEED_REWRITE)
{ {

14
src/wallet/wallet.h

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

7
test/functional/feature_pruning.py

@ -260,10 +260,17 @@ class PruneTest(BitcoinTestFramework):
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000) # 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)) 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) # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
node.generate(6) node.generate(6)
assert_equal(node.getblockchaininfo()["blocks"], 1001) 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 # negative heights should raise an exception
assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10) assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10)

94
test/functional/p2p_sendheaders.py

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

1
test/functional/rpc_blockchain.py

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

23
test/functional/rpc_txoutproof.py

@ -6,6 +6,8 @@
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import * from test_framework.util import *
from test_framework.mininode import FromHex, ToHex
from test_framework.messages import CMerkleBlock
class MerkleBlockTest(BitcoinTestFramework): class MerkleBlockTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
@ -78,6 +80,27 @@ class MerkleBlockTest(BitcoinTestFramework):
# We can't get a proof if we specify transactions from different blocks # 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]) 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__': if __name__ == '__main__':
MerkleBlockTest().main() MerkleBlockTest().main()

46
test/functional/test_framework/messages.py

@ -836,6 +836,52 @@ class BlockTransactions():
def __repr__(self): def __repr__(self):
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions)) 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 # Objects that correspond to messages on the wire
class msg_version(): class msg_version():

32
test/functional/wallet_abandonconflict.py

@ -47,32 +47,40 @@ class AbandonConflictTest(BitcoinTestFramework):
inputs.append({"txid":txB, "vout":nB}) inputs.append({"txid":txB, "vout":nB})
outputs = {} outputs = {}
outputs[self.nodes[0].getnewaddress()] = Decimal("14.998") outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998")
outputs[self.nodes[1].getnewaddress()] = Decimal("5") outputs[self.nodes[1].getnewaddress()] = Decimal("5")
signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) txAB1 = self.nodes[0].sendrawtransaction(signed["hex"])
# Identify the 14.99998btc output # Identify the 14.99998btc output
nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.998")) nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998"))
#Create a child tx spending AB1 and C #Create a child tx spending AB1 and C
inputs = [] inputs = []
inputs.append({"txid":txAB1, "vout":nAB}) inputs.append({"txid":txAB1, "vout":nAB})
inputs.append({"txid":txC, "vout":nC}) inputs.append({"txid":txC, "vout":nC})
outputs = {} outputs = {}
outputs[self.nodes[0].getnewaddress()] = Decimal("24.96") outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996")
signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) 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 # In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance() newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("30") + Decimal("24.96")) assert_equal(newbalance, balance - Decimal("30") + signed3_change)
balance = newbalance balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool # Restart the node with a higher min relay fee so the parent tx is no longer in mempool
# TODO: redo with eviction # TODO: redo with eviction
self.stop_node(0) self.stop_node(0)
self.start_node(0, extra_args=["-minrelaytxfee=0.01"]) self.start_node(0, extra_args=["-minrelaytxfee=0.0001"])
# Verify txs no longer in either node's mempool # Verify txs no longer in either node's mempool
assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[0].getrawmempool()), 0)
@ -81,7 +89,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Not in mempool txs from self should only reduce balance # Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received # inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance() 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 # Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance # up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance() unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
@ -99,7 +107,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned # 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.stop_node(0)
self.start_node(0, extra_args=["-minrelaytxfee=0.001"]) self.start_node(0, extra_args=["-minrelaytxfee=0.00001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[0].getrawmempool()), 0)
assert_equal(self.nodes[0].getbalance(), balance) assert_equal(self.nodes[0].getbalance(), balance)
@ -108,21 +116,21 @@ class AbandonConflictTest(BitcoinTestFramework):
# But its child tx remains abandoned # But its child tx remains abandoned
self.nodes[0].sendrawtransaction(signed["hex"]) self.nodes[0].sendrawtransaction(signed["hex"])
newbalance = self.nodes[0].getbalance() newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("20") + Decimal("14.998")) assert_equal(newbalance, balance - Decimal("20") + Decimal("14.99998"))
balance = newbalance balance = newbalance
# Send child tx again so its unabandoned # Send child tx again so its unabandoned
self.nodes[0].sendrawtransaction(signed2["hex"]) self.nodes[0].sendrawtransaction(signed2["hex"])
newbalance = self.nodes[0].getbalance() newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("10") - Decimal("14.998") + Decimal("24.96")) assert_equal(newbalance, balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
balance = newbalance balance = newbalance
# Remove using high relay fee again # Remove using high relay fee again
self.stop_node(0) self.stop_node(0)
self.start_node(0, extra_args=["-minrelaytxfee=0.01"]) self.start_node(0, extra_args=["-minrelaytxfee=0.0001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[0].getrawmempool()), 0)
newbalance = self.nodes[0].getbalance() newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("24.96")) assert_equal(newbalance, balance - Decimal("24.9996"))
balance = newbalance balance = newbalance
# Create a double spend of AB1 by spending again from only A's 10 output # Create a double spend of AB1 by spending again from only A's 10 output
@ -130,7 +138,7 @@ class AbandonConflictTest(BitcoinTestFramework):
inputs =[] inputs =[]
inputs.append({"txid":txA, "vout":nA}) inputs.append({"txid":txA, "vout":nA})
outputs = {} outputs = {}
outputs[self.nodes[1].getnewaddress()] = Decimal("9.99") outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999")
tx = self.nodes[0].createrawtransaction(inputs, outputs) tx = self.nodes[0].createrawtransaction(inputs, outputs)
signed = self.nodes[0].signrawtransaction(tx) signed = self.nodes[0].signrawtransaction(tx)
self.nodes[1].sendrawtransaction(signed["hex"]) self.nodes[1].sendrawtransaction(signed["hex"])

9
test/functional/wallet_encryption.py

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

8
test/functional/wallet_listreceivedby.py

@ -6,10 +6,13 @@
from decimal import Decimal from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework 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_equal,
assert_raises_rpc_error, assert_raises_rpc_error,
) sync_blocks,
)
class ReceivedByTest(BitcoinTestFramework): class ReceivedByTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
@ -18,6 +21,7 @@ class ReceivedByTest(BitcoinTestFramework):
def run_test(self): def run_test(self):
# Generate block to get out of IBD # Generate block to get out of IBD
self.nodes[0].generate(1) self.nodes[0].generate(1)
sync_blocks(self.nodes)
self.log.info("listreceivedbyaddress Test") self.log.info("listreceivedbyaddress Test")

Loading…
Cancel
Save