Merge #10516: Backports for 0.14.3
ff274d3
[doc] Add hint about getmempoolentry to getrawmempool help. (Karl-Johan Alm)76f9cf9
contrib: Update location of seeds.txt (Wladimir J. van der Laan)12adedf
Trivial: remove extra character from comment (CryptAxe)d2ec969
Fixed typo in documentation for merkleblock.h (Mikerah)3612219
contrib/init/bitcoind.openrcconf: Don't disable wallet by default (Luke Dashjr)692dbb0
[doc] Minor corrections to osx dependencies (fanquake)87a21d5
Fix: make CCoinsViewDbCursor::Seek work for missing keys (Pieter Wuille)28b8b8b
[wallet] Securely erase potentially sensitive keys/values (Thomas Snider)ff13f59
[wallet] Make sure pindex is non-null before possibly referencing in LogPrintf call. (Karl-Johan Alm)e23cef0
Fix some empty vector references (Pieter Wuille)6ad45b8
Re-enable upnp support in contrib/debian (Matt Corallo)e9a0d89
Build with QT5 on Debian-based systems using contrib/debian (Matt Corallo)2ea0358
Bump minimum boost version in contrib/debian (Matt Corallo)c94e262
Update contrib/debian to latest Ubuntu PPA upload. (Matt Corallo)96c7f2c
Add CheckQueue Tests (Jeremy Rubin)e207342
Fix CCheckQueue IsIdle (potential) race condition and remove dangerous constructors. (Jeremy Rubin)ef810c4
[trivial] Fix a typo (introduced two days ago) in the default fee warning (practicalswift)7abe7bb
Qt/Send: Give fallback fee a reasonable indent (Luke Dashjr)3e4d7bf
Qt/Send: Figure a decent warning colour from theme (Luke Dashjr)c5adf8f
[Qt] Show more significant warning if we fall back to the default fee (Jonas Schnelli)ee1a60d
[tests] update disconnect_ban.py test case to work with listbanned (John Newbery)d289b56
[net] listbanned RPC and QT should show correct banned subnets (John Newbery)0422693
[tests] disconnect_ban: remove dependency on urllib (John Newbery)98bd0c3
[tests] disconnect_ban: use wait_until instead of sleep (John Newbery)bfd1cf6
[tests] disconnectban test - only use two nodes (John Newbery)5bc75bb
[tests] fix nodehandling.py flake8 warnings (John Newbery)c25d0a8
Update release notes to include RPC error code changes. (John Newbery)f5efe82
Return correct error codes in fundrawtransaction(). (John Newbery)4943d7a
Return correct error codes in setban(). (John Newbery)18c109d
Return correct error codes in removeprunedfunds(). (John Newbery)fe51c89
Return correct error codes in blockchain.cpp. (John Newbery)3ad00b4
Return correct error codes in bumpfee(). (John Newbery)71463a7
[qa] Test prioritise_transaction / getblocktemplate interaction (Suhas Daftuar)d28d583
Bugfix: PrioritiseTransaction updates the mempool tx counter (Suhas Daftuar) Tree-SHA512: fa3628527c8e176e438de992b9c5815cc2f3c296dbe5d81b592d17a907554e9c6af7eb595e96a2c345de399ba5326c07b4791a91b7b07f89dce0787c85891206
This commit is contained in:
commit
91be5e3c1e
|
@ -1,3 +1,122 @@
|
|||
bitcoin (0.14.1-trusty4) trusty; urgency=medium
|
||||
|
||||
* Re-enable UPnP support.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 05 May 2017 13:28:00 -0400
|
||||
|
||||
bitcoin (0.14.1-trusty3) trusty; urgency=medium
|
||||
|
||||
* Build with qt5 if we are on a non-Ubuntu (ie non-Unity) distro.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 04 May 2017 17:13:00 -0400
|
||||
|
||||
bitcoin (0.14.1-trusty2) trusty; urgency=medium
|
||||
|
||||
* Bump minimum boost version in deps.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 04 May 2017 17:12:00 -0400
|
||||
|
||||
bitcoin (0.14.1-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Sat, 22 Apr 2017 17:10:00 -0400
|
||||
|
||||
bitcoin (0.14.0-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 08 Mar 2017 10:30:00 -0500
|
||||
|
||||
bitcoin (0.13.2-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 05 Jan 2017 09:59:00 -0500
|
||||
|
||||
bitcoin (0.13.1-trusty2) trusty; urgency=medium
|
||||
|
||||
* Revert to Qt4, due to https://github.com/bitcoin/bitcoin/issues/9038
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 31 Oct 2016 11:16:00 -0400
|
||||
|
||||
bitcoin (0.13.1-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
* Backport updated bitcoin-qt.desktop from upstream master
|
||||
* Add zmq dependency
|
||||
* Switch to Qt5 (breaks precise, but that was already broken by C++11)
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 27 Oct 2016 17:32:00 -0400
|
||||
|
||||
bitcoin (0.13.0-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Sun, 04 Sep 2016 22:09:00 -0400
|
||||
|
||||
bitcoin (0.12.1-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 18 Apr 2016 14:26:00 -0700
|
||||
|
||||
bitcoin (0.12.0-trusty6) trusty; urgency=medium
|
||||
|
||||
* Fix program-options dep.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 25 Mar 2016 21:41:00 -0700
|
||||
|
||||
bitcoin (0.12.0-trusty5) trusty; urgency=medium
|
||||
|
||||
* Test explicit --with-gui
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 23:25:00 -0800
|
||||
|
||||
bitcoin (0.12.0-trusty4) trusty; urgency=medium
|
||||
|
||||
* Fix libevent-dev dep.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 23:25:00 -0800
|
||||
|
||||
bitcoin (0.12.0-trusty3) trusty; urgency=medium
|
||||
|
||||
* Fix precise boost dep.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:55:00 -0800
|
||||
|
||||
bitcoin (0.12.0-trusty2) trusty; urgency=medium
|
||||
|
||||
* Fix libevent dep.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:53:00 -0800
|
||||
|
||||
bitcoin (0.12.0-trusty1) trusty; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
* Various updates to contrib/debian were merged, a few were not
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:29:00 -0800
|
||||
|
||||
bitcoin (0.11.2-trusty1) trusty; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 13 Nov 2015 18:39:00 -0800
|
||||
|
||||
bitcoin (0.11.1-trusty2) trusty; urgency=low
|
||||
|
||||
* Remove minupnpc builddep.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 14 Oct 2015 23:06:00 -1000
|
||||
|
||||
bitcoin (0.11.1-trusty1) trusty; urgency=high
|
||||
|
||||
* New upstream release.
|
||||
* Disable all UPnP support.
|
||||
|
||||
-- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 14 Oct 2015 13:57:00 -1000
|
||||
|
||||
bitcoin (0.11.0-precise1) precise; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
@ -179,7 +298,7 @@ bitcoin (0.5.3-natty0) natty; urgency=low
|
|||
bitcoin (0.5.2-natty1) natty; urgency=low
|
||||
|
||||
* Remove mentions on anonymity in package descriptions and manpage.
|
||||
These should never have been there, bitcoin isn't anonymous without
|
||||
These should never have been there, bitcoin isnt anonymous without
|
||||
a ton of work that virtually no users will ever be willing and
|
||||
capable of doing
|
||||
|
||||
|
@ -220,7 +339,7 @@ bitcoin (0.5.0~rc1-natty1) natty; urgency=low
|
|||
|
||||
* Add test_bitcoin to build test
|
||||
* Fix clean
|
||||
* Remove unnecessary build-dependancies
|
||||
* Remove uneccessary build-dependancies
|
||||
|
||||
-- Matt Corallo <matt@bluematt.me> Wed, 26 Oct 2011 14:37:18 -0400
|
||||
|
||||
|
@ -380,7 +499,7 @@ bitcoin (0.3.20.01~dfsg-1) unstable; urgency=low
|
|||
|
||||
bitcoin (0.3.19~dfsg-6) unstable; urgency=low
|
||||
|
||||
* Fix override aggressive optimizations.
|
||||
* Fix override agressive optimizations.
|
||||
* Fix tighten build-dependencies to really fit backporting to Lenny:
|
||||
+ Add fallback build-dependency on libdb4.6++-dev.
|
||||
+ Tighten unversioned Boost build-dependencies to recent versions,
|
||||
|
|
|
@ -1,27 +1,30 @@
|
|||
Source: bitcoin
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Jonas Smedegaard <dr@jones.dk>
|
||||
Uploaders: Micah Anderson <micah@debian.org>
|
||||
Maintainer: Matt Corallo <matt@mattcorallo.com>
|
||||
Uploaders: Matt Corallo <matt@mattcorallo.com>
|
||||
Build-Depends: debhelper,
|
||||
devscripts,
|
||||
automake,
|
||||
libtool,
|
||||
bash-completion,
|
||||
libboost-system-dev (>> 1.35) | libboost-system1.35-dev,
|
||||
libdb4.8++-dev,
|
||||
libssl-dev,
|
||||
pkg-config,
|
||||
libminiupnpc8-dev | libminiupnpc-dev (>> 1.6),
|
||||
libboost-filesystem-dev (>> 1.35) | libboost-filesystem1.35-dev,
|
||||
libboost-program-options-dev (>> 1.35) | libboost-program-options1.35-dev,
|
||||
libboost-thread-dev (>> 1.35) | libboost-thread1.35-dev,
|
||||
libboost-test-dev (>> 1.35) | libboost-test1.35-dev,
|
||||
qt4-qmake,
|
||||
libqt4-dev,
|
||||
libevent-dev,
|
||||
libboost-system1.48-dev | libboost-system-dev (>> 1.47),
|
||||
libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.47),
|
||||
libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.47),
|
||||
libboost-thread1.48-dev | libboost-thread-dev (>> 1.47),
|
||||
libboost-test1.48-dev | libboost-test-dev (>> 1.47),
|
||||
libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47),
|
||||
libminiupnpc8-dev | libminiupnpc-dev,
|
||||
qt4-qmake, libqt4-dev,
|
||||
qttools5-dev-tools, qttools5-dev,
|
||||
libqrencode-dev,
|
||||
libprotobuf-dev, protobuf-compiler,
|
||||
python
|
||||
python,
|
||||
libzmq3-dev
|
||||
Standards-Version: 3.9.2
|
||||
Homepage: https://bitcoincore.org/
|
||||
Vcs-Git: git://github.com/bitcoin/bitcoin.git
|
||||
|
@ -31,11 +34,11 @@ Package: bitcoind
|
|||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: peer-to-peer network based digital currency - daemon
|
||||
Bitcoin is an experimental new digital currency that enables instant
|
||||
payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer
|
||||
technology to operate with no central authority: managing transactions
|
||||
and issuing money are carried out collectively by the network. Bitcoin Core
|
||||
is the name of the open source software which enables the use of this currency.
|
||||
Bitcoin is a free open source peer-to-peer electronic cash system that
|
||||
is completely decentralized, without the need for a central server or
|
||||
trusted parties. Users hold the crypto keys to their own money and
|
||||
transact directly with each other, with the help of a P2P network to
|
||||
check for double-spending.
|
||||
.
|
||||
This package provides the daemon, bitcoind, and the CLI tool
|
||||
bitcoin-cli to interact with the daemon.
|
||||
|
@ -44,11 +47,11 @@ Package: bitcoin-qt
|
|||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: peer-to-peer network based digital currency - Qt GUI
|
||||
Bitcoin is an experimental new digital currency that enables instant
|
||||
payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer
|
||||
technology to operate with no central authority: managing transactions
|
||||
and issuing money are carried out collectively by the network. Bitcoin Core
|
||||
is the name of the open source software which enables the use of this currency.
|
||||
Bitcoin is a free open source peer-to-peer electronic cash system that
|
||||
is completely decentralized, without the need for a central server or
|
||||
trusted parties. Users hold the crypto keys to their own money and
|
||||
transact directly with each other, with the help of a P2P network to
|
||||
check for double-spending.
|
||||
.
|
||||
This package provides Bitcoin-Qt, a GUI for Bitcoin based on Qt.
|
||||
|
||||
|
@ -56,11 +59,11 @@ Package: bitcoin-tx
|
|||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: peer-to-peer digital currency - standalone transaction tool
|
||||
Bitcoin is an experimental new digital currency that enables instant
|
||||
payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer
|
||||
technology to operate with no central authority: managing transactions
|
||||
and issuing money are carried out collectively by the network. Bitcoin Core
|
||||
is the name of the open source software which enables the use of this currency.
|
||||
Bitcoin is a free open source peer-to-peer electronic cash system that
|
||||
is completely decentralized, without the need for a central server or
|
||||
trusted parties. Users hold the crypto keys to their own money and
|
||||
transact directly with each other, with the help of a P2P network to
|
||||
check for double-spending.
|
||||
.
|
||||
This package provides bitcoin-tx, a command-line transaction creation
|
||||
tool which can be used without a bitcoin daemon. Some means of
|
||||
|
|
|
@ -12,10 +12,12 @@ override_dh_auto_clean:
|
|||
if [ -f Makefile ]; then $(MAKE) distclean; fi
|
||||
rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/bitcoin-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in
|
||||
|
||||
QT=$(shell dpkg-vendor --derives-from Ubuntu && echo qt4 || echo qt5)
|
||||
|
||||
# Yea, autogen should be run on the source archive, but I like doing git archive
|
||||
override_dh_auto_configure:
|
||||
./autogen.sh
|
||||
./configure
|
||||
./configure --with-gui=$(QT)
|
||||
|
||||
override_dh_auto_test:
|
||||
make check
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#BITCOIND_NICE=0
|
||||
|
||||
# Additional options (avoid -conf and -datadir, use flags above)
|
||||
BITCOIND_OPTS="-disablewallet"
|
||||
#BITCOIND_OPTS=""
|
||||
|
||||
# The timeout in seconds OpenRC will wait for bitcoind to terminate
|
||||
# after a SIGTERM has been raised.
|
||||
|
|
|
@ -8,7 +8,7 @@ and remove old versions as necessary.
|
|||
|
||||
The seeds compiled into the release are created from sipa's DNS seed data, like this:
|
||||
|
||||
curl -s http://bitcoin.sipa.be/seeds.txt > seeds_main.txt
|
||||
curl -s http://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt
|
||||
python3 makeseeds.py < seeds_main.txt > nodes_main.txt
|
||||
python3 generate-seeds.py . > ../../src/chainparamsseeds.h
|
||||
|
||||
|
|
|
@ -11,14 +11,14 @@ Install the OS X command line tools:
|
|||
|
||||
When the popup appears, click `Install`.
|
||||
|
||||
Then install [Homebrew](http://brew.sh).
|
||||
Then install [Homebrew](https://brew.sh).
|
||||
|
||||
Dependencies
|
||||
----------------------
|
||||
|
||||
brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf --c++11 qt5 libevent
|
||||
brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf qt libevent
|
||||
|
||||
In case you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG
|
||||
If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG
|
||||
|
||||
brew install librsvg
|
||||
|
||||
|
|
|
@ -30,6 +30,55 @@ frequently tested on them.
|
|||
Notable changes
|
||||
===============
|
||||
|
||||
Low-level RPC changes
|
||||
---------------------
|
||||
|
||||
- Error codes have been updated to be more accurate for the following error cases:
|
||||
- `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for
|
||||
example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR.
|
||||
- `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned
|
||||
because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND.
|
||||
- `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned
|
||||
because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR.
|
||||
- `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned
|
||||
because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR.
|
||||
- `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address
|
||||
or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED.
|
||||
- `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban
|
||||
a node that has not previously been banned. Previously returned RPC_MISC_ERROR.
|
||||
- `removeprunedfunds` now returns RPC_WALLET_ERROR if bitcoind is unable to remove
|
||||
the transaction. Previously returned RPC_INTERNAL_ERROR.
|
||||
- `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not
|
||||
exist in the wallet. Previously returned RPC_INTERNAL_ERROR.
|
||||
- `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change
|
||||
address is provided. Previously returned RPC_INVALID_PARAMETER.
|
||||
- `fundrawtransaction` now returns RPC_WALLET_ERROR if bitcoind is unable to create
|
||||
the transaction. The error message provides further details. Previously returned
|
||||
RPC_INTERNAL_ERROR.
|
||||
- `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has
|
||||
descendants in the wallet. Previously returned RPC_MISC_ERROR.
|
||||
- `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has
|
||||
descendants in the mempool. Previously returned RPC_MISC_ERROR.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has
|
||||
has been mined or conflicts with a mined transaction. Previously returned
|
||||
RPC_INVALID_ADDRESS_OR_KEY.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not
|
||||
BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already
|
||||
been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains
|
||||
inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change
|
||||
outputs. Previously returned RPC_MISC_ERROR.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change
|
||||
output. Previously returned RPC_MISC_ERROR.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned
|
||||
RPC_MISC_ERROR.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned
|
||||
RPC_MISC_ERROR.
|
||||
- `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the
|
||||
fee. Previously returned RPC_MISC_ERROR.
|
||||
|
||||
miniupnp CVE-2017-8798
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
|
|||
def test_nonrbf_bumpfee_fails(peer_node, dest_address):
|
||||
# cannot replace a non RBF transaction (from node which did not enable RBF)
|
||||
not_rbfid = create_fund_sign_send(peer_node, {dest_address: 0.00090000})
|
||||
assert_raises_message(JSONRPCException, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
|
||||
assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
|
||||
|
||||
|
||||
def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
|
||||
|
@ -149,7 +149,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
|
|||
signedtx = rbf_node.signrawtransaction(rawtx)
|
||||
signedtx = peer_node.signrawtransaction(signedtx["hex"])
|
||||
rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
|
||||
assert_raises_message(JSONRPCException, "Transaction contains inputs that don't belong to this wallet",
|
||||
assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet",
|
||||
rbf_node.bumpfee, rbfid)
|
||||
|
||||
|
||||
|
@ -160,7 +160,7 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
|
|||
tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
|
||||
tx = rbf_node.signrawtransaction(tx)
|
||||
txid = rbf_node.sendrawtransaction(tx["hex"])
|
||||
assert_raises_message(JSONRPCException, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
|
||||
assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
|
||||
|
||||
|
||||
def test_small_output_fails(rbf_node, dest_address):
|
||||
|
@ -175,7 +175,7 @@ def test_small_output_fails(rbf_node, dest_address):
|
|||
Decimal("0.00100000"),
|
||||
{dest_address: 0.00080000,
|
||||
get_change_address(rbf_node): Decimal("0.00010000")})
|
||||
assert_raises_message(JSONRPCException, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001})
|
||||
assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001})
|
||||
|
||||
|
||||
def test_dust_to_fee(rbf_node, dest_address):
|
||||
|
@ -210,7 +210,7 @@ def test_rebumping(rbf_node, dest_address):
|
|||
rbf_node.settxfee(Decimal("0.00001000"))
|
||||
rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
|
||||
bumped = rbf_node.bumpfee(rbfid, {"totalFee": 1000})
|
||||
assert_raises_message(JSONRPCException, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000})
|
||||
assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000})
|
||||
rbf_node.bumpfee(bumped["txid"], {"totalFee": 2000})
|
||||
|
||||
|
||||
|
@ -218,7 +218,7 @@ def test_rebumping_not_replaceable(rbf_node, dest_address):
|
|||
# check that re-bumping a non-replaceable bump tx fails
|
||||
rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
|
||||
bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
|
||||
assert_raises_message(JSONRPCException, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
|
||||
assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
|
||||
{"totalFee": 20000})
|
||||
|
||||
|
||||
|
@ -269,7 +269,7 @@ def test_bumpfee_metadata(rbf_node, dest_address):
|
|||
def test_locked_wallet_fails(rbf_node, dest_address):
|
||||
rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
|
||||
rbf_node.walletlock()
|
||||
assert_raises_message(JSONRPCException, "Please enter the wallet passphrase with walletpassphrase first.",
|
||||
assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.",
|
||||
rbf_node.bumpfee, rbfid)
|
||||
|
||||
|
||||
|
@ -316,9 +316,7 @@ def submit_block_with_tx(node, tx):
|
|||
block.rehash()
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.solve()
|
||||
error = node.submitblock(bytes_to_hex_str(block.serialize(True)))
|
||||
if error is not None:
|
||||
raise Exception(error)
|
||||
node.submitblock(bytes_to_hex_str(block.serialize(True)))
|
||||
return block
|
||||
|
||||
|
||||
|
|
|
@ -186,12 +186,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
|
||||
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
|
||||
|
||||
try:
|
||||
self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'})
|
||||
raise AssertionError("Accepted invalid option foo")
|
||||
except JSONRPCException as e:
|
||||
assert("Unexpected key foo" in e.error['message'])
|
||||
|
||||
assert_raises_jsonrpc(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'})
|
||||
|
||||
############################################################
|
||||
# test a fundrawtransaction with an invalid change address #
|
||||
|
@ -204,12 +199,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
|
||||
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
|
||||
|
||||
try:
|
||||
self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': 'foobar'})
|
||||
raise AssertionError("Accepted invalid bitcoin address")
|
||||
except JSONRPCException as e:
|
||||
assert("changeAddress must be a valid bitcoin address" in e.error['message'])
|
||||
|
||||
assert_raises_jsonrpc(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
|
||||
|
||||
############################################################
|
||||
# test a fundrawtransaction with a provided change address #
|
||||
|
@ -223,12 +213,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
|
||||
|
||||
change = self.nodes[2].getnewaddress()
|
||||
try:
|
||||
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 2})
|
||||
except JSONRPCException as e:
|
||||
assert('changePosition out of bounds' == e.error['message'])
|
||||
else:
|
||||
assert(False)
|
||||
assert_raises_jsonrpc(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2})
|
||||
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
|
||||
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
|
||||
out = dec_tx['vout'][0]
|
||||
|
@ -337,12 +322,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
|
||||
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
|
||||
|
||||
try:
|
||||
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
|
||||
raise AssertionError("Spent more than available")
|
||||
except JSONRPCException as e:
|
||||
assert("Insufficient" in e.error['message'])
|
||||
|
||||
assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx)
|
||||
|
||||
############################################################
|
||||
#compare fee of a standard pubkeyhash transaction
|
||||
|
@ -498,21 +478,13 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
|
||||
# fund a transaction that requires a new key for the change output
|
||||
# creating the key must be impossible because the wallet is locked
|
||||
try:
|
||||
fundedTx = self.nodes[1].fundrawtransaction(rawTx)
|
||||
raise AssertionError("Wallet unlocked without passphrase")
|
||||
except JSONRPCException as e:
|
||||
assert('Keypool ran out' in e.error['message'])
|
||||
assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[1].fundrawtransaction, rawtx)
|
||||
|
||||
#refill the keypool
|
||||
self.nodes[1].walletpassphrase("test", 100)
|
||||
self.nodes[1].walletlock()
|
||||
|
||||
try:
|
||||
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
|
||||
raise AssertionError("Wallet unlocked without passphrase")
|
||||
except JSONRPCException as e:
|
||||
assert('walletpassphrase' in e.error['message'])
|
||||
assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2)
|
||||
|
||||
oldBalance = self.nodes[0].getbalance()
|
||||
|
||||
|
|
|
@ -76,12 +76,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||
self.sync_all()
|
||||
|
||||
#Import with no affiliated address
|
||||
try:
|
||||
self.nodes[1].importprunedfunds(rawtxn1, proof1)
|
||||
except JSONRPCException as e:
|
||||
assert('No addresses' in e.error['message'])
|
||||
else:
|
||||
assert(False)
|
||||
assert_raises_jsonrpc(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1)
|
||||
|
||||
balance1 = self.nodes[1].getbalance("", 0, True)
|
||||
assert_equal(balance1, Decimal(0))
|
||||
|
@ -112,12 +107,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||
assert_equal(address_info['ismine'], True)
|
||||
|
||||
#Remove transactions
|
||||
try:
|
||||
self.nodes[1].removeprunedfunds(txnid1)
|
||||
except JSONRPCException as e:
|
||||
assert('does not exist' in e.error['message'])
|
||||
else:
|
||||
assert(False)
|
||||
assert_raises_jsonrpc(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1)
|
||||
|
||||
balance1 = self.nodes[1].getbalance("*", 0, True)
|
||||
assert_equal(balance1, Decimal('0.075'))
|
||||
|
|
|
@ -7,79 +7,83 @@
|
|||
# Test node handling
|
||||
#
|
||||
|
||||
from test_framework.mininode import wait_until
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.util import (assert_equal,
|
||||
assert_raises_jsonrpc,
|
||||
connect_nodes_bi,
|
||||
start_node,
|
||||
stop_node,
|
||||
)
|
||||
|
||||
import urllib.parse
|
||||
|
||||
class NodeHandlingTest (BitcoinTestFramework):
|
||||
class NodeHandlingTest(BitcoinTestFramework):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.num_nodes = 4
|
||||
self.num_nodes = 2
|
||||
self.setup_clean_chain = False
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = self.setup_nodes()
|
||||
connect_nodes_bi(self.nodes, 0, 1)
|
||||
|
||||
def run_test(self):
|
||||
###########################
|
||||
# setban/listbanned tests #
|
||||
###########################
|
||||
assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point
|
||||
self.nodes[2].setban("127.0.0.1", "add")
|
||||
time.sleep(3) #wait till the nodes are disconected
|
||||
assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point
|
||||
assert_equal(len(self.nodes[2].listbanned()), 1)
|
||||
self.nodes[2].clearbanned()
|
||||
assert_equal(len(self.nodes[2].listbanned()), 0)
|
||||
self.nodes[2].setban("127.0.0.0/24", "add")
|
||||
assert_equal(len(self.nodes[2].listbanned()), 1)
|
||||
try:
|
||||
self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24
|
||||
except:
|
||||
pass
|
||||
assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
|
||||
try:
|
||||
self.nodes[2].setban("127.0.0.1", "remove")
|
||||
except:
|
||||
pass
|
||||
assert_equal(len(self.nodes[2].listbanned()), 1)
|
||||
self.nodes[2].setban("127.0.0.0/24", "remove")
|
||||
assert_equal(len(self.nodes[2].listbanned()), 0)
|
||||
self.nodes[2].clearbanned()
|
||||
assert_equal(len(self.nodes[2].listbanned()), 0)
|
||||
assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point
|
||||
self.nodes[1].setban("127.0.0.1", "add")
|
||||
assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)
|
||||
assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point
|
||||
assert_equal(len(self.nodes[1].listbanned()), 1)
|
||||
self.nodes[1].clearbanned()
|
||||
assert_equal(len(self.nodes[1].listbanned()), 0)
|
||||
self.nodes[1].setban("127.0.0.0/24", "add")
|
||||
assert_equal(len(self.nodes[1].listbanned()), 1)
|
||||
# This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24
|
||||
assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add")
|
||||
# This will throw an exception because 127.0.0.1/42 is not a real subnet
|
||||
assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add")
|
||||
assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
|
||||
# This will throw an exception because 127.0.0.1 was not added above
|
||||
assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove")
|
||||
assert_equal(len(self.nodes[1].listbanned()), 1)
|
||||
self.nodes[1].setban("127.0.0.0/24", "remove")
|
||||
assert_equal(len(self.nodes[1].listbanned()), 0)
|
||||
self.nodes[1].clearbanned()
|
||||
assert_equal(len(self.nodes[1].listbanned()), 0)
|
||||
|
||||
##test persisted banlist
|
||||
self.nodes[2].setban("127.0.0.0/32", "add")
|
||||
self.nodes[2].setban("127.0.0.0/24", "add")
|
||||
self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds
|
||||
self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds
|
||||
listBeforeShutdown = self.nodes[2].listbanned()
|
||||
assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here
|
||||
time.sleep(2) #make 100% sure we expired 192.168.0.1 node time
|
||||
# test persisted banlist
|
||||
self.nodes[1].setban("127.0.0.0/32", "add")
|
||||
self.nodes[1].setban("127.0.0.0/24", "add")
|
||||
self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds
|
||||
self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds
|
||||
listBeforeShutdown = self.nodes[1].listbanned()
|
||||
assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address'])
|
||||
assert wait_until(lambda: len(self.nodes[1].listbanned()) == 3, timeout=10)
|
||||
|
||||
#stop node
|
||||
stop_node(self.nodes[2], 2)
|
||||
stop_node(self.nodes[1], 1)
|
||||
|
||||
self.nodes[2] = start_node(2, self.options.tmpdir)
|
||||
listAfterShutdown = self.nodes[2].listbanned()
|
||||
self.nodes[1] = start_node(1, self.options.tmpdir)
|
||||
listAfterShutdown = self.nodes[1].listbanned()
|
||||
assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
|
||||
assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
|
||||
assert_equal("/19" in listAfterShutdown[2]['address'], True)
|
||||
|
||||
# Clear ban lists
|
||||
self.nodes[1].clearbanned()
|
||||
connect_nodes_bi(self.nodes, 0, 1)
|
||||
|
||||
###########################
|
||||
# RPC disconnectnode test #
|
||||
###########################
|
||||
url = urllib.parse.urlparse(self.nodes[1].url)
|
||||
self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1)))
|
||||
time.sleep(2) #disconnecting a node needs a little bit of time
|
||||
for node in self.nodes[0].getpeerinfo():
|
||||
assert(node['addr'] != url.hostname+":"+str(p2p_port(1)))
|
||||
address1 = self.nodes[0].getpeerinfo()[0]['addr']
|
||||
self.nodes[0].disconnectnode(address=address1)
|
||||
assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
|
||||
assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
|
||||
|
||||
connect_nodes_bi(self.nodes,0,1) #reconnect the node
|
||||
found = False
|
||||
for node in self.nodes[0].getpeerinfo():
|
||||
if node['addr'] == url.hostname+":"+str(p2p_port(1)):
|
||||
found = True
|
||||
assert(found)
|
||||
connect_nodes_bi(self.nodes, 0, 1) # reconnect the node
|
||||
assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
|
||||
|
||||
if __name__ == '__main__':
|
||||
NodeHandlingTest ().main ()
|
||||
NodeHandlingTest().main()
|
||||
|
|
|
@ -199,11 +199,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
|||
assert_equal(x['status'], "headers-only")
|
||||
|
||||
# But this block should be accepted by node0 since it has more work.
|
||||
try:
|
||||
self.nodes[0].getblock(blocks_h3[0].hash)
|
||||
print("Unrequested more-work block accepted from non-whitelisted peer")
|
||||
except:
|
||||
raise AssertionError("Unrequested more work block was not processed")
|
||||
self.nodes[0].getblock(blocks_h3[0].hash)
|
||||
print("Unrequested more-work block accepted from non-whitelisted peer")
|
||||
|
||||
# Node1 should have accepted and reorged.
|
||||
assert_equal(self.nodes[1].getblockcount(), 3)
|
||||
|
@ -227,26 +224,17 @@ class AcceptBlockTest(BitcoinTestFramework):
|
|||
tips[j] = next_block
|
||||
|
||||
time.sleep(2)
|
||||
for x in all_blocks:
|
||||
try:
|
||||
self.nodes[0].getblock(x.hash)
|
||||
if x == all_blocks[287]:
|
||||
raise AssertionError("Unrequested block too far-ahead should have been ignored")
|
||||
except:
|
||||
if x == all_blocks[287]:
|
||||
print("Unrequested block too far-ahead not processed")
|
||||
else:
|
||||
raise AssertionError("Unrequested block with more work should have been accepted")
|
||||
# Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead
|
||||
for x in all_blocks[:-1]:
|
||||
self.nodes[0].getblock(x.hash)
|
||||
assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash)
|
||||
|
||||
headers_message.headers.pop() # Ensure the last block is unrequested
|
||||
white_node.send_message(headers_message) # Send headers leading to tip
|
||||
white_node.send_message(msg_block(tips[1])) # Now deliver the tip
|
||||
try:
|
||||
white_node.sync_with_ping()
|
||||
self.nodes[1].getblock(tips[1].hash)
|
||||
print("Unrequested block far ahead of tip accepted from whitelisted peer")
|
||||
except:
|
||||
raise AssertionError("Unrequested block from whitelisted peer not accepted")
|
||||
white_node.sync_with_ping()
|
||||
self.nodes[1].getblock(tips[1].hash)
|
||||
print("Unrequested block far ahead of tip accepted from whitelisted peer")
|
||||
|
||||
# 5. Test handling of unrequested block on the node that didn't process
|
||||
# Should still not be processed (even though it has a child that has more
|
||||
|
|
|
@ -16,7 +16,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
self.num_nodes = 2
|
||||
|
||||
self.txouts = gen_return_txouts()
|
||||
|
||||
|
@ -25,8 +25,11 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
|||
self.is_network_split = False
|
||||
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-printpriority=1"]))
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
|
||||
|
||||
|
||||
def run_test(self):
|
||||
utxo_count = 90
|
||||
utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], utxo_count)
|
||||
|
@ -139,5 +142,16 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
|||
assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id)
|
||||
assert(tx2_id in self.nodes[0].getrawmempool())
|
||||
|
||||
# Test that calling prioritisetransaction is sufficient to trigger
|
||||
# getblocktemplate to (eventually) return a new block.
|
||||
mock_time = int(time.time())
|
||||
self.nodes[0].setmocktime(mock_time)
|
||||
template = self.nodes[0].getblocktemplate()
|
||||
self.nodes[0].prioritisetransaction(txid, 0, -int(self.relayfee*COIN))
|
||||
self.nodes[0].setmocktime(mock_time+10)
|
||||
new_template = self.nodes[0].getblocktemplate()
|
||||
|
||||
assert(template != new_template)
|
||||
|
||||
if __name__ == '__main__':
|
||||
PrioritiseTransactionTest().main()
|
||||
|
|
|
@ -186,11 +186,8 @@ class PruneTest(BitcoinTestFramework):
|
|||
|
||||
def reorg_back(self):
|
||||
# Verify that a block on the old main chain fork has been pruned away
|
||||
try:
|
||||
self.nodes[2].getblock(self.forkhash)
|
||||
raise AssertionError("Old block wasn't pruned so can't test redownload")
|
||||
except JSONRPCException as e:
|
||||
print("Will need to redownload block",self.forkheight)
|
||||
assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash)
|
||||
print("Will need to redownload block",self.forkheight)
|
||||
|
||||
# Verify that we have enough history to reorg back to the fork point
|
||||
# Although this is more than 288 blocks, because this chain was written more recently
|
||||
|
@ -235,7 +232,7 @@ class PruneTest(BitcoinTestFramework):
|
|||
# at this point, node has 995 blocks and has not yet run in prune mode
|
||||
node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0"], timewait=900)
|
||||
assert_equal(node.getblockcount(), 995)
|
||||
assert_raises_message(JSONRPCException, "not in prune mode", node.pruneblockchain, 500)
|
||||
assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500)
|
||||
self.stop_node(node_number)
|
||||
|
||||
# now re-start in manual pruning mode
|
||||
|
@ -267,14 +264,14 @@ class PruneTest(BitcoinTestFramework):
|
|||
return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index))
|
||||
|
||||
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
|
||||
assert_raises_message(JSONRPCException, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
|
||||
assert_raises_jsonrpc(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
|
||||
|
||||
# mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
|
||||
node.generate(6)
|
||||
assert_equal(node.getblockchaininfo()["blocks"], 1001)
|
||||
|
||||
# negative heights should raise an exception
|
||||
assert_raises_message(JSONRPCException, "Negative", node.pruneblockchain, -10)
|
||||
assert_raises_jsonrpc(-8, "Negative", node.pruneblockchain, -10)
|
||||
|
||||
# height=100 too low to prune first block file so this is a no-op
|
||||
prune(100)
|
||||
|
@ -320,12 +317,9 @@ class PruneTest(BitcoinTestFramework):
|
|||
def wallet_test(self):
|
||||
# check that the pruning node's wallet is still in good shape
|
||||
print("Stop and start pruning node to trigger wallet rescan")
|
||||
try:
|
||||
self.stop_node(2)
|
||||
start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"])
|
||||
print("Success")
|
||||
except Exception as detail:
|
||||
raise AssertionError("Wallet test: unable to re-start the pruning node")
|
||||
self.stop_node(2)
|
||||
start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"])
|
||||
print("Success")
|
||||
|
||||
# check that wallet loads loads successfully when restarting a pruned node after IBD.
|
||||
# this was reported to fail in #7494.
|
||||
|
@ -333,12 +327,9 @@ class PruneTest(BitcoinTestFramework):
|
|||
connect_nodes(self.nodes[0], 5)
|
||||
nds = [self.nodes[0], self.nodes[5]]
|
||||
sync_blocks(nds, wait=5, timeout=300)
|
||||
try:
|
||||
self.stop_node(5) #stop and start to trigger rescan
|
||||
start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"])
|
||||
print ("Success")
|
||||
except Exception as detail:
|
||||
raise AssertionError("Wallet test: unable to re-start node5")
|
||||
self.stop_node(5) #stop and start to trigger rescan
|
||||
start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"])
|
||||
print ("Success")
|
||||
|
||||
def run_test(self):
|
||||
print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
|
||||
|
|
|
@ -61,13 +61,8 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
|
||||
rawtx = self.nodes[2].signrawtransaction(rawtx)
|
||||
|
||||
try:
|
||||
rawtx = self.nodes[2].sendrawtransaction(rawtx['hex'])
|
||||
except JSONRPCException as e:
|
||||
assert("Missing inputs" in e.error['message'])
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
# This will raise an exception since there are missing inputs
|
||||
assert_raises_jsonrpc(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex'])
|
||||
|
||||
#########################
|
||||
# RAW TX MULTISIG TESTS #
|
||||
|
@ -161,13 +156,13 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex'])
|
||||
|
||||
# 6. invalid parameters - supply txid and string "Flase"
|
||||
assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, "Flase")
|
||||
assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase")
|
||||
|
||||
# 7. invalid parameters - supply txid and empty array
|
||||
assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, [])
|
||||
assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, [])
|
||||
|
||||
# 8. invalid parameters - supply txid and empty dict
|
||||
assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, {})
|
||||
assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {})
|
||||
|
||||
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
|
||||
outputs = { self.nodes[0].getnewaddress() : 1 }
|
||||
|
@ -175,13 +170,15 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
decrawtx= self.nodes[0].decoderawtransaction(rawtx)
|
||||
assert_equal(decrawtx['vin'][0]['sequence'], 1000)
|
||||
|
||||
# 9. invalid parameters - sequence number out of range
|
||||
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}]
|
||||
outputs = { self.nodes[0].getnewaddress() : 1 }
|
||||
assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs)
|
||||
assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)
|
||||
|
||||
# 10. invalid parameters - sequence number out of range
|
||||
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}]
|
||||
outputs = { self.nodes[0].getnewaddress() : 1 }
|
||||
assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs)
|
||||
assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)
|
||||
|
||||
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}]
|
||||
outputs = { self.nodes[0].getnewaddress() : 1 }
|
||||
|
|
|
@ -89,6 +89,7 @@ BITCOIN_TESTS =\
|
|||
test/blockencodings_tests.cpp \
|
||||
test/bloom_tests.cpp \
|
||||
test/bswap_tests.cpp \
|
||||
test/checkqueue_tests.cpp \
|
||||
test/coins_tests.cpp \
|
||||
test/compress_tests.cpp \
|
||||
test/crypto_tests.cpp \
|
||||
|
|
|
@ -127,6 +127,9 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
//! Mutex to ensure only one concurrent CCheckQueueControl
|
||||
boost::mutex ControlMutex;
|
||||
|
||||
//! Create a new check queue
|
||||
CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
|
||||
|
||||
|
@ -161,12 +164,6 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
bool IsIdle()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
return (nTotal == nIdle && nTodo == 0 && fAllOk == true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -177,16 +174,18 @@ template <typename T>
|
|||
class CCheckQueueControl
|
||||
{
|
||||
private:
|
||||
CCheckQueue<T>* pqueue;
|
||||
CCheckQueue<T> * const pqueue;
|
||||
bool fDone;
|
||||
|
||||
public:
|
||||
CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false)
|
||||
CCheckQueueControl() = delete;
|
||||
CCheckQueueControl(const CCheckQueueControl&) = delete;
|
||||
CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
|
||||
explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false)
|
||||
{
|
||||
// passed queue is supposed to be unused, or NULL
|
||||
if (pqueue != NULL) {
|
||||
bool isIdle = pqueue->IsIdle();
|
||||
assert(isIdle);
|
||||
ENTER_CRITICAL_SECTION(pqueue->ControlMutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,6 +208,9 @@ public:
|
|||
{
|
||||
if (!fDone)
|
||||
Wait();
|
||||
if (pqueue != NULL) {
|
||||
LEAVE_CRITICAL_SECTION(pqueue->ControlMutex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve
|
|||
} else {
|
||||
// calculate left hash
|
||||
uint256 left = CalcHash(height-1, pos*2, vTxid), right;
|
||||
// calculate right hash if not beyond the end of the array - copy left hash otherwise1
|
||||
// calculate right hash if not beyond the end of the array - copy left hash otherwise
|
||||
if (pos*2+1 < CalcTreeWidth(height-1))
|
||||
right = CalcHash(height-1, pos*2+1, vTxid);
|
||||
else
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* storing a bit for each traversed node, signifying whether the node is the
|
||||
* parent of at least one matched leaf txid (or a matched txid itself). In
|
||||
* case we are at the leaf level, or this bit is 0, its merkle node hash is
|
||||
* stored, and its children are not explorer further. Otherwise, no hash is
|
||||
* stored, and its children are not explored further. Otherwise, no hash is
|
||||
* stored, but we recurse into both (or the only) child branch. During
|
||||
* decoding, the same depth-first traversal is performed, consuming bits and
|
||||
* hashes as they written during encoding.
|
||||
|
|
|
@ -413,10 +413,10 @@ void CConnman::DumpBanlist()
|
|||
|
||||
CBanDB bandb;
|
||||
banmap_t banmap;
|
||||
SetBannedSetDirty(false);
|
||||
GetBanned(banmap);
|
||||
if (!bandb.Write(banmap))
|
||||
SetBannedSetDirty(true);
|
||||
if (bandb.Write(banmap)) {
|
||||
SetBannedSetDirty(false);
|
||||
}
|
||||
|
||||
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
|
||||
banmap.size(), GetTimeMillis() - nStart);
|
||||
|
@ -536,6 +536,8 @@ bool CConnman::Unban(const CSubNet &subNet) {
|
|||
void CConnman::GetBanned(banmap_t &banMap)
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
// Sweep the banlist so expired bans are not returned
|
||||
SweepBanned();
|
||||
banMap = setBanned; //create a thread safe copy
|
||||
}
|
||||
|
||||
|
|
|
@ -759,11 +759,33 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="fallbackFeeWarningLabel">
|
||||
<property name="toolTip">
|
||||
<string>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain.</string>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Warning: Fee estimation is currently not possible.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "txmempool.h"
|
||||
#include "wallet/wallet.h"
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollBar>
|
||||
#include <QSettings>
|
||||
|
@ -656,6 +657,11 @@ void SendCoinsDialog::updateSmartFeeLabel()
|
|||
std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
|
||||
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
|
||||
ui->labelFeeEstimation->setText("");
|
||||
ui->fallbackFeeWarningLabel->setVisible(true);
|
||||
int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
|
||||
QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
|
||||
ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");
|
||||
ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -663,6 +669,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
|
|||
std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
|
||||
ui->labelSmartFee2->hide();
|
||||
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks));
|
||||
ui->fallbackFeeWarningLabel->setVisible(false);
|
||||
}
|
||||
|
||||
updateFeeMinimizedLabel();
|
||||
|
|
|
@ -417,6 +417,7 @@ UniValue getrawmempool(const JSONRPCRequest& request)
|
|||
throw runtime_error(
|
||||
"getrawmempool ( verbose )\n"
|
||||
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
|
||||
"\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n"
|
||||
"\nArguments:\n"
|
||||
"1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
|
||||
"\nResult: (for verbose = false):\n"
|
||||
|
@ -744,10 +745,15 @@ UniValue getblock(const JSONRPCRequest& request)
|
|||
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||
|
||||
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
|
||||
|
||||
if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
|
||||
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
|
||||
// Block not found on disk. This could be because we have the block
|
||||
// header in our index but don't have the block (for example if a
|
||||
// non-whitelisted node sends us an unrequested long chain of valid
|
||||
// blocks, we add the headers to our index, but don't accept the
|
||||
// block).
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
|
||||
|
||||
if (!fVerbose)
|
||||
{
|
||||
|
@ -829,7 +835,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
|
|||
+ HelpExampleRpc("pruneblockchain", "1000"));
|
||||
|
||||
if (!fPruneMode)
|
||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode.");
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
|
@ -843,7 +849,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
|
|||
// Add a 2 hour buffer to include blocks which might have had old timestamps
|
||||
CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - 7200);
|
||||
if (!pindex) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
|
||||
}
|
||||
heightParam = pindex->nHeight;
|
||||
}
|
||||
|
@ -851,7 +857,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
|
|||
unsigned int height = (unsigned int) heightParam;
|
||||
unsigned int chainHeight = (unsigned int) chainActive.Height();
|
||||
if (chainHeight < Params().PruneAfterHeight())
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning.");
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
|
||||
else if (height > chainHeight)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
|
||||
else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
|
||||
|
|
|
@ -506,7 +506,7 @@ UniValue setban(const JSONRPCRequest& request)
|
|||
LookupSubNet(request.params[0].get_str().c_str(), subNet);
|
||||
|
||||
if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
|
||||
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet");
|
||||
|
||||
if (strCommand == "add")
|
||||
{
|
||||
|
@ -526,7 +526,7 @@ UniValue setban(const JSONRPCRequest& request)
|
|||
else if(strCommand == "remove")
|
||||
{
|
||||
if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
|
||||
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
|
||||
}
|
||||
return NullUniValue;
|
||||
}
|
||||
|
|
|
@ -248,7 +248,8 @@ public:
|
|||
|
||||
void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
|
||||
{
|
||||
assert(last - first >= 0);
|
||||
if (last == first) return;
|
||||
assert(last - first > 0);
|
||||
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
|
||||
{
|
||||
// special case for inserting at the front when there's room
|
||||
|
@ -261,7 +262,8 @@ public:
|
|||
|
||||
void insert(iterator it, const char* first, const char* last)
|
||||
{
|
||||
assert(last - first >= 0);
|
||||
if (last == first) return;
|
||||
assert(last - first > 0);
|
||||
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
|
||||
{
|
||||
// special case for inserting at the front when there's room
|
||||
|
@ -339,6 +341,8 @@ public:
|
|||
|
||||
void read(char* pch, size_t nSize)
|
||||
{
|
||||
if (nSize == 0) return;
|
||||
|
||||
// Read from the beginning of the buffer
|
||||
unsigned int nReadPosNext = nReadPos + nSize;
|
||||
if (nReadPosNext >= vch.size())
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
// Attempt to overwrite data in the specified memory span.
|
||||
void memory_cleanse(void *ptr, size_t len);
|
||||
|
||||
#endif // BITCOIN_SUPPORT_CLEANSE_H
|
||||
|
|
442
src/test/checkqueue_tests.cpp
Normal file
442
src/test/checkqueue_tests.cpp
Normal file
|
@ -0,0 +1,442 @@
|
|||
// Copyright (c) 2012-2017 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "util.h"
|
||||
#include "utiltime.h"
|
||||
#include "validation.h"
|
||||
|
||||
#include "test/test_bitcoin.h"
|
||||
#include "checkqueue.h"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include "random.h"
|
||||
|
||||
// BasicTestingSetup not sufficient because nScriptCheckThreads is not set
|
||||
// otherwise.
|
||||
BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup)
|
||||
|
||||
static const int QUEUE_BATCH_SIZE = 128;
|
||||
|
||||
struct FakeCheck {
|
||||
bool operator()()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
void swap(FakeCheck& x){};
|
||||
};
|
||||
|
||||
struct FakeCheckCheckCompletion {
|
||||
static std::atomic<size_t> n_calls;
|
||||
bool operator()()
|
||||
{
|
||||
++n_calls;
|
||||
return true;
|
||||
}
|
||||
void swap(FakeCheckCheckCompletion& x){};
|
||||
};
|
||||
|
||||
struct FailingCheck {
|
||||
bool fails;
|
||||
FailingCheck(bool fails) : fails(fails){};
|
||||
FailingCheck() : fails(true){};
|
||||
bool operator()()
|
||||
{
|
||||
return !fails;
|
||||
}
|
||||
void swap(FailingCheck& x)
|
||||
{
|
||||
std::swap(fails, x.fails);
|
||||
};
|
||||
};
|
||||
|
||||
struct UniqueCheck {
|
||||
static std::mutex m;
|
||||
static std::unordered_multiset<size_t> results;
|
||||
size_t check_id;
|
||||
UniqueCheck(size_t check_id_in) : check_id(check_id_in){};
|
||||
UniqueCheck() : check_id(0){};
|
||||
bool operator()()
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m);
|
||||
results.insert(check_id);
|
||||
return true;
|
||||
}
|
||||
void swap(UniqueCheck& x) { std::swap(x.check_id, check_id); };
|
||||
};
|
||||
|
||||
|
||||
struct MemoryCheck {
|
||||
static std::atomic<size_t> fake_allocated_memory;
|
||||
bool b {false};
|
||||
bool operator()()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
MemoryCheck(){};
|
||||
MemoryCheck(const MemoryCheck& x)
|
||||
{
|
||||
// We have to do this to make sure that destructor calls are paired
|
||||
//
|
||||
// Really, copy constructor should be deletable, but CCheckQueue breaks
|
||||
// if it is deleted because of internal push_back.
|
||||
fake_allocated_memory += b;
|
||||
};
|
||||
MemoryCheck(bool b_) : b(b_)
|
||||
{
|
||||
fake_allocated_memory += b;
|
||||
};
|
||||
~MemoryCheck(){
|
||||
fake_allocated_memory -= b;
|
||||
|
||||
};
|
||||
void swap(MemoryCheck& x) { std::swap(b, x.b); };
|
||||
};
|
||||
|
||||
struct FrozenCleanupCheck {
|
||||
static std::atomic<uint64_t> nFrozen;
|
||||
static std::condition_variable cv;
|
||||
static std::mutex m;
|
||||
// Freezing can't be the default initialized behavior given how the queue
|
||||
// swaps in default initialized Checks.
|
||||
bool should_freeze {false};
|
||||
bool operator()()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
FrozenCleanupCheck() {}
|
||||
~FrozenCleanupCheck()
|
||||
{
|
||||
if (should_freeze) {
|
||||
std::unique_lock<std::mutex> l(m);
|
||||
nFrozen = 1;
|
||||
cv.notify_one();
|
||||
cv.wait(l, []{ return nFrozen == 0;});
|
||||
}
|
||||
}
|
||||
void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);};
|
||||
};
|
||||
|
||||
// Static Allocations
|
||||
std::mutex FrozenCleanupCheck::m{};
|
||||
std::atomic<uint64_t> FrozenCleanupCheck::nFrozen{0};
|
||||
std::condition_variable FrozenCleanupCheck::cv{};
|
||||
std::mutex UniqueCheck::m;
|
||||
std::unordered_multiset<size_t> UniqueCheck::results;
|
||||
std::atomic<size_t> FakeCheckCheckCompletion::n_calls{0};
|
||||
std::atomic<size_t> MemoryCheck::fake_allocated_memory{0};
|
||||
|
||||
// Queue Typedefs
|
||||
typedef CCheckQueue<FakeCheckCheckCompletion> Correct_Queue;
|
||||
typedef CCheckQueue<FakeCheck> Standard_Queue;
|
||||
typedef CCheckQueue<FailingCheck> Failing_Queue;
|
||||
typedef CCheckQueue<UniqueCheck> Unique_Queue;
|
||||
typedef CCheckQueue<MemoryCheck> Memory_Queue;
|
||||
typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;
|
||||
|
||||
|
||||
/** This test case checks that the CCheckQueue works properly
|
||||
* with each specified size_t Checks pushed.
|
||||
*/
|
||||
void Correct_Queue_range(std::vector<size_t> range)
|
||||
{
|
||||
auto small_queue = std::unique_ptr<Correct_Queue>(new Correct_Queue {QUEUE_BATCH_SIZE});
|
||||
boost::thread_group tg;
|
||||
for (auto x = 0; x < nScriptCheckThreads; ++x) {
|
||||
tg.create_thread([&]{small_queue->Thread();});
|
||||
}
|
||||
// Make vChecks here to save on malloc (this test can be slow...)
|
||||
std::vector<FakeCheckCheckCompletion> vChecks;
|
||||
for (auto i : range) {
|
||||
size_t total = i;
|
||||
FakeCheckCheckCompletion::n_calls = 0;
|
||||
CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());
|
||||
while (total) {
|
||||
vChecks.resize(std::min(total, (size_t) GetRand(10)));
|
||||
total -= vChecks.size();
|
||||
control.Add(vChecks);
|
||||
}
|
||||
BOOST_REQUIRE(control.Wait());
|
||||
if (FakeCheckCheckCompletion::n_calls != i) {
|
||||
BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);
|
||||
BOOST_TEST_MESSAGE("Failure on trial " << i << " expected, got " << FakeCheckCheckCompletion::n_calls);
|
||||
}
|
||||
}
|
||||
tg.interrupt_all();
|
||||
tg.join_all();
|
||||
}
|
||||
|
||||
/** Test that 0 checks is correct
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
|
||||
{
|
||||
std::vector<size_t> range;
|
||||
range.push_back((size_t)0);
|
||||
Correct_Queue_range(range);
|
||||
}
|
||||
/** Test that 1 check is correct
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One)
|
||||
{
|
||||
std::vector<size_t> range;
|
||||
range.push_back((size_t)1);
|
||||
Correct_Queue_range(range);
|
||||
}
|
||||
/** Test that MAX check is correct
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max)
|
||||
{
|
||||
std::vector<size_t> range;
|
||||
range.push_back(100000);
|
||||
Correct_Queue_range(range);
|
||||
}
|
||||
/** Test that random numbers of checks are correct
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)
|
||||
{
|
||||
std::vector<size_t> range;
|
||||
range.reserve(100000/1000);
|
||||
for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)GetRand(std::min((size_t)1000, ((size_t)100000) - i))))
|
||||
range.push_back(i);
|
||||
Correct_Queue_range(range);
|
||||
}
|
||||
|
||||
|
||||
/** Test that failing checks are caught */
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
|
||||
{
|
||||
auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE});
|
||||
|
||||
boost::thread_group tg;
|
||||
for (auto x = 0; x < nScriptCheckThreads; ++x) {
|
||||
tg.create_thread([&]{fail_queue->Thread();});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 1001; ++i) {
|
||||
CCheckQueueControl<FailingCheck> control(fail_queue.get());
|
||||
size_t remaining = i;
|
||||
while (remaining) {
|
||||
size_t r = GetRand(10);
|
||||
|
||||
std::vector<FailingCheck> vChecks;
|
||||
vChecks.reserve(r);
|
||||
for (size_t k = 0; k < r && remaining; k++, remaining--)
|
||||
vChecks.emplace_back(remaining == 1);
|
||||
control.Add(vChecks);
|
||||
}
|
||||
bool success = control.Wait();
|
||||
if (i > 0) {
|
||||
BOOST_REQUIRE(!success);
|
||||
} else if (i == 0) {
|
||||
BOOST_REQUIRE(success);
|
||||
}
|
||||
}
|
||||
tg.interrupt_all();
|
||||
tg.join_all();
|
||||
}
|
||||
// Test that a block validation which fails does not interfere with
|
||||
// future blocks, ie, the bad state is cleared.
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
|
||||
{
|
||||
auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE});
|
||||
boost::thread_group tg;
|
||||
for (auto x = 0; x < nScriptCheckThreads; ++x) {
|
||||
tg.create_thread([&]{fail_queue->Thread();});
|
||||
}
|
||||
|
||||
for (auto times = 0; times < 10; ++times) {
|
||||
for (bool end_fails : {true, false}) {
|
||||
CCheckQueueControl<FailingCheck> control(fail_queue.get());
|
||||
{
|
||||
std::vector<FailingCheck> vChecks;
|
||||
vChecks.resize(100, false);
|
||||
vChecks[99] = end_fails;
|
||||
control.Add(vChecks);
|
||||
}
|
||||
bool r =control.Wait();
|
||||
BOOST_REQUIRE(r || end_fails);
|
||||
}
|
||||
}
|
||||
tg.interrupt_all();
|
||||
tg.join_all();
|
||||
}
|
||||
|
||||
// Test that unique checks are actually all called individually, rather than
|
||||
// just one check being called repeatedly. Test that checks are not called
|
||||
// more than once as well
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
|
||||
{
|
||||
auto queue = std::unique_ptr<Unique_Queue>(new Unique_Queue {QUEUE_BATCH_SIZE});
|
||||
boost::thread_group tg;
|
||||
for (auto x = 0; x < nScriptCheckThreads; ++x) {
|
||||
tg.create_thread([&]{queue->Thread();});
|
||||
|
||||
}
|
||||
|
||||
size_t COUNT = 100000;
|
||||
size_t total = COUNT;
|
||||
{
|
||||
CCheckQueueControl<UniqueCheck> control(queue.get());
|
||||
while (total) {
|
||||
size_t r = GetRand(10);
|
||||
std::vector<UniqueCheck> vChecks;
|
||||
for (size_t k = 0; k < r && total; k++)
|
||||
vChecks.emplace_back(--total);
|
||||
control.Add(vChecks);
|
||||
}
|
||||
}
|
||||
bool r = true;
|
||||
BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT);
|
||||
for (size_t i = 0; i < COUNT; ++i)
|
||||
r = r && UniqueCheck::results.count(i) == 1;
|
||||
BOOST_REQUIRE(r);
|
||||
tg.interrupt_all();
|
||||
tg.join_all();
|
||||
}
|
||||
|
||||
|
||||
// Test that blocks which might allocate lots of memory free their memory agressively.
|
||||
//
|
||||
// This test attempts to catch a pathological case where by lazily freeing
|
||||
// checks might mean leaving a check un-swapped out, and decreasing by 1 each
|
||||
// time could leave the data hanging across a sequence of blocks.
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
|
||||
{
|
||||
auto queue = std::unique_ptr<Memory_Queue>(new Memory_Queue {QUEUE_BATCH_SIZE});
|
||||
boost::thread_group tg;
|
||||
for (auto x = 0; x < nScriptCheckThreads; ++x) {
|
||||
tg.create_thread([&]{queue->Thread();});
|
||||
}
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
size_t total = i;
|
||||
{
|
||||
CCheckQueueControl<MemoryCheck> control(queue.get());
|
||||
while (total) {
|
||||
size_t r = GetRand(10);
|
||||
std::vector<MemoryCheck> vChecks;
|
||||
for (size_t k = 0; k < r && total; k++) {
|
||||
total--;
|
||||
// Each iteration leaves data at the front, back, and middle
|
||||
// to catch any sort of deallocation failure
|
||||
vChecks.emplace_back(total == 0 || total == i || total == i/2);
|
||||
}
|
||||
control.Add(vChecks);
|
||||
}
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0);
|
||||
}
|
||||
tg.interrupt_all();
|
||||
tg.join_all();
|
||||
}
|
||||
|
||||
// Test that a new verification cannot occur until all checks
|
||||
// have been destructed
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
|
||||
{
|
||||
auto queue = std::unique_ptr<FrozenCleanup_Queue>(new FrozenCleanup_Queue {QUEUE_BATCH_SIZE});
|
||||
boost::thread_group tg;
|
||||
bool fails = false;
|
||||
for (auto x = 0; x < nScriptCheckThreads; ++x) {
|
||||
tg.create_thread([&]{queue->Thread();});
|
||||
}
|
||||
std::thread t0([&]() {
|
||||
CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
|
||||
std::vector<FrozenCleanupCheck> vChecks(1);
|
||||
// Freezing can't be the default initialized behavior given how the queue
|
||||
// swaps in default initialized Checks (otherwise freezing destructor
|
||||
// would get called twice).
|
||||
vChecks[0].should_freeze = true;
|
||||
control.Add(vChecks);
|
||||
control.Wait(); // Hangs here
|
||||
});
|
||||
{
|
||||
std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
|
||||
// Wait until the queue has finished all jobs and frozen
|
||||
FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;});
|
||||
// Try to get control of the queue a bunch of times
|
||||
for (auto x = 0; x < 100 && !fails; ++x) {
|
||||
fails = queue->ControlMutex.try_lock();
|
||||
}
|
||||
// Unfreeze
|
||||
FrozenCleanupCheck::nFrozen = 0;
|
||||
}
|
||||
// Awaken frozen destructor
|
||||
FrozenCleanupCheck::cv.notify_one();
|
||||
// Wait for control to finish
|
||||
t0.join();
|
||||
tg.interrupt_all();
|
||||
tg.join_all();
|
||||
BOOST_REQUIRE(!fails);
|
||||
}
|
||||
|
||||
|
||||
/** Test that CCheckQueueControl is threadsafe */
|
||||
BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
|
||||
{
|
||||
auto queue = std::unique_ptr<Standard_Queue>(new Standard_Queue{QUEUE_BATCH_SIZE});
|
||||
{
|
||||
boost::thread_group tg;
|
||||
std::atomic<int> nThreads {0};
|
||||
std::atomic<int> fails {0};
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
tg.create_thread(
|
||||
[&]{
|
||||
CCheckQueueControl<FakeCheck> control(queue.get());
|
||||
// While sleeping, no other thread should execute to this point
|
||||
auto observed = ++nThreads;
|
||||
MilliSleep(10);
|
||||
fails += observed != nThreads;
|
||||
});
|
||||
}
|
||||
tg.join_all();
|
||||
BOOST_REQUIRE_EQUAL(fails, 0);
|
||||
}
|
||||
{
|
||||
boost::thread_group tg;
|
||||
std::mutex m;
|
||||
bool has_lock {false};
|
||||
bool has_tried {false};
|
||||
bool done {false};
|
||||
bool done_ack {false};
|
||||
std::condition_variable cv;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m);
|
||||
tg.create_thread([&]{
|
||||
CCheckQueueControl<FakeCheck> control(queue.get());
|
||||
std::unique_lock<std::mutex> l(m);
|
||||
has_lock = true;
|
||||
cv.notify_one();
|
||||
cv.wait(l, [&]{return has_tried;});
|
||||
done = true;
|
||||
cv.notify_one();
|
||||
// Wait until the done is acknowledged
|
||||
//
|
||||
cv.wait(l, [&]{return done_ack;});
|
||||
});
|
||||
// Wait for thread to get the lock
|
||||
cv.wait(l, [&](){return has_lock;});
|
||||
bool fails = false;
|
||||
for (auto x = 0; x < 100 && !fails; ++x) {
|
||||
fails = queue->ControlMutex.try_lock();
|
||||
}
|
||||
has_tried = true;
|
||||
cv.notify_one();
|
||||
cv.wait(l, [&](){return done;});
|
||||
// Acknowledge the done
|
||||
done_ack = true;
|
||||
cv.notify_one();
|
||||
BOOST_REQUIRE(!fails);
|
||||
}
|
||||
tg.join_all();
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
@ -98,7 +98,11 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const
|
|||
that restriction. */
|
||||
i->pcursor->Seek(DB_COINS);
|
||||
// Cache key of first record
|
||||
i->pcursor->GetKey(i->keyTmp);
|
||||
if (i->pcursor->Valid()) {
|
||||
i->pcursor->GetKey(i->keyTmp);
|
||||
} else {
|
||||
i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
@ -945,6 +945,7 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string str
|
|||
BOOST_FOREACH(txiter descendantIt, setDescendants) {
|
||||
mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0));
|
||||
}
|
||||
++nTransactionsUpdated;
|
||||
}
|
||||
}
|
||||
LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
|
||||
|
|
|
@ -432,7 +432,7 @@ class CTxMemPool
|
|||
{
|
||||
private:
|
||||
uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check.
|
||||
unsigned int nTransactionsUpdated;
|
||||
unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
|
||||
CBlockPolicyEstimator* minerPolicyEstimator;
|
||||
|
||||
uint64_t totalTxSize; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
|
||||
|
|
|
@ -126,22 +126,23 @@ protected:
|
|||
Dbt datValue;
|
||||
datValue.set_flags(DB_DBT_MALLOC);
|
||||
int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
|
||||
memset(datKey.get_data(), 0, datKey.get_size());
|
||||
if (datValue.get_data() == NULL)
|
||||
return false;
|
||||
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||
bool success = false;
|
||||
if (datValue.get_data() != NULL) {
|
||||
// Unserialize value
|
||||
try {
|
||||
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
||||
ssValue >> value;
|
||||
success = true;
|
||||
} catch (const std::exception&) {
|
||||
// In this case success remains 'false'
|
||||
}
|
||||
|
||||
// Unserialize value
|
||||
try {
|
||||
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
||||
ssValue >> value;
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
// Clear and free memory
|
||||
memory_cleanse(datValue.get_data(), datValue.get_size());
|
||||
free(datValue.get_data());
|
||||
}
|
||||
|
||||
// Clear and free memory
|
||||
memset(datValue.get_data(), 0, datValue.get_size());
|
||||
free(datValue.get_data());
|
||||
return (ret == 0);
|
||||
return ret == 0 && success;
|
||||
}
|
||||
|
||||
template <typename K, typename T>
|
||||
|
@ -168,8 +169,8 @@ protected:
|
|||
int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
|
||||
|
||||
// Clear memory in case it was a private key
|
||||
memset(datKey.get_data(), 0, datKey.get_size());
|
||||
memset(datValue.get_data(), 0, datValue.get_size());
|
||||
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||
memory_cleanse(datValue.get_data(), datValue.get_size());
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
|
@ -191,7 +192,7 @@ protected:
|
|||
int ret = pdb->del(activeTxn, &datKey, 0);
|
||||
|
||||
// Clear memory
|
||||
memset(datKey.get_data(), 0, datKey.get_size());
|
||||
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||
return (ret == 0 || ret == DB_NOTFOUND);
|
||||
}
|
||||
|
||||
|
@ -211,7 +212,7 @@ protected:
|
|||
int ret = pdb->exists(activeTxn, &datKey, 0);
|
||||
|
||||
// Clear memory
|
||||
memset(datKey.get_data(), 0, datKey.get_size());
|
||||
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
|
@ -254,8 +255,8 @@ protected:
|
|||
ssValue.write((char*)datValue.get_data(), datValue.get_size());
|
||||
|
||||
// Clear and free memory
|
||||
memset(datKey.get_data(), 0, datKey.get_size());
|
||||
memset(datValue.get_data(), 0, datValue.get_size());
|
||||
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||
memory_cleanse(datValue.get_data(), datValue.get_size());
|
||||
free(datKey.get_data());
|
||||
free(datValue.get_data());
|
||||
return 0;
|
||||
|
|
|
@ -340,11 +340,11 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
|
|||
vector<uint256> vHashOut;
|
||||
|
||||
if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction.");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction.");
|
||||
}
|
||||
|
||||
if(vHashOut.empty()) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet.");
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
|
||||
}
|
||||
|
||||
return NullUniValue;
|
||||
|
|
|
@ -2603,7 +2603,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
|
|||
CBitcoinAddress address(options["changeAddress"].get_str());
|
||||
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
|
||||
|
||||
changeAddress = address.Get();
|
||||
}
|
||||
|
@ -2657,7 +2657,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
|
|||
string strFailReason;
|
||||
|
||||
if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("hex", EncodeHexTx(tx)));
|
||||
|
@ -2756,33 +2756,33 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
|||
CWalletTx& wtx = pwalletMain->mapWallet[hash];
|
||||
|
||||
if (pwalletMain->HasWalletSpend(hash)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the wallet");
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the wallet");
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
auto it = mempool.mapTx.find(hash);
|
||||
if (it != mempool.mapTx.end() && it->GetCountWithDescendants() > 1) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the mempool");
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the mempool");
|
||||
}
|
||||
}
|
||||
|
||||
if (wtx.GetDepthInMainChain() != 0) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction has been mined, or is conflicted with a mined transaction");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has been mined, or is conflicted with a mined transaction");
|
||||
}
|
||||
|
||||
if (!SignalsOptInRBF(wtx)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction is not BIP 125 replaceable");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is not BIP 125 replaceable");
|
||||
}
|
||||
|
||||
if (wtx.mapValue.count("replaced_by_txid")) {
|
||||
throw JSONRPCError(RPC_INVALID_REQUEST, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid")));
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid")));
|
||||
}
|
||||
|
||||
// check that original tx consists entirely of our inputs
|
||||
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
|
||||
if (!pwalletMain->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that don't belong to this wallet");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction contains inputs that don't belong to this wallet");
|
||||
}
|
||||
|
||||
// figure out which output was change
|
||||
|
@ -2791,13 +2791,13 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
|||
for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
|
||||
if (pwalletMain->IsChange(wtx.tx->vout[i])) {
|
||||
if (nOutput != -1) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Transaction has multiple change outputs");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has multiple change outputs");
|
||||
}
|
||||
nOutput = i;
|
||||
}
|
||||
}
|
||||
if (nOutput == -1) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not have a change output");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction does not have a change output");
|
||||
}
|
||||
|
||||
// Calculate the expected size of the new transaction.
|
||||
|
@ -2888,7 +2888,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
|||
|
||||
// Check that in all cases the new fee doesn't violate maxTxFee
|
||||
if (nNewFee > maxTxFee) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR,
|
||||
throw JSONRPCError(RPC_WALLET_ERROR,
|
||||
strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
|
||||
FormatMoney(nNewFee), FormatMoney(maxTxFee)));
|
||||
}
|
||||
|
@ -2900,7 +2900,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
|||
// moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
|
||||
CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
|
||||
if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
|
||||
}
|
||||
|
||||
// Now modify the output to increase the fee.
|
||||
|
@ -2910,7 +2910,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
|||
CMutableTransaction tx(*(wtx.tx));
|
||||
CTxOut* poutput = &(tx.vout[nOutput]);
|
||||
if (poutput->nValue < nDelta) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Change output is too small to bump the fee");
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Change output is too small to bump the fee");
|
||||
}
|
||||
|
||||
// If the output would become dust, discard it (converting the dust to fee)
|
||||
|
|
|
@ -1572,6 +1572,10 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
|
|||
{
|
||||
if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0)
|
||||
ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((GuessVerificationProgress(chainParams.TxData(), pindex) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
|
||||
if (GetTime() >= nNow + 60) {
|
||||
nNow = GetTime();
|
||||
LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
|
||||
}
|
||||
|
||||
CBlock block;
|
||||
if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
|
||||
|
@ -1585,10 +1589,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
|
|||
ret = nullptr;
|
||||
}
|
||||
pindex = chainActive.Next(pindex);
|
||||
if (GetTime() >= nNow + 60) {
|
||||
nNow = GetTime();
|
||||
LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
|
||||
}
|
||||
}
|
||||
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue