21ad71c578 Merge #21676: test: Use mocktime to avoid intermittent failure in rpc_tests (MarcoFalke)
76a41eb245 Merge #21602: rpc: add additional ban time fields to listbanned (MarcoFalke)
adea52a5fe Merge bitcoin-core/gui#260: Handle exceptions instead of crash (W. J. van der Laan)
7e023c394f Merge #17934: doc: Use CONFIG_SITE variable instead of --prefix option (fanquake)
bc6e3ed6e4 Merge #21606: fuzz: Extend psbt fuzz target a bit (MarcoFalke)
233fb245f7 Merge #21445: cirrus: Use SSD cluster for speedup (fanquake)
a224b800e4 Merge #21609: ci: increase CPU count of sanitizer job to increase memory limit (MarcoFalke)
ad947099a0 test: remove exception for util::Ref which doesn't exist more (Konstantin Akimov)
6674ee85ab Merge #21390: test: Test improvements for UTXO set hash tests (MarcoFalke)
e10eec249b Merge #21338: test: add functional test for anchors.dat (MarcoFalke)
d9c31d6817 Merge #21411: test: add logging, reduce blocks, move sync_all in wallet_ groups (MarcoFalke)

Pull request description:

  ## Issue being fixed or feature implemented
  Regular backports from bitcoin v22

  ## Note for reviewers:
  PRs bitcoin#17934 and bitcoin#21606 have been backported partially in past.

  ## What was done?
  Removed unused sanitizer rules (see bitcoin#21366 and dashpay/dash#5055)
   - bitcoin/bitcoin#21338
   - bitcoin/bitcoin#21390
   - bitcoin/bitcoin#21609
   - bitcoin/bitcoin#21445
   - bitcoin/bitcoin#21606
   - bitcoin/bitcoin#17934
   - bitcoin-core/gui#260
   - bitcoin/bitcoin#21602
   - bitcoin/bitcoin#21676

  ## How Has This Been Tested?
  Run unit/functional tests

  ## Breaking Changes
  N/A

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone

ACKs for top commit:
  PastaPastaPasta:
    utACK 21ad71c578

Tree-SHA512: 94276d56255300d7d8c056d15b468720ba028d83cc585b16396e8bad90157e9e010490be239e09cccd4362f575f8df2d56dde3fb505745376c7790d70e3635cd
This commit is contained in:
pasta 2024-04-12 10:30:20 -05:00
commit 7aa8f54c0f
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
29 changed files with 259 additions and 60 deletions

View File

@ -29,7 +29,6 @@ global_task_template: &GLOBAL_TASK_TEMPLATE
# Each project has 16 CPU in total, assign 2 to each container, so that 8 tasks run in parallel
cpu: 2
memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-containers
kvm: true # Use kvm to avoid spurious CI failures in the default virtualization cluster, see https://github.com/bitcoin/bitcoin/issues/20093
ccache_cache:
folder: "/tmp/ccache_dir"
depends_built_cache:
@ -102,7 +101,7 @@ task:
<< : *GLOBAL_TASK_TEMPLATE
container:
image: ubuntu:lunar
cpu: 4 # Double CPU and increase Memory to avoid timeout
cpu: 6 # Increase CPU and Memory to avoid timeout
memory: 24G
env:
MAKEJOBS: "-j8"

View File

@ -24,7 +24,7 @@ The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [lib
```
cd <DASH_SOURCE_DIRECTORY>
make -C depends NO_QT=1 MULTIPROCESS=1
./configure --prefix=$PWD/depends/x86_64-pc-linux-gnu
CONFIG_SITE=$PWD/depends/x86_64-pc-linux-gnu/share/config.site ./configure
make
src/dash-node -regtest -printtoconsole -debug=ipc
DASHD=dash-node test/functional/test_runner.py

View File

@ -0,0 +1,7 @@
Updated RPCs
------------
- The `listbanned` RPC now returns two new numeric fields: `ban_duration` and `time_remaining`.
Respectively, these new fields indicate the duration of a ban and the time remaining until a ban expires,
both in seconds. Additionally, the `ban_created` field is repositioned to come before `banned_until`. (#5976)

View File

@ -18,6 +18,7 @@
#include <map>
// Database-independent metric indicating the UTXO set size
uint64_t GetBogoSize(const CScript& script_pub_key)
{
return 32 /* txid */ +

View File

@ -47,11 +47,13 @@
#include <QApplication>
#include <QDebug>
#include <QLatin1String>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#include <QProcess>
#include <QSettings>
#include <QStringBuilder>
#include <QThread>
#include <QTimer>
#include <QTranslator>
@ -491,10 +493,23 @@ void BitcoinApplication::shutdownResult()
void BitcoinApplication::handleRunawayException(const QString &message)
{
QMessageBox::critical(nullptr, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) + QString("<br><br>") + message);
QMessageBox::critical(
nullptr, tr("Runaway exception"),
tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) %
QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT));
::exit(EXIT_FAILURE);
}
void BitcoinApplication::handleNonFatalException(const QString& message)
{
assert(QThread::currentThread() == thread());
QMessageBox::warning(
nullptr, tr("Internal error"),
tr("An internal error occurred. %1 will attempt to continue safely. This is "
"an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) %
QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT));
}
WId BitcoinApplication::getMainWinId() const
{
if (!window)

View File

@ -96,6 +96,12 @@ public Q_SLOTS:
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
void handleRunawayException(const QString &message);
/**
* A helper function that shows a message box
* with details about a non-fatal exception.
*/
void handleNonFatalException(const QString& message);
Q_SIGNALS:
void requestedInitialize();
void requestedRestart(QStringList args);

View File

@ -891,7 +891,7 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
m_open_wallet_action->setEnabled(true);
m_open_wallet_action->setMenu(m_open_wallet_menu);
connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) {

View File

@ -52,6 +52,7 @@
#include <QGuiApplication>
#include <QJsonObject>
#include <QKeyEvent>
#include <QLatin1String>
#include <QLineEdit>
#include <QList>
#include <QLocale>
@ -65,6 +66,7 @@
#include <QShortcut>
#include <QSize>
#include <QString>
#include <QStringBuilder>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
#include <QTimer>
@ -1874,4 +1876,22 @@ QImage GetImage(const QLabel* label)
#endif
}
QString MakeHtmlLink(const QString& source, const QString& link)
{
return QString(source).replace(
link,
QLatin1String("<a href=\"") % link % QLatin1String("\">") % link % QLatin1String("</a>"));
}
void PrintSlotException(
const std::exception* exception,
const QObject* sender,
const QObject* receiver)
{
std::string description = sender->metaObject()->className();
description += "->";
description += receiver->metaObject()->className();
PrintExceptionContinue(std::make_exception_ptr(exception), description.c_str());
}
} // namespace GUIUtil

View File

@ -9,18 +9,23 @@
#include <fs.h>
#include <qt/guiconstants.h>
#include <netaddress.h>
#include <util/check.h>
#include <QApplication>
#include <QEvent>
#include <QHeaderView>
#include <QItemDelegate>
#include <QMessageBox>
#include <QMetaObject>
#include <QObject>
#include <QProgressBar>
#include <QString>
#include <QTableView>
#include <QLabel>
#include <cassert>
#include <chrono>
#include <utility>
class QValidatedLineEdit;
class OptionsModel;
@ -520,6 +525,58 @@ namespace GUIUtil
QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection);
}
/**
* Replaces a plain text link with an HTML tagged one.
*/
QString MakeHtmlLink(const QString& source, const QString& link);
void PrintSlotException(
const std::exception* exception,
const QObject* sender,
const QObject* receiver);
/**
* A drop-in replacement of QObject::connect function
* (see: https://doc.qt.io/qt-5/qobject.html#connect-3), that
* guaranties that all exceptions are handled within the slot.
*
* NOTE: This function is incompatible with Qt private signals.
*/
template <typename Sender, typename Signal, typename Receiver, typename Slot>
auto ExceptionSafeConnect(
Sender sender, Signal signal, Receiver receiver, Slot method,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(
sender, signal, receiver,
[sender, receiver, method](auto&&... args) {
bool ok{true};
try {
(receiver->*method)(std::forward<decltype(args)>(args)...);
} catch (const NonFatalCheckError& e) {
PrintSlotException(&e, sender, receiver);
ok = QMetaObject::invokeMethod(
qApp, "handleNonFatalException",
blockingGUIThreadConnection(),
Q_ARG(QString, QString::fromStdString(e.what())));
} catch (const std::exception& e) {
PrintSlotException(&e, sender, receiver);
ok = QMetaObject::invokeMethod(
qApp, "handleRunawayException",
blockingGUIThreadConnection(),
Q_ARG(QString, QString::fromStdString(e.what())));
} catch (...) {
PrintSlotException(nullptr, sender, receiver);
ok = QMetaObject::invokeMethod(
qApp, "handleRunawayException",
blockingGUIThreadConnection(),
Q_ARG(QString, "Unknown failure occurred."));
}
assert(ok);
},
type);
}
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H

View File

@ -153,6 +153,8 @@ SendCoinsDialog::SendCoinsDialog(bool _fCoinJoin, QWidget* parent) :
}
m_coin_control->UseCoinJoin(_fCoinJoin);
GUIUtil::ExceptionSafeConnect(ui->sendButton, &QPushButton::clicked, this, &SendCoinsDialog::sendButtonClicked);
}
void SendCoinsDialog::setClientModel(ClientModel *_clientModel)
@ -459,7 +461,7 @@ bool SendCoinsDialog::send(const QList<SendCoinsRecipient>& recipients, QString&
return true;
}
void SendCoinsDialog::on_sendButton_clicked()
void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
{
if(!model || !model->getOptionsModel())
return;

View File

@ -83,7 +83,7 @@ private:
void updateCoinControlState(CCoinControl& ctrl);
private Q_SLOTS:
void on_sendButton_clicked();
void sendButtonClicked(bool checked);
void on_buttonChooseFee_clicked();
void on_buttonMinimizeFee_clicked();
void removeEntry(SendCoinsEntry* entry);

View File

@ -68,7 +68,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
if (status == CT_NEW) txid = hash;
}));
ConfirmSend();
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
assert(invoked);
return txid;
}

View File

@ -12,6 +12,7 @@
#include <qt/addresstablemodel.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/paymentserver.h>
#include <qt/recentrequeststablemodel.h>
@ -68,7 +69,10 @@ WalletModel::~WalletModel()
void WalletModel::startPollBalance()
{
// This timer will be fired repeatedly to update the balance
connect(timer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged);
// Since the QTimer::timeout is a private signal, it cannot be used
// in the GUIUtil::ExceptionSafeConnect directly.
connect(timer, &QTimer::timeout, this, &WalletModel::timerTimeout);
GUIUtil::ExceptionSafeConnect(this, &WalletModel::timerTimeout, this, &WalletModel::pollBalanceChanged);
timer->start(MODEL_UPDATE_DELAY);
}

View File

@ -233,6 +233,8 @@ Q_SIGNALS:
// Notify that there are now keys in the keypool
void canGetAddressesChanged();
void timerTimeout();
public Q_SLOTS:
/* Starts a timer to periodically update the balance */
void startPollBalance();

View File

@ -1366,15 +1366,15 @@ static RPCHelpMan gettxoutsetinfo()
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "height", "The current block height (index)"},
{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
{RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
{RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
{RPCResult::Type::STR_HEX, "hash_serialized_2", /* optional */ true, "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
{RPCResult::Type::STR_HEX, "muhash", /* optional */ true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
{RPCResult::Type::NUM, "transactions", "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
{RPCResult::Type::NUM, "disk_size", "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount"},
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
{RPCResult::Type::STR_AMOUNT, "total_unspendable_amount", "The total amount of coins permanently excluded from the UTXO set (only available if coinstatsindex is used)"},
{RPCResult::Type::OBJ, "block_info", "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
{

View File

@ -789,9 +789,11 @@ static RPCHelpMan listbanned()
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "address", ""},
{RPCResult::Type::NUM_TIME, "banned_until", ""},
{RPCResult::Type::NUM_TIME, "ban_created", ""},
{RPCResult::Type::STR, "address", "The IP/Subnet of the banned node"},
{RPCResult::Type::NUM_TIME, "ban_created", "The " + UNIX_EPOCH_TIME + " the ban was created"},
{RPCResult::Type::NUM_TIME, "banned_until", "The " + UNIX_EPOCH_TIME + " the ban expires"},
{RPCResult::Type::NUM_TIME, "ban_duration", "The ban duration, in seconds"},
{RPCResult::Type::NUM_TIME, "time_remaining", "The time remaining until the ban expires, in seconds"},
}},
}},
RPCExamples{
@ -808,6 +810,7 @@ static RPCHelpMan listbanned()
banmap_t banMap;
node.banman->GetBanned(banMap);
const int64_t current_time{GetTime()};
UniValue bannedAddresses(UniValue::VARR);
for (const auto& entry : banMap)
@ -815,8 +818,10 @@ static RPCHelpMan listbanned()
const CBanEntry& banEntry = entry.second;
UniValue rec(UniValue::VOBJ);
rec.pushKV("address", entry.first.ToString());
rec.pushKV("banned_until", banEntry.nBanUntil);
rec.pushKV("ban_created", banEntry.nCreateTime);
rec.pushKV("banned_until", banEntry.nBanUntil);
rec.pushKV("ban_duration", (banEntry.nBanUntil - banEntry.nCreateTime));
rec.pushKV("time_remaining", (banEntry.nBanUntil - current_time));
bannedAddresses.push_back(rec);
}

View File

@ -114,7 +114,6 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect
}
BOOST_CHECK(dummyNode1.fDisconnect == true);
SetMockTime(0);
peerLogic->FinalizeNode(dummyNode1);
}

View File

@ -46,6 +46,7 @@ FUZZ_TARGET(psbt)
(void)PSBTInputSigned(input);
(void)input.IsNull();
}
(void)CountPSBTUnsignedInputs(psbt);
for (const PSBTOutput& output : psbt.outputs) {
(void)output.IsNull();

View File

@ -14,7 +14,6 @@ BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(logging_timer)
{
SetMockTime(1);
auto sec_timer = BCLog::Timer<std::chrono::seconds>("tests", "end_msg");
SetMockTime(2);
@ -29,8 +28,6 @@ BOOST_AUTO_TEST_CASE(logging_timer)
auto micro_timer = BCLog::Timer<std::chrono::microseconds>("tests", "end_msg");
SetMockTime(2);
BOOST_CHECK_EQUAL(micro_timer.LogMsg("test micros"), "tests: test micros (1000000μs)");
SetMockTime(0);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -571,8 +571,6 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
// ... unless it has gone all the way to 0 (after getting past 1000/2)
SetMockTime(0);
}
inline CTransactionRef make_tx(std::vector<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>())

View File

@ -317,22 +317,29 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
UniValue banned_until = find_value(o1, "banned_until");
int64_t banned_until{find_value(o1, "banned_until").get_int64()};
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
BOOST_CHECK_EQUAL(banned_until.get_int64(), 9907731200); // absolute time check
BOOST_CHECK_EQUAL(banned_until, 9907731200); // absolute time check
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
auto now = 10'000s;
SetMockTime(now);
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 200")));
SetMockTime(now += 2s);
const int64_t time_remaining_expected{198};
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
banned_until = find_value(o1, "banned_until");
banned_until = find_value(o1, "banned_until").get_int64();
const int64_t ban_created{find_value(o1, "ban_created").get_int64()};
const int64_t ban_duration{find_value(o1, "ban_duration").get_int64()};
const int64_t time_remaining{find_value(o1, "time_remaining").get_int64()};
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
int64_t now = GetTime();
BOOST_CHECK(banned_until.get_int64() > now);
BOOST_CHECK(banned_until.get_int64()-now <= 200);
BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count());
BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created);
BOOST_CHECK_EQUAL(time_remaining, time_remaining_expected);
// must throw an exception because 127.0.0.1 is in already banned subnet range
BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error);

View File

@ -196,6 +196,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
BasicTestingSetup::~BasicTestingSetup()
{
SetMockTime(0s); // Reset mocktime for following tests
connman.reset();
llmq::quorumSnapshotManager.reset();
m_node.cpoolman.reset();
@ -500,7 +501,6 @@ TestChainSetup::~TestChainSetup()
g_txindex->Stop();
SyncWithValidationInterfaceQueue();
g_txindex.reset();
SetMockTime(0);
}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const

View File

@ -315,8 +315,6 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
BOOST_CHECK_EQUAL(found, expected);
}
}
SetMockTime(0);
}
// Verify getaddressinfo RPC produces more or less expected results
@ -473,9 +471,6 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
// If there are future entries, new transaction should use time of the
// newest entry that is no more than 300 seconds ahead of the clock time.
BOOST_CHECK_EQUAL(AddTx(*m_node.chainman, m_wallet, 5, 50, 600), 300);
// Reset mock time for other tests.
SetMockTime(0);
}
BOOST_AUTO_TEST_CASE(LoadReceiveRequests)

View File

@ -0,0 +1,85 @@
#!/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.
"""Test Anchors functionality"""
import os
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
def check_node_connections(*, node, num_in, num_out):
info = node.getnetworkinfo()
assert_equal(info["connections_in"], num_in)
assert_equal(info["connections_out"], num_out)
class AnchorsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
def setup_network(self):
self.setup_nodes()
def run_test(self):
self.log.info("Add 2 block-relay-only connections to node 0")
for i in range(2):
self.log.debug(f"block-relay-only: {i}")
self.nodes[0].add_outbound_p2p_connection(
P2PInterface(), p2p_idx=i, connection_type="block-relay-only"
)
self.log.info("Add 5 inbound connections to node 0")
for i in range(5):
self.log.debug(f"inbound: {i}")
self.nodes[0].add_p2p_connection(P2PInterface())
self.log.info("Check node 0 connections")
check_node_connections(node=self.nodes[0], num_in=5, num_out=2)
# 127.0.0.1
ip = "7f000001"
# Since the ip is always 127.0.0.1 for this case,
# we store only the port to identify the peers
block_relay_nodes_port = []
inbound_nodes_port = []
for p in self.nodes[0].getpeerinfo():
addr_split = p["addr"].split(":")
if p["connection_type"] == "block-relay-only":
block_relay_nodes_port.append(hex(int(addr_split[1]))[2:])
else:
inbound_nodes_port.append(hex(int(addr_split[1]))[2:])
self.log.info("Stop node 0")
self.stop_node(0)
node0_anchors_path = os.path.join(
self.nodes[0].datadir, "regtest", "anchors.dat"
)
# It should contain only the block-relay-only addresses
self.log.info("Check the addresses in anchors.dat")
with open(node0_anchors_path, "rb") as file_handler:
anchors = file_handler.read().hex()
for port in block_relay_nodes_port:
ip_port = ip + port
assert ip_port in anchors
for port in inbound_nodes_port:
ip_port = ip + port
assert ip_port not in anchors
self.log.info("Start node 0")
self.start_node(0)
self.log.info("When node starts, check if anchors.dat doesn't exist anymore")
assert not os.path.exists(node0_anchors_path)
if __name__ == "__main__":
AnchorsTest().main()

View File

@ -6,7 +6,6 @@
import struct
from test_framework.blocktools import create_transaction
from test_framework.messages import (
CBlock,
COutPoint,
@ -15,38 +14,30 @@ from test_framework.messages import (
from test_framework.crypto.muhash import MuHash3072
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.wallet import MiniWallet
class UTXOSetHashTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def test_deterministic_hash_results(self):
self.log.info("Test deterministic UTXO set hash results")
# These depend on the setup_clean_chain option, the chain loaded from the cache
assert_equal(self.nodes[0].gettxoutsetinfo()['hash_serialized_2'], "b61ee2cb582d2f4f94493f3d480e9a59d064706e98a12be0f335a3eeadd5678a")
assert_equal(self.nodes[0].gettxoutsetinfo("muhash")['muhash'], "dd5ad2a105c2d29495f577245c357409002329b9f4d6182c0af3dc2f462555c8")
def test_muhash_implementation(self):
self.log.info("Test MuHash implementation consistency")
node = self.nodes[0]
wallet = MiniWallet(node)
mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1
node.setmocktime(mocktime)
# Generate 100 blocks and remove the first since we plan to spend its
# coinbase
block_hashes = node.generate(100)
block_hashes = wallet.generate(1) + node.generate(99)
blocks = list(map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes))
spending = blocks.pop(0)
blocks.pop(0)
# Create a spending transaction and mine a block which includes it
tx = create_transaction(node, spending.vtx[0].rehash(), node.getnewaddress(), amount=49)
txid = node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
tx_block = node.generateblock(node.getnewaddress(), [txid])['hash']
txid = wallet.send_self_transfer(from_node=node)['txid']
tx_block = node.generateblock(output=wallet.get_address(), transactions=[txid])['hash']
blocks.append(from_hex(CBlock(), node.getblock(tx_block, False)))
# Serialize the outputs that should be in the UTXO set and add them to
@ -77,8 +68,11 @@ class UTXOSetHashTest(BitcoinTestFramework):
assert_equal(finalized[::-1].hex(), node_muhash)
self.log.info("Test deterministic UTXO set hash results")
assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "4eb23b9673b7472e33ebf6e6aefee849fe5bc5e598fd387c2f9222070cc2f711")
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "dd74d7f1fb047577915d490e82d063e843f7853ae7543c9980a28c67326e1a2c")
def run_test(self):
self.test_deterministic_hash_results()
self.test_muhash_implementation()

View File

@ -39,6 +39,9 @@ class MiniWallet:
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
return blocks
def get_address(self):
return self._address
def get_utxo(self, *, txid=''):
"""
Returns a utxo and marks it as spent (pops it from the internal list)

View File

@ -318,6 +318,7 @@ BASE_SCRIPTS = [
'p2p_ping.py',
'rpc_scantxoutset.py',
'feature_logging.py',
'feature_anchors.py',
'feature_coinstatsindex.py',
'wallet_orphanedreward.py',
'p2p_node_network_limited.py',

View File

@ -32,8 +32,9 @@ class WalletGroupTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def run_test(self):
self.log.info("Setting up")
# Mine some coins
self.nodes[0].generate(COINBASE_MATURITY + 10)
self.nodes[0].generate(COINBASE_MATURITY + 1)
# Get some addresses from the two nodes
addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
@ -51,6 +52,7 @@ class WalletGroupTest(BitcoinTestFramework):
# - node[1] should pick one 0.5 UTXO and leave the rest
# - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
# given address, and leave the rest
self.log.info("Test sending transactions picks one UTXO group and leaves the rest")
txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
tx1 = self.nodes[1].getrawtransaction(txid1, True)
# txid1 should have 1 input and 2 outputs
@ -73,7 +75,7 @@ class WalletGroupTest(BitcoinTestFramework):
assert_approx(v[0], vexp=0.2, vspan=0.0001)
assert_approx(v[1], vexp=1.3, vspan=0.0001)
# Test 'avoid partial if warranted, even if disabled'
self.log.info("Test avoiding partial spends if warranted, even if avoidpartialspends is disabled")
self.sync_all()
self.nodes[0].generate(1)
# Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
@ -107,7 +109,7 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(input_addrs[0], input_addrs[1])
# Node 2 enforces avoidpartialspends so needs no checking here
# Test wallet option maxapsfee with Node 3
self.log.info("Test wallet option maxapsfee")
addr_aps = self.nodes[3].getnewaddress()
self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.nodes[0].sendtoaddress(addr_aps, 1.0)
@ -134,6 +136,7 @@ class WalletGroupTest(BitcoinTestFramework):
# Test wallet option maxapsfee with node 4, which sets maxapsfee
# 1 sat higher, crossing the threshold from non-grouped to grouped.
self.log.info("Test wallet option maxapsfee threshold from non-grouped to grouped")
addr_aps3 = self.nodes[4].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
self.nodes[0].generate(1)
@ -150,8 +153,7 @@ class WalletGroupTest(BitcoinTestFramework):
self.sync_all()
self.nodes[0].generate(1)
# Fill node2's wallet with 10000 outputs corresponding to the same
# scriptPubKey
self.log.info("Fill a wallet with 10,000 outputs corresponding to the same scriptPubKey")
for _ in range(5):
raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
tx = tx_from_hex(raw_tx)
@ -161,12 +163,12 @@ class WalletGroupTest(BitcoinTestFramework):
signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
self.nodes[0].sendrawtransaction(signed_tx['hex'])
self.nodes[0].generate(1)
self.sync_all()
self.sync_all()
# Check that we can create a transaction that only requires ~100 of our
# utxos, without pulling in all outputs and creating a transaction that
# is way too big.
self.log.info("Test creating txn that only requires ~100 of our UTXOs without pulling in all outputs")
assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)

View File

@ -55,7 +55,6 @@ IGNORED_WARNINGS=(
"src/test/checkqueue_tests.cpp:.* Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit."
"src/test/fuzz/util.h:.* Class 'FuzzedFileProvider' has a constructor with 1 argument that is not explicit."
"src/test/fuzz/util.h:.* Class 'FuzzedAutoFileProvider' has a constructor with 1 argument that is not explicit."
"src/util/ref.h:.* Class 'Ref' has a constructor with 1 argument that is not explicit."
"src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit."
)