mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 11:32:46 +01:00
Merge pull request #4251 from PastaPastaPasta/backport-triv-pr12
backport: 'trivial' pr12
This commit is contained in:
commit
d0385cc04d
16
.fuzzbuzz.yml
Normal file
16
.fuzzbuzz.yml
Normal file
@ -0,0 +1,16 @@
|
||||
base: ubuntu:16.04
|
||||
language: c++
|
||||
engine: libFuzzer
|
||||
environment:
|
||||
- CXXFLAGS=-fcoverage-mapping -fno-omit-frame-pointer -fprofile-instr-generate -gline-tables-only -O1
|
||||
setup:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -y autoconf bsdmainutils clang git libboost-all-dev libboost-program-options-dev libc++1 libc++abi1 libc++abi-dev libc++-dev libclang1 libclang-dev libdb5.3++ libevent-dev libllvm-ocaml-dev libomp5 libomp-dev libprotobuf-dev libqt5core5a libqt5dbus5 libqt5gui5 libssl-dev libtool llvm llvm-dev llvm-runtime pkg-config protobuf-compiler qttools5-dev qttools5-dev-tools software-properties-common
|
||||
- ./autogen.sh
|
||||
- CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined
|
||||
- make
|
||||
- git clone https://github.com/bitcoin-core/qa-assets
|
||||
auto_targets:
|
||||
find_targets_command: find src/test/fuzz/ -executable -type f ! -name "*.cpp" ! -name "*.h"
|
||||
base_corpus_dir: qa-assets/fuzz_seed_corpus/
|
||||
memory_limit: none
|
@ -41,7 +41,7 @@ OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus
|
||||
OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist
|
||||
OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/dash.icns
|
||||
OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed
|
||||
OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW
|
||||
OSX_QT_TRANSLATIONS = ar,bg,ca,cs,da,de,es,fa,fi,fr,gd,gl,he,hu,it,ja,ko,lt,lv,pl,pt,ru,sk,sl,sv,uk,zh_CN,zh_TW
|
||||
|
||||
DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)
|
||||
DIST_CONTRIB = $(top_srcdir)/contrib/dash-cli.bash-completion \
|
||||
|
@ -33,7 +33,7 @@
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 47
|
||||
#serial 48
|
||||
|
||||
# example boost program (need to pass version)
|
||||
m4_define([_AX_BOOST_BASE_PROGRAM],
|
||||
@ -123,6 +123,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
|
||||
dnl are almost assuredly the ones desired.
|
||||
AS_CASE([${host_cpu}],
|
||||
[i?86],[multiarch_libsubdir="lib/i386-${host_os}"],
|
||||
[armv7l],[multiarch_libsubdir="lib/arm-${host_os}"],
|
||||
[multiarch_libsubdir="lib/${host_cpu}-${host_os}"]
|
||||
)
|
||||
|
||||
|
@ -34,14 +34,14 @@ dnl faketime breaks configure and is only needed for make. Disable it here.
|
||||
unset FAKETIME
|
||||
|
||||
dnl Automake init set-up and checks
|
||||
AM_INIT_AUTOMAKE([no-define subdir-objects foreign])
|
||||
AM_INIT_AUTOMAKE([1.13 no-define subdir-objects foreign])
|
||||
|
||||
dnl faketime messes with timestamps and causes configure to be re-run.
|
||||
dnl --disable-maintainer-mode can be used to bypass this.
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
|
||||
dnl make the compilation flags quiet unless V=1 is used
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
dnl Compiler checks (here before libtool).
|
||||
if test "x${CXXFLAGS+set}" = "xset"; then
|
||||
@ -409,6 +409,7 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
|
||||
AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]])
|
||||
AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]])
|
||||
AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]])
|
||||
AX_CHECK_COMPILE_FLAG([-Wdeprecated-copy],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-deprecated-copy"],,[[$CXXFLAG_WERROR]])
|
||||
fi
|
||||
|
||||
enable_sse42=no
|
||||
@ -1425,9 +1426,6 @@ if test "x$use_ccache" != "xno"; then
|
||||
fi
|
||||
AC_MSG_RESULT($use_ccache)
|
||||
fi
|
||||
if test "x$use_ccache" = "xyes"; then
|
||||
AX_CHECK_PREPROC_FLAG([-Qunused-arguments],[CPPFLAGS="-Qunused-arguments $CPPFLAGS"])
|
||||
fi
|
||||
|
||||
dnl enable wallet
|
||||
AC_MSG_CHECKING([if wallet should be enabled])
|
||||
|
@ -10,6 +10,7 @@ $(package)_build_subdir=qtbase
|
||||
$(package)_qt_libs=corelib network widgets gui plugins testlib
|
||||
$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch xkb-default.patch no-xlib.patch
|
||||
|
||||
# Update OSX_QT_TRANSLATIONS when this is updated
|
||||
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
|
||||
$(package)_qttranslations_sha256_hash=9822084f8e2d2939ba39f4af4c0c2320e45d5996762a9423f833055607604ed8
|
||||
|
||||
|
@ -197,7 +197,7 @@ endif
|
||||
|
||||
%.cpp.test: %.cpp
|
||||
@echo Running tests: `cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $<
|
||||
$(AM_V_at)$(TEST_BINARY) -l test_suite -t "`cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" > $<.log 2>&1 || (cat $<.log && false)
|
||||
$(AM_V_at)$(TEST_BINARY) --catch_system_errors=no -l test_suite -t "`cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" > $<.log 2>&1 || (cat $<.log && false)
|
||||
|
||||
test/data/%.json.h: test/data/%.json
|
||||
@$(MKDIR_P) $(@D)
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
assert(!IsSpent());
|
||||
uint32_t code = nHeight * 2 + fCoinBase;
|
||||
uint32_t code = nHeight * uint32_t{2} + fCoinBase;
|
||||
::Serialize(s, VARINT(code));
|
||||
::Serialize(s, Using<TxOutCompression>(out));
|
||||
}
|
||||
|
37
src/fs.cpp
37
src/fs.cpp
@ -2,6 +2,9 @@
|
||||
|
||||
#ifndef WIN32
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <sys/file.h>
|
||||
#include <sys/utsname.h>
|
||||
#else
|
||||
#include <codecvt>
|
||||
#include <windows.h>
|
||||
@ -40,20 +43,38 @@ FileLock::~FileLock()
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsWSL()
|
||||
{
|
||||
struct utsname uname_data;
|
||||
return uname(&uname_data) == 0 && std::string(uname_data.version).find("Microsoft") != std::string::npos;
|
||||
}
|
||||
|
||||
bool FileLock::TryLock()
|
||||
{
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_SETLK, &lock) == -1) {
|
||||
reason = GetErrorReason();
|
||||
return false;
|
||||
|
||||
// Exclusive file locking is broken on WSL using fcntl (issue #18622)
|
||||
// This workaround can be removed once the bug on WSL is fixed
|
||||
static const bool is_wsl = IsWSL();
|
||||
if (is_wsl) {
|
||||
if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
|
||||
reason = GetErrorReason();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_SETLK, &lock) == -1) {
|
||||
reason = GetErrorReason();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
@ -218,7 +218,7 @@ static bool InitRPCAuthentication()
|
||||
{
|
||||
if (gArgs.GetArg("-rpcpassword", "") == "")
|
||||
{
|
||||
LogPrintf("No rpcpassword set - using random cookie authentication.\n");
|
||||
LogPrintf("Using random cookie authentication.\n");
|
||||
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
|
||||
uiInterface.ThreadSafeMessageBox(
|
||||
_("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
|
||||
|
@ -242,7 +242,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
|
||||
if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
|
||||
LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
|
||||
hreq->GetPeer().ToString());
|
||||
hreq->WriteReply(HTTP_BADMETHOD);
|
||||
hreq->WriteReply(HTTP_BAD_METHOD);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -274,10 +274,10 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
|
||||
item.release(); /* if true, queue took ownership */
|
||||
else {
|
||||
LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
|
||||
item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
|
||||
item->req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, "Work queue depth exceeded");
|
||||
}
|
||||
} else {
|
||||
hreq->WriteReply(HTTP_NOTFOUND);
|
||||
hreq->WriteReply(HTTP_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ HTTPRequest::~HTTPRequest()
|
||||
if (!replySent) {
|
||||
// Keep track of whether reply was sent to avoid request leaks
|
||||
LogPrintf("%s: Unhandled request\n", __func__);
|
||||
WriteReply(HTTP_INTERNAL, "Unhandled request");
|
||||
WriteReply(HTTP_INTERNAL_SERVER_ERROR, "Unhandled request");
|
||||
}
|
||||
// evhttpd cleans up the request, as long as a reply was sent.
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <tinyformat.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
std::string COutPoint::ToString() const
|
||||
{
|
||||
return strprintf("COutPoint(%s, %u)", hash.ToString()/*.substr(0,10)*/, n);
|
||||
@ -99,10 +101,11 @@ CAmount CTransaction::GetValueOut() const
|
||||
{
|
||||
CAmount nValueOut = 0;
|
||||
for (const auto& tx_out : vout) {
|
||||
nValueOut += tx_out.nValue;
|
||||
if (!MoneyRange(tx_out.nValue) || !MoneyRange(nValueOut))
|
||||
if (!MoneyRange(tx_out.nValue) || !MoneyRange(nValueOut + tx_out.nValue))
|
||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||
nValueOut += tx_out.nValue;
|
||||
}
|
||||
assert(MoneyRange(nValueOut));
|
||||
return nValueOut;
|
||||
}
|
||||
|
||||
|
@ -692,8 +692,7 @@ void CoinControlDialog::updateView()
|
||||
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
|
||||
|
||||
for (const auto& coins : model->wallet().listCoins()) {
|
||||
CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
|
||||
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
|
||||
CCoinControlWidgetItem* itemWalletAddress{nullptr};
|
||||
QString sWalletAddress = QString::fromStdString(EncodeDestination(coins.first));
|
||||
QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
|
||||
if (sWalletLabel.isEmpty())
|
||||
@ -702,7 +701,7 @@ void CoinControlDialog::updateView()
|
||||
if (treeMode)
|
||||
{
|
||||
// wallet address
|
||||
ui->treeWidget->addTopLevelItem(itemWalletAddress);
|
||||
itemWalletAddress = new CCoinControlWidgetItem(ui->treeWidget);
|
||||
|
||||
itemWalletAddress->setFlags(flgTristate);
|
||||
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
|
||||
|
@ -30,7 +30,6 @@ class CCoinControlWidgetItem : public QTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
explicit CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
|
||||
explicit CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
|
||||
explicit CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
|
||||
|
||||
bool operator<(const QTreeWidgetItem &other) const override;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QColor>
|
||||
#include <QTimer>
|
||||
|
||||
|
@ -683,7 +683,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
|
||||
return details;
|
||||
}
|
||||
case ConfirmedRole:
|
||||
return rec->status.countsForBalance;
|
||||
return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
|
||||
case FormattedAmountRole:
|
||||
// Used for copy/export, so don't include separators
|
||||
return formatTxAmount(rec, false, BitcoinUnits::separatorNever);
|
||||
|
@ -580,7 +580,7 @@ static bool rest_blockhash_by_height(HTTPRequest* req,
|
||||
std::string height_str;
|
||||
const RetFormat rf = ParseDataFormat(height_str, str_uri_part);
|
||||
|
||||
int32_t blockheight;
|
||||
int32_t blockheight = -1; // Initialization done only to prevent valgrind false positive, see https://github.com/bitcoin/bitcoin/pull/18785
|
||||
if (!ParseInt32(height_str, &blockheight) || blockheight < 0) {
|
||||
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid height: " + SanitizeString(height_str));
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ const char* ScriptErrorString(const ScriptError serror)
|
||||
case SCRIPT_ERR_MINIMALDATA:
|
||||
return "Data push larger than necessary";
|
||||
case SCRIPT_ERR_SIG_PUSHONLY:
|
||||
return "Only non-push operators allowed in signatures";
|
||||
return "Only push operators allowed in signatures";
|
||||
case SCRIPT_ERR_SIG_HIGH_S:
|
||||
return "Non-canonical signature: S value is unnecessarily high";
|
||||
case SCRIPT_ERR_SIG_NULLDUMMY:
|
||||
|
@ -45,8 +45,7 @@ extern unsigned nMaxDatacarrierBytes;
|
||||
/**
|
||||
* Mandatory script verification flags that all new blocks must comply with for
|
||||
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
|
||||
* but in the future other flags may be added, such as a soft-fork to enforce
|
||||
* strict DER encoding.
|
||||
* but in the future other flags may be added.
|
||||
*
|
||||
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
* details.
|
||||
|
@ -257,6 +257,11 @@ void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
|
||||
}
|
||||
if (addr) {
|
||||
*lockingSuccess = mlock(addr, len) == 0;
|
||||
#if defined(MADV_DONTDUMP) // Linux
|
||||
madvise(addr, len, MADV_DONTDUMP);
|
||||
#elif defined(MADV_NOCORE) // FreeBSD
|
||||
madvise(addr, len, MADV_NOCORE);
|
||||
#endif
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
@ -10,9 +10,9 @@
|
||||
#include <util/macros.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// //
|
||||
|
@ -4,9 +4,6 @@
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
|
||||
// It would probably be ideal to define dummy test(s) that report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros)
|
||||
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -18,6 +15,10 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)
|
||||
|
||||
#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
|
||||
|
||||
static std::map<void*, short> tags;
|
||||
static std::map<void*, uint16_t> orders;
|
||||
static uint16_t tagSequence = 0;
|
||||
@ -36,8 +37,6 @@ static void tag_free(void* mem) {
|
||||
free(mem);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(raii_event_creation)
|
||||
{
|
||||
event_set_mem_functions(tag_malloc, realloc, tag_free);
|
||||
@ -89,6 +88,14 @@ BOOST_AUTO_TEST_CASE(raii_event_order)
|
||||
event_set_mem_functions(malloc, realloc, free);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
#else
|
||||
|
||||
BOOST_AUTO_TEST_CASE(raii_event_tests_SKIPPED)
|
||||
{
|
||||
// It would probably be ideal to report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros)
|
||||
BOOST_TEST_MESSAGE("Skipping raii_event_tess: libevent doesn't support event_set_mem_functions");
|
||||
}
|
||||
|
||||
#endif // EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -112,6 +112,24 @@ BOOST_AUTO_TEST_CASE(manythreads)
|
||||
BOOST_CHECK_EQUAL(counterSum, 200);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(wait_until_past)
|
||||
{
|
||||
std::condition_variable condvar;
|
||||
Mutex mtx;
|
||||
WAIT_LOCK(mtx, lock);
|
||||
|
||||
const auto no_wait= [&](const std::chrono::seconds& d) {
|
||||
return condvar.wait_until(lock, std::chrono::system_clock::now() - d);
|
||||
};
|
||||
|
||||
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::seconds{1}));
|
||||
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::minutes{1}));
|
||||
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1}));
|
||||
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{10}));
|
||||
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{100}));
|
||||
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1000}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
|
||||
{
|
||||
CScheduler scheduler;
|
||||
|
@ -24,7 +24,7 @@ struct TxInUndoFormatter
|
||||
{
|
||||
template<typename Stream>
|
||||
void Ser(Stream &s, const Coin& txout) {
|
||||
::Serialize(s, VARINT(txout.nHeight * 2 + (txout.fCoinBase ? 1u : 0u)));
|
||||
::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase ));
|
||||
if (txout.nHeight > 0) {
|
||||
// Required to maintain compatibility with older undo format.
|
||||
::Serialize(s, (unsigned char)0);
|
||||
@ -34,9 +34,9 @@ struct TxInUndoFormatter
|
||||
|
||||
template<typename Stream>
|
||||
void Unser(Stream &s, Coin& txout) {
|
||||
unsigned int nCode = 0;
|
||||
uint32_t nCode = 0;
|
||||
::Unserialize(s, VARINT(nCode));
|
||||
txout.nHeight = nCode / 2;
|
||||
txout.nHeight = nCode >> 1;
|
||||
txout.fCoinBase = nCode & 1;
|
||||
if (txout.nHeight > 0) {
|
||||
// Old versions stored the version number for the last spend of
|
||||
|
@ -580,7 +580,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.move_tip(44)
|
||||
b47 = self.next_block(47, solve=False)
|
||||
target = uint256_from_compact(b47.nBits)
|
||||
while b47.sha256 < target:
|
||||
while b47.sha256 <= target:
|
||||
b47.nNonce += 1
|
||||
b47.rehash()
|
||||
self.send_blocks([b47], False, request_block=False)
|
||||
@ -1257,6 +1257,8 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
if solve:
|
||||
block.solve()
|
||||
else:
|
||||
block.rehash()
|
||||
self.tip = block
|
||||
self.block_heights[block.sha256] = height
|
||||
assert number not in self.blocks
|
||||
|
100
test/functional/mempool_expiry.py
Executable file
100
test/functional/mempool_expiry.py
Executable file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2020 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Tests that a mempool transaction expires after a given timeout and that its
|
||||
children are removed as well.
|
||||
|
||||
Both the default expiry timeout defined by DEFAULT_MEMPOOL_EXPIRY and a user
|
||||
definable expiry timeout via the '-mempoolexpiry=<n>' command line argument
|
||||
(<n> is the timeout in hours) are tested.
|
||||
"""
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_raises_rpc_error,
|
||||
find_vout_for_address,
|
||||
)
|
||||
|
||||
DEFAULT_MEMPOOL_EXPIRY = 336 # hours
|
||||
CUSTOM_MEMPOOL_EXPIRY = 10 # hours
|
||||
|
||||
|
||||
class MempoolExpiryTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def test_transaction_expiry(self, timeout):
|
||||
"""Tests that a transaction expires after the expiry timeout and its
|
||||
children are removed as well."""
|
||||
node = self.nodes[0]
|
||||
|
||||
# Send a parent transaction that will expire.
|
||||
parent_address = node.getnewaddress()
|
||||
parent_txid = node.sendtoaddress(parent_address, 1.0)
|
||||
|
||||
# Set the mocktime to the arrival time of the parent transaction.
|
||||
entry_time = node.getmempoolentry(parent_txid)['time']
|
||||
node.setmocktime(entry_time)
|
||||
|
||||
# Create child transaction spending the parent transaction
|
||||
vout = find_vout_for_address(node, parent_txid, parent_address)
|
||||
inputs = [{'txid': parent_txid, 'vout': vout}]
|
||||
outputs = {node.getnewaddress(): 0.99}
|
||||
child_raw = node.createrawtransaction(inputs, outputs)
|
||||
child_signed = node.signrawtransactionwithwallet(child_raw)['hex']
|
||||
|
||||
# Let half of the timeout elapse and broadcast the child transaction.
|
||||
half_expiry_time = entry_time + int(60 * 60 * timeout/2)
|
||||
node.setmocktime(half_expiry_time)
|
||||
child_txid = node.sendrawtransaction(child_signed)
|
||||
self.log.info('Broadcast child transaction after {} hours.'.format(
|
||||
timedelta(seconds=(half_expiry_time-entry_time))))
|
||||
|
||||
# Let most of the timeout elapse and check that the parent tx is still
|
||||
# in the mempool.
|
||||
nearly_expiry_time = entry_time + 60 * 60 * timeout - 5
|
||||
node.setmocktime(nearly_expiry_time)
|
||||
# Expiry of mempool transactions is only checked when a new transaction
|
||||
# is added to the to the mempool.
|
||||
node.sendtoaddress(node.getnewaddress(), 1.0)
|
||||
self.log.info('Test parent tx not expired after {} hours.'.format(
|
||||
timedelta(seconds=(nearly_expiry_time-entry_time))))
|
||||
assert_equal(entry_time, node.getmempoolentry(parent_txid)['time'])
|
||||
|
||||
# Transaction should be evicted from the mempool after the expiry time
|
||||
# has passed.
|
||||
expiry_time = entry_time + 60 * 60 * timeout + 5
|
||||
node.setmocktime(expiry_time)
|
||||
# Expiry of mempool transactions is only checked when a new transaction
|
||||
# is added to the to the mempool.
|
||||
node.sendtoaddress(node.getnewaddress(), 1.0)
|
||||
self.log.info('Test parent tx expiry after {} hours.'.format(
|
||||
timedelta(seconds=(expiry_time-entry_time))))
|
||||
assert_raises_rpc_error(-5, 'Transaction not in mempool',
|
||||
node.getmempoolentry, parent_txid)
|
||||
|
||||
# The child transaction should be removed from the mempool as well.
|
||||
self.log.info('Test child tx is evicted as well.')
|
||||
assert_raises_rpc_error(-5, 'Transaction not in mempool',
|
||||
node.getmempoolentry, child_txid)
|
||||
|
||||
def run_test(self):
|
||||
self.log.info('Test default mempool expiry timeout of %d hours.' %
|
||||
DEFAULT_MEMPOOL_EXPIRY)
|
||||
self.test_transaction_expiry(DEFAULT_MEMPOOL_EXPIRY)
|
||||
|
||||
self.log.info('Test custom mempool expiry timeout of %d hours.' %
|
||||
CUSTOM_MEMPOOL_EXPIRY)
|
||||
self.restart_node(0, ['-mempoolexpiry=%d' % CUSTOM_MEMPOOL_EXPIRY])
|
||||
self.test_transaction_expiry(CUSTOM_MEMPOOL_EXPIRY)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
MempoolExpiryTest().main()
|
@ -434,7 +434,11 @@ def connect_nodes(from_connection, node_num):
|
||||
from_connection.addnode(ip_port, "onetry")
|
||||
# poll until version handshake complete to avoid race conditions
|
||||
# with transaction relaying
|
||||
wait_until(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
|
||||
# See comments in net_processing:
|
||||
# * Must have a version message before anything else
|
||||
# * Must have a verack message before anything else
|
||||
wait_until(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
|
||||
wait_until(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()))
|
||||
|
||||
def connect_nodes_bi(nodes, a, b):
|
||||
connect_nodes(nodes[a], b)
|
||||
|
@ -156,6 +156,7 @@ BASE_SCRIPTS = [
|
||||
'rpc_signmessage.py',
|
||||
'feature_nulldummy.py',
|
||||
'mempool_accept.py',
|
||||
'mempool_expiry.py',
|
||||
'wallet_import_rescan.py',
|
||||
'rpc_bind.py --ipv4',
|
||||
'rpc_bind.py --ipv6',
|
||||
|
Loading…
Reference in New Issue
Block a user