mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 11:32:46 +01:00
Merge #5976: backport: bitcoin#17934, #21338, #21390, #21445, #21602, #21606, #21609, #21676, bitcoin-core/gui#260,
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: utACK21ad71c578
Tree-SHA512: 94276d56255300d7d8c056d15b468720ba028d83cc585b16396e8bad90157e9e010490be239e09cccd4362f575f8df2d56dde3fb505745376c7790d70e3635cd
This commit is contained in:
commit
7aa8f54c0f
@ -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
|
# Each project has 16 CPU in total, assign 2 to each container, so that 8 tasks run in parallel
|
||||||
cpu: 2
|
cpu: 2
|
||||||
memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-containers
|
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:
|
ccache_cache:
|
||||||
folder: "/tmp/ccache_dir"
|
folder: "/tmp/ccache_dir"
|
||||||
depends_built_cache:
|
depends_built_cache:
|
||||||
@ -102,7 +101,7 @@ task:
|
|||||||
<< : *GLOBAL_TASK_TEMPLATE
|
<< : *GLOBAL_TASK_TEMPLATE
|
||||||
container:
|
container:
|
||||||
image: ubuntu:lunar
|
image: ubuntu:lunar
|
||||||
cpu: 4 # Double CPU and increase Memory to avoid timeout
|
cpu: 6 # Increase CPU and Memory to avoid timeout
|
||||||
memory: 24G
|
memory: 24G
|
||||||
env:
|
env:
|
||||||
MAKEJOBS: "-j8"
|
MAKEJOBS: "-j8"
|
||||||
|
@ -24,7 +24,7 @@ The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [lib
|
|||||||
```
|
```
|
||||||
cd <DASH_SOURCE_DIRECTORY>
|
cd <DASH_SOURCE_DIRECTORY>
|
||||||
make -C depends NO_QT=1 MULTIPROCESS=1
|
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
|
make
|
||||||
src/dash-node -regtest -printtoconsole -debug=ipc
|
src/dash-node -regtest -printtoconsole -debug=ipc
|
||||||
DASHD=dash-node test/functional/test_runner.py
|
DASHD=dash-node test/functional/test_runner.py
|
||||||
|
7
doc/release-notes-21602.md
Normal file
7
doc/release-notes-21602.md
Normal 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)
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
// Database-independent metric indicating the UTXO set size
|
||||||
uint64_t GetBogoSize(const CScript& script_pub_key)
|
uint64_t GetBogoSize(const CScript& script_pub_key)
|
||||||
{
|
{
|
||||||
return 32 /* txid */ +
|
return 32 /* txid */ +
|
||||||
|
@ -47,11 +47,13 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QLatin1String>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QStringBuilder>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
@ -491,10 +493,23 @@ void BitcoinApplication::shutdownResult()
|
|||||||
|
|
||||||
void BitcoinApplication::handleRunawayException(const QString &message)
|
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);
|
::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
|
WId BitcoinApplication::getMainWinId() const
|
||||||
{
|
{
|
||||||
if (!window)
|
if (!window)
|
||||||
|
@ -96,6 +96,12 @@ public Q_SLOTS:
|
|||||||
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
|
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
|
||||||
void handleRunawayException(const QString &message);
|
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:
|
Q_SIGNALS:
|
||||||
void requestedInitialize();
|
void requestedInitialize();
|
||||||
void requestedRestart(QStringList args);
|
void requestedRestart(QStringList args);
|
||||||
|
@ -891,7 +891,7 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
|
|||||||
m_open_wallet_action->setEnabled(true);
|
m_open_wallet_action->setEnabled(true);
|
||||||
m_open_wallet_action->setMenu(m_open_wallet_menu);
|
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);
|
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
|
||||||
|
|
||||||
for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) {
|
for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) {
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include <QLatin1String>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
@ -65,6 +66,7 @@
|
|||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QStringBuilder>
|
||||||
#include <QTextDocument> // for Qt::mightBeRichText
|
#include <QTextDocument> // for Qt::mightBeRichText
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@ -1874,4 +1876,22 @@ QImage GetImage(const QLabel* label)
|
|||||||
#endif
|
#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
|
} // namespace GUIUtil
|
||||||
|
@ -9,18 +9,23 @@
|
|||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <qt/guiconstants.h>
|
#include <qt/guiconstants.h>
|
||||||
#include <netaddress.h>
|
#include <netaddress.h>
|
||||||
|
#include <util/check.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QItemDelegate>
|
#include <QItemDelegate>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QMetaObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class QValidatedLineEdit;
|
class QValidatedLineEdit;
|
||||||
class OptionsModel;
|
class OptionsModel;
|
||||||
@ -520,6 +525,58 @@ namespace GUIUtil
|
|||||||
QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection);
|
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
|
} // namespace GUIUtil
|
||||||
|
|
||||||
#endif // BITCOIN_QT_GUIUTIL_H
|
#endif // BITCOIN_QT_GUIUTIL_H
|
||||||
|
@ -153,6 +153,8 @@ SendCoinsDialog::SendCoinsDialog(bool _fCoinJoin, QWidget* parent) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_coin_control->UseCoinJoin(_fCoinJoin);
|
m_coin_control->UseCoinJoin(_fCoinJoin);
|
||||||
|
|
||||||
|
GUIUtil::ExceptionSafeConnect(ui->sendButton, &QPushButton::clicked, this, &SendCoinsDialog::sendButtonClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCoinsDialog::setClientModel(ClientModel *_clientModel)
|
void SendCoinsDialog::setClientModel(ClientModel *_clientModel)
|
||||||
@ -459,7 +461,7 @@ bool SendCoinsDialog::send(const QList<SendCoinsRecipient>& recipients, QString&
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCoinsDialog::on_sendButton_clicked()
|
void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
|
||||||
{
|
{
|
||||||
if(!model || !model->getOptionsModel())
|
if(!model || !model->getOptionsModel())
|
||||||
return;
|
return;
|
||||||
|
@ -83,7 +83,7 @@ private:
|
|||||||
void updateCoinControlState(CCoinControl& ctrl);
|
void updateCoinControlState(CCoinControl& ctrl);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void on_sendButton_clicked();
|
void sendButtonClicked(bool checked);
|
||||||
void on_buttonChooseFee_clicked();
|
void on_buttonChooseFee_clicked();
|
||||||
void on_buttonMinimizeFee_clicked();
|
void on_buttonMinimizeFee_clicked();
|
||||||
void removeEntry(SendCoinsEntry* entry);
|
void removeEntry(SendCoinsEntry* entry);
|
||||||
|
@ -68,7 +68,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
|
|||||||
if (status == CT_NEW) txid = hash;
|
if (status == CT_NEW) txid = hash;
|
||||||
}));
|
}));
|
||||||
ConfirmSend();
|
ConfirmSend();
|
||||||
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
|
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
|
||||||
assert(invoked);
|
assert(invoked);
|
||||||
return txid;
|
return txid;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <qt/addresstablemodel.h>
|
#include <qt/addresstablemodel.h>
|
||||||
#include <qt/clientmodel.h>
|
#include <qt/clientmodel.h>
|
||||||
#include <qt/guiconstants.h>
|
#include <qt/guiconstants.h>
|
||||||
|
#include <qt/guiutil.h>
|
||||||
#include <qt/optionsmodel.h>
|
#include <qt/optionsmodel.h>
|
||||||
#include <qt/paymentserver.h>
|
#include <qt/paymentserver.h>
|
||||||
#include <qt/recentrequeststablemodel.h>
|
#include <qt/recentrequeststablemodel.h>
|
||||||
@ -68,7 +69,10 @@ WalletModel::~WalletModel()
|
|||||||
void WalletModel::startPollBalance()
|
void WalletModel::startPollBalance()
|
||||||
{
|
{
|
||||||
// This timer will be fired repeatedly to update the balance
|
// 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);
|
timer->start(MODEL_UPDATE_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +233,8 @@ Q_SIGNALS:
|
|||||||
// Notify that there are now keys in the keypool
|
// Notify that there are now keys in the keypool
|
||||||
void canGetAddressesChanged();
|
void canGetAddressesChanged();
|
||||||
|
|
||||||
|
void timerTimeout();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/* Starts a timer to periodically update the balance */
|
/* Starts a timer to periodically update the balance */
|
||||||
void startPollBalance();
|
void startPollBalance();
|
||||||
|
@ -1366,15 +1366,15 @@ static RPCHelpMan gettxoutsetinfo()
|
|||||||
RPCResult{
|
RPCResult{
|
||||||
RPCResult::Type::OBJ, "", "",
|
RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::NUM, "height", "The current block height (index)"},
|
{RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
|
||||||
{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
|
{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, "txouts", "The number of unspent transaction outputs"},
|
||||||
{RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
|
{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, "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::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, "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::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::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)",
|
{RPCResult::Type::OBJ, "block_info", "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
|
||||||
{
|
{
|
||||||
|
@ -789,9 +789,11 @@ static RPCHelpMan listbanned()
|
|||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "", "",
|
{RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::STR, "address", ""},
|
{RPCResult::Type::STR, "address", "The IP/Subnet of the banned node"},
|
||||||
{RPCResult::Type::NUM_TIME, "banned_until", ""},
|
{RPCResult::Type::NUM_TIME, "ban_created", "The " + UNIX_EPOCH_TIME + " the ban was created"},
|
||||||
{RPCResult::Type::NUM_TIME, "ban_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{
|
RPCExamples{
|
||||||
@ -808,6 +810,7 @@ static RPCHelpMan listbanned()
|
|||||||
|
|
||||||
banmap_t banMap;
|
banmap_t banMap;
|
||||||
node.banman->GetBanned(banMap);
|
node.banman->GetBanned(banMap);
|
||||||
|
const int64_t current_time{GetTime()};
|
||||||
|
|
||||||
UniValue bannedAddresses(UniValue::VARR);
|
UniValue bannedAddresses(UniValue::VARR);
|
||||||
for (const auto& entry : banMap)
|
for (const auto& entry : banMap)
|
||||||
@ -815,8 +818,10 @@ static RPCHelpMan listbanned()
|
|||||||
const CBanEntry& banEntry = entry.second;
|
const CBanEntry& banEntry = entry.second;
|
||||||
UniValue rec(UniValue::VOBJ);
|
UniValue rec(UniValue::VOBJ);
|
||||||
rec.pushKV("address", entry.first.ToString());
|
rec.pushKV("address", entry.first.ToString());
|
||||||
rec.pushKV("banned_until", banEntry.nBanUntil);
|
|
||||||
rec.pushKV("ban_created", banEntry.nCreateTime);
|
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);
|
bannedAddresses.push_back(rec);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,6 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
|||||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect
|
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect
|
||||||
}
|
}
|
||||||
BOOST_CHECK(dummyNode1.fDisconnect == true);
|
BOOST_CHECK(dummyNode1.fDisconnect == true);
|
||||||
SetMockTime(0);
|
|
||||||
|
|
||||||
peerLogic->FinalizeNode(dummyNode1);
|
peerLogic->FinalizeNode(dummyNode1);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ FUZZ_TARGET(psbt)
|
|||||||
(void)PSBTInputSigned(input);
|
(void)PSBTInputSigned(input);
|
||||||
(void)input.IsNull();
|
(void)input.IsNull();
|
||||||
}
|
}
|
||||||
|
(void)CountPSBTUnsignedInputs(psbt);
|
||||||
|
|
||||||
for (const PSBTOutput& output : psbt.outputs) {
|
for (const PSBTOutput& output : psbt.outputs) {
|
||||||
(void)output.IsNull();
|
(void)output.IsNull();
|
||||||
|
@ -14,7 +14,6 @@ BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(logging_timer)
|
BOOST_AUTO_TEST_CASE(logging_timer)
|
||||||
{
|
{
|
||||||
|
|
||||||
SetMockTime(1);
|
SetMockTime(1);
|
||||||
auto sec_timer = BCLog::Timer<std::chrono::seconds>("tests", "end_msg");
|
auto sec_timer = BCLog::Timer<std::chrono::seconds>("tests", "end_msg");
|
||||||
SetMockTime(2);
|
SetMockTime(2);
|
||||||
@ -29,8 +28,6 @@ BOOST_AUTO_TEST_CASE(logging_timer)
|
|||||||
auto micro_timer = BCLog::Timer<std::chrono::microseconds>("tests", "end_msg");
|
auto micro_timer = BCLog::Timer<std::chrono::microseconds>("tests", "end_msg");
|
||||||
SetMockTime(2);
|
SetMockTime(2);
|
||||||
BOOST_CHECK_EQUAL(micro_timer.LogMsg("test micros"), "tests: test micros (1000000μs)");
|
BOOST_CHECK_EQUAL(micro_timer.LogMsg("test micros"), "tests: test micros (1000000μs)");
|
||||||
|
|
||||||
SetMockTime(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -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);
|
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);
|
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
|
||||||
// ... unless it has gone all the way to 0 (after getting past 1000/2)
|
// ... 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>())
|
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>())
|
||||||
|
@ -317,22 +317,29 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
|
|||||||
ar = r.get_array();
|
ar = r.get_array();
|
||||||
o1 = ar[0].get_obj();
|
o1 = ar[0].get_obj();
|
||||||
adr = find_value(o1, "address");
|
adr = find_value(o1, "address");
|
||||||
UniValue banned_until = find_value(o1, "banned_until");
|
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(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")));
|
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")));
|
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")));
|
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
|
||||||
ar = r.get_array();
|
ar = r.get_array();
|
||||||
o1 = ar[0].get_obj();
|
o1 = ar[0].get_obj();
|
||||||
adr = find_value(o1, "address");
|
adr = find_value(o1, "address");
|
||||||
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");
|
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
|
||||||
int64_t now = GetTime();
|
BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count());
|
||||||
BOOST_CHECK(banned_until.get_int64() > now);
|
BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created);
|
||||||
BOOST_CHECK(banned_until.get_int64()-now <= 200);
|
BOOST_CHECK_EQUAL(time_remaining, time_remaining_expected);
|
||||||
|
|
||||||
// must throw an exception because 127.0.0.1 is in already banned subnet range
|
// 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);
|
BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error);
|
||||||
|
@ -196,6 +196,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
|
|||||||
|
|
||||||
BasicTestingSetup::~BasicTestingSetup()
|
BasicTestingSetup::~BasicTestingSetup()
|
||||||
{
|
{
|
||||||
|
SetMockTime(0s); // Reset mocktime for following tests
|
||||||
connman.reset();
|
connman.reset();
|
||||||
llmq::quorumSnapshotManager.reset();
|
llmq::quorumSnapshotManager.reset();
|
||||||
m_node.cpoolman.reset();
|
m_node.cpoolman.reset();
|
||||||
@ -500,7 +501,6 @@ TestChainSetup::~TestChainSetup()
|
|||||||
g_txindex->Stop();
|
g_txindex->Stop();
|
||||||
SyncWithValidationInterfaceQueue();
|
SyncWithValidationInterfaceQueue();
|
||||||
g_txindex.reset();
|
g_txindex.reset();
|
||||||
SetMockTime(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const
|
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const
|
||||||
|
@ -315,8 +315,6 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
|
|||||||
BOOST_CHECK_EQUAL(found, expected);
|
BOOST_CHECK_EQUAL(found, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetMockTime(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify getaddressinfo RPC produces more or less expected results
|
// 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
|
// 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.
|
// 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);
|
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)
|
BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
|
||||||
|
85
test/functional/feature_anchors.py
Executable file
85
test/functional/feature_anchors.py
Executable 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()
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from test_framework.blocktools import create_transaction
|
|
||||||
from test_framework.messages import (
|
from test_framework.messages import (
|
||||||
CBlock,
|
CBlock,
|
||||||
COutPoint,
|
COutPoint,
|
||||||
@ -15,38 +14,30 @@ from test_framework.messages import (
|
|||||||
from test_framework.crypto.muhash import MuHash3072
|
from test_framework.crypto.muhash import MuHash3072
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import assert_equal
|
from test_framework.util import assert_equal
|
||||||
|
from test_framework.wallet import MiniWallet
|
||||||
|
|
||||||
class UTXOSetHashTest(BitcoinTestFramework):
|
class UTXOSetHashTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.setup_clean_chain = True
|
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):
|
def test_muhash_implementation(self):
|
||||||
self.log.info("Test MuHash implementation consistency")
|
self.log.info("Test MuHash implementation consistency")
|
||||||
|
|
||||||
node = self.nodes[0]
|
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
|
# Generate 100 blocks and remove the first since we plan to spend its
|
||||||
# coinbase
|
# 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))
|
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
|
# Create a spending transaction and mine a block which includes it
|
||||||
tx = create_transaction(node, spending.vtx[0].rehash(), node.getnewaddress(), amount=49)
|
txid = wallet.send_self_transfer(from_node=node)['txid']
|
||||||
txid = node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
|
tx_block = node.generateblock(output=wallet.get_address(), transactions=[txid])['hash']
|
||||||
|
|
||||||
tx_block = node.generateblock(node.getnewaddress(), [txid])['hash']
|
|
||||||
blocks.append(from_hex(CBlock(), node.getblock(tx_block, False)))
|
blocks.append(from_hex(CBlock(), node.getblock(tx_block, False)))
|
||||||
|
|
||||||
# Serialize the outputs that should be in the UTXO set and add them to
|
# 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)
|
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):
|
def run_test(self):
|
||||||
self.test_deterministic_hash_results()
|
|
||||||
self.test_muhash_implementation()
|
self.test_muhash_implementation()
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ class MiniWallet:
|
|||||||
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
|
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
|
||||||
return blocks
|
return blocks
|
||||||
|
|
||||||
|
def get_address(self):
|
||||||
|
return self._address
|
||||||
|
|
||||||
def get_utxo(self, *, txid=''):
|
def get_utxo(self, *, txid=''):
|
||||||
"""
|
"""
|
||||||
Returns a utxo and marks it as spent (pops it from the internal list)
|
Returns a utxo and marks it as spent (pops it from the internal list)
|
||||||
|
@ -318,6 +318,7 @@ BASE_SCRIPTS = [
|
|||||||
'p2p_ping.py',
|
'p2p_ping.py',
|
||||||
'rpc_scantxoutset.py',
|
'rpc_scantxoutset.py',
|
||||||
'feature_logging.py',
|
'feature_logging.py',
|
||||||
|
'feature_anchors.py',
|
||||||
'feature_coinstatsindex.py',
|
'feature_coinstatsindex.py',
|
||||||
'wallet_orphanedreward.py',
|
'wallet_orphanedreward.py',
|
||||||
'p2p_node_network_limited.py',
|
'p2p_node_network_limited.py',
|
||||||
|
@ -32,8 +32,9 @@ class WalletGroupTest(BitcoinTestFramework):
|
|||||||
self.skip_if_no_wallet()
|
self.skip_if_no_wallet()
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
self.log.info("Setting up")
|
||||||
# Mine some coins
|
# Mine some coins
|
||||||
self.nodes[0].generate(COINBASE_MATURITY + 10)
|
self.nodes[0].generate(COINBASE_MATURITY + 1)
|
||||||
|
|
||||||
# Get some addresses from the two nodes
|
# Get some addresses from the two nodes
|
||||||
addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
|
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[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
|
# - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
|
||||||
# given address, and leave the rest
|
# 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)
|
txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
|
||||||
tx1 = self.nodes[1].getrawtransaction(txid1, True)
|
tx1 = self.nodes[1].getrawtransaction(txid1, True)
|
||||||
# txid1 should have 1 input and 2 outputs
|
# 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[0], vexp=0.2, vspan=0.0001)
|
||||||
assert_approx(v[1], vexp=1.3, 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.sync_all()
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
# Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
|
# 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])
|
assert_equal(input_addrs[0], input_addrs[1])
|
||||||
# Node 2 enforces avoidpartialspends so needs no checking here
|
# 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()
|
addr_aps = self.nodes[3].getnewaddress()
|
||||||
self.nodes[0].sendtoaddress(addr_aps, 1.0)
|
self.nodes[0].sendtoaddress(addr_aps, 1.0)
|
||||||
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
|
# Test wallet option maxapsfee with node 4, which sets maxapsfee
|
||||||
# 1 sat higher, crossing the threshold from non-grouped to grouped.
|
# 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()
|
addr_aps3 = self.nodes[4].getnewaddress()
|
||||||
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
|
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
@ -150,8 +153,7 @@ class WalletGroupTest(BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
|
||||||
# Fill node2's wallet with 10000 outputs corresponding to the same
|
self.log.info("Fill a wallet with 10,000 outputs corresponding to the same scriptPubKey")
|
||||||
# scriptPubKey
|
|
||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
|
raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
|
||||||
tx = tx_from_hex(raw_tx)
|
tx = tx_from_hex(raw_tx)
|
||||||
@ -161,12 +163,12 @@ class WalletGroupTest(BitcoinTestFramework):
|
|||||||
signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
|
signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
|
||||||
self.nodes[0].sendrawtransaction(signed_tx['hex'])
|
self.nodes[0].sendrawtransaction(signed_tx['hex'])
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
self.sync_all()
|
||||||
self.sync_all()
|
|
||||||
|
|
||||||
# Check that we can create a transaction that only requires ~100 of our
|
# Check that we can create a transaction that only requires ~100 of our
|
||||||
# utxos, without pulling in all outputs and creating a transaction that
|
# utxos, without pulling in all outputs and creating a transaction that
|
||||||
# is way too big.
|
# 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)
|
assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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/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 '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/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."
|
"src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user