aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.qt.include14
-rw-r--r--src/Makefile.qttest.include3
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/coins.h3
-rw-r--r--src/init.cpp2
-rw-r--r--src/node/coinstats.cpp1
-rw-r--r--src/qt/Makefile2
-rw-r--r--src/qt/android/AndroidManifest.xml38
-rw-r--r--src/qt/android/build.gradle52
-rw-r--r--src/qt/android/gradle.properties4
-rw-r--r--src/qt/android/res/drawable-hdpi/bitcoin.pngbin0 -> 4536 bytes
-rw-r--r--src/qt/android/res/drawable-ldpi/bitcoin.pngbin0 -> 1697 bytes
-rw-r--r--src/qt/android/res/drawable-mdpi/bitcoin.pngbin0 -> 2558 bytes
-rw-r--r--src/qt/android/res/drawable-xhdpi/bitcoin.pngbin0 -> 6832 bytes
-rw-r--r--src/qt/android/res/drawable-xxhdpi/bitcoin.pngbin0 -> 11479 bytes
-rw-r--r--src/qt/android/res/drawable-xxxhdpi/bitcoin.pngbin0 -> 17034 bytes
-rw-r--r--src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java29
-rw-r--r--src/qt/bitcoin.cpp6
-rw-r--r--src/qt/createwalletdialog.cpp6
-rw-r--r--src/qt/guiutil.cpp12
-rw-r--r--src/qt/paymentserver.cpp12
-rw-r--r--src/qt/platformstyle.cpp2
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/test/compattests.cpp25
-rw-r--r--src/qt/test/compattests.h19
-rw-r--r--src/qt/test/test_main.cpp5
-rw-r--r--src/qt/trafficgraphwidget.cpp10
-rw-r--r--src/rpc/blockchain.cpp6
-rw-r--r--src/test/bswap_tests.cpp1
-rw-r--r--src/test/fuzz/addrman.cpp2
-rw-r--r--src/test/fuzz/pow.cpp8
-rw-r--r--src/test/fuzz/process_message.cpp4
-rw-r--r--src/test/fuzz/process_messages.cpp6
-rw-r--r--src/test/fuzz/tx_pool.cpp285
-rw-r--r--src/test/fuzz/util.cpp78
-rw-r--r--src/test/fuzz/util.h22
-rw-r--r--src/test/fuzz/versionbits.cpp42
-rw-r--r--src/test/net_tests.cpp54
-rw-r--r--src/txmempool.h2
-rw-r--r--src/wallet/load.cpp2
40 files changed, 648 insertions, 112 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 59cfdb9839..399a8430ef 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -378,6 +378,20 @@ bitcoin_qt_clean: FORCE
bitcoin_qt : qt/bitcoin-qt$(EXEEXT)
+APK_LIB_DIR = qt/android/libs/$(ANDROID_ARCH)
+QT_BASE_PATH = $(shell find ../depends/sources/ -maxdepth 1 -type f -regex ".*qtbase.*\.tar.xz")
+QT_BASE_TLD = $(shell tar tf $(QT_BASE_PATH) --exclude='*/*')
+
+bitcoin_qt_apk: FORCE
+ mkdir -p $(APK_LIB_DIR)
+ cp $(dir $(CC))../sysroot/usr/lib/$(host_alias)/libc++_shared.so $(APK_LIB_DIR)
+ tar xf $(QT_BASE_PATH) -C qt/android/src/ $(QT_BASE_TLD)src/android/jar/src --strip-components=5
+ tar xf $(QT_BASE_PATH) -C qt/android/src/ $(QT_BASE_TLD)src/android/java/src --strip-components=5
+ tar xf $(QT_BASE_PATH) -C qt/android/res/ $(QT_BASE_TLD)src/android/java/res --strip-components=5
+ cp qt/bitcoin-qt $(APK_LIB_DIR)/libbitcoin-qt.so
+ cd qt/android && gradle wrapper --gradle-version=6.6.1
+ cd qt/android && ./gradlew build
+
ui_%.h: %.ui
@test -f $(UIC)
@$(MKDIR_P) $(@D)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index a6a857d952..91a5e9fd9b 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -7,7 +7,6 @@ TESTS += qt/test/test_bitcoin-qt
TEST_QT_MOC_CPP = \
qt/test/moc_apptests.cpp \
- qt/test/moc_compattests.cpp \
qt/test/moc_rpcnestedtests.cpp \
qt/test/moc_uritests.cpp
@@ -20,7 +19,6 @@ endif # ENABLE_WALLET
TEST_QT_H = \
qt/test/addressbooktests.h \
qt/test/apptests.h \
- qt/test/compattests.h \
qt/test/rpcnestedtests.h \
qt/test/uritests.h \
qt/test/util.h \
@@ -31,7 +29,6 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
qt_test_test_bitcoin_qt_SOURCES = \
qt/test/apptests.cpp \
- qt/test/compattests.cpp \
qt/test/rpcnestedtests.cpp \
qt/test/test_main.cpp \
qt/test/uritests.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 7ed0eafb14..e00f17a83f 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -297,6 +297,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/transaction.cpp \
test/fuzz/tx_in.cpp \
test/fuzz/tx_out.cpp \
+ test/fuzz/tx_pool.cpp \
test/fuzz/txrequest.cpp \
test/fuzz/validation_load_mempool.cpp \
test/fuzz/versionbits.cpp
diff --git a/src/coins.h b/src/coins.h
index feb441fd6a..5a6f73652b 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -75,6 +75,9 @@ public:
::Unserialize(s, Using<TxOutCompression>(out));
}
+ /** Either this coin never existed (see e.g. coinEmpty in coins.cpp), or it
+ * did exist and has been spent.
+ */
bool IsSpent() const {
return out.IsNull();
}
diff --git a/src/init.cpp b/src/init.cpp
index 7d5420e3be..f4b7699233 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1308,7 +1308,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
LogPrintf("Config file: %s\n", config_file_path.string());
} else if (args.IsArgSet("-conf")) {
// Warn if no conf file exists at path provided by user
- InitWarning(strprintf(_("The specified config file %s does not exist\n"), config_file_path.string()));
+ InitWarning(strprintf(_("The specified config file %s does not exist"), config_file_path.string()));
} else {
// Not categorizing as "Warning" because it's the default behavior
LogPrintf("Config file: %s (not found, skipping)\n", config_file_path.string());
diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp
index 88bdba5953..268580c6e6 100644
--- a/src/node/coinstats.cpp
+++ b/src/node/coinstats.cpp
@@ -15,6 +15,7 @@
#include <map>
+// Database-independent metric indicating the UTXO set size
static uint64_t GetBogoSize(const CScript& scriptPubKey)
{
return 32 /* txid */ +
diff --git a/src/qt/Makefile b/src/qt/Makefile
index b9dcf0c599..3bd6199059 100644
--- a/src/qt/Makefile
+++ b/src/qt/Makefile
@@ -7,3 +7,5 @@ check: FORCE
$(MAKE) -C .. test_bitcoin_qt_check
bitcoin-qt bitcoin-qt.exe: FORCE
$(MAKE) -C .. bitcoin_qt
+apk: FORCE
+ $(MAKE) -C .. bitcoin_qt_apk
diff --git a/src/qt/android/AndroidManifest.xml b/src/qt/android/AndroidManifest.xml
new file mode 100644
index 0000000000..abb88fe89d
--- /dev/null
+++ b/src/qt/android/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<manifest package="org.bitcoincore.qt" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
+ <uses-sdk android:targetSdkVersion="24"/>
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+ <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+
+ <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Bitcoin Core">
+ <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:name="org.bitcoincore.qt.BitcoinQtActivity"
+ android:label="Bitcoin Core"
+ android:icon="@drawable/bitcoin"
+ android:screenOrientation="unspecified"
+ android:launchMode="singleTop">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+
+ <meta-data android:name="android.app.arguments" android:value="-testnet"/>
+ <meta-data android:name="android.app.lib_name" android:value="bitcoin-qt"/>
+ <meta-data android:name="android.app.repository" android:value="default"/>
+ <meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>
+ <meta-data android:name="android.app.use_local_qt_libs" android:value="1"/>
+ <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
+ <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/>
+ <meta-data android:name="android.app.background_running" android:value="true"/>
+ <meta-data android:name="android.app.auto_screen_scale_factor" android:value="true"/>
+ <meta-data android:name="android.app.extract_android_style" android:value="default"/>
+ </activity>
+
+ </application>
+</manifest>
diff --git a/src/qt/android/build.gradle b/src/qt/android/build.gradle
new file mode 100644
index 0000000000..4c36e79db8
--- /dev/null
+++ b/src/qt/android/build.gradle
@@ -0,0 +1,52 @@
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.1.0'
+ }
+}
+
+repositories {
+ google()
+ jcenter()
+}
+
+apply plugin: 'com.android.application'
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+}
+
+android {
+ compileSdkVersion androidCompileSdkVersion.toInteger()
+
+ buildToolsVersion androidBuildToolsVersion
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
+ aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
+ res.srcDirs = [qt5AndroidDir + '/res', 'res']
+ resources.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ assets.srcDirs = ['assets']
+ jniLibs.srcDirs = ['libs']
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ dexOptions {
+ javaMaxHeapSize '4g'
+ }
+
+ defaultConfig {
+ minSdkVersion 24
+ }
+}
diff --git a/src/qt/android/gradle.properties b/src/qt/android/gradle.properties
new file mode 100644
index 0000000000..838870f62d
--- /dev/null
+++ b/src/qt/android/gradle.properties
@@ -0,0 +1,4 @@
+androidBuildToolsVersion=28.0.3
+androidCompileSdkVersion=28
+qt5AndroidDir=new File(".").absolutePath
+org.gradle.jvmargs=-Xmx4608M
diff --git a/src/qt/android/res/drawable-hdpi/bitcoin.png b/src/qt/android/res/drawable-hdpi/bitcoin.png
new file mode 100644
index 0000000000..31a556a35f
--- /dev/null
+++ b/src/qt/android/res/drawable-hdpi/bitcoin.png
Binary files differ
diff --git a/src/qt/android/res/drawable-ldpi/bitcoin.png b/src/qt/android/res/drawable-ldpi/bitcoin.png
new file mode 100644
index 0000000000..76d80d4196
--- /dev/null
+++ b/src/qt/android/res/drawable-ldpi/bitcoin.png
Binary files differ
diff --git a/src/qt/android/res/drawable-mdpi/bitcoin.png b/src/qt/android/res/drawable-mdpi/bitcoin.png
new file mode 100644
index 0000000000..c2aeab851a
--- /dev/null
+++ b/src/qt/android/res/drawable-mdpi/bitcoin.png
Binary files differ
diff --git a/src/qt/android/res/drawable-xhdpi/bitcoin.png b/src/qt/android/res/drawable-xhdpi/bitcoin.png
new file mode 100644
index 0000000000..2bd5e3defc
--- /dev/null
+++ b/src/qt/android/res/drawable-xhdpi/bitcoin.png
Binary files differ
diff --git a/src/qt/android/res/drawable-xxhdpi/bitcoin.png b/src/qt/android/res/drawable-xxhdpi/bitcoin.png
new file mode 100644
index 0000000000..d236cf2132
--- /dev/null
+++ b/src/qt/android/res/drawable-xxhdpi/bitcoin.png
Binary files differ
diff --git a/src/qt/android/res/drawable-xxxhdpi/bitcoin.png b/src/qt/android/res/drawable-xxxhdpi/bitcoin.png
new file mode 100644
index 0000000000..bb1dbc3554
--- /dev/null
+++ b/src/qt/android/res/drawable-xxxhdpi/bitcoin.png
Binary files differ
diff --git a/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java b/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java
new file mode 100644
index 0000000000..cf3b4f6668
--- /dev/null
+++ b/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java
@@ -0,0 +1,29 @@
+package org.bitcoincore.qt;
+
+import android.os.Bundle;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import org.qtproject.qt5.android.bindings.QtActivity;
+
+import java.io.File;
+
+public class BitcoinQtActivity extends QtActivity
+{
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ final File bitcoinDir = new File(getFilesDir().getAbsolutePath() + "/.bitcoin");
+ if (!bitcoinDir.exists()) {
+ bitcoinDir.mkdir();
+ }
+
+ try {
+ Os.setenv("QT_QPA_PLATFORM", "android", true);
+ } catch (ErrnoException e) {
+ e.printStackTrace();
+ }
+
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 791a29f7a0..fc6d0febc2 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -466,6 +466,12 @@ int GuiMain(int argc, char* argv[])
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+#if defined(QT_QPA_PLATFORM_ANDROID)
+ QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+ QApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
+#endif
+
BitcoinApplication app;
QFontDatabase::addApplicationFont(":/fonts/monospace");
diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp
index 1467801522..113bd30a0c 100644
--- a/src/qt/createwalletdialog.cpp
+++ b/src/qt/createwalletdialog.cpp
@@ -53,6 +53,12 @@ CreateWalletDialog::CreateWalletDialog(QWidget* parent) :
}
});
+ connect(ui->blank_wallet_checkbox, &QCheckBox::toggled, [this](bool checked) {
+ if (!checked) {
+ ui->disable_privkeys_checkbox->setChecked(false);
+ }
+ });
+
#ifndef USE_SQLITE
ui->descriptor_checkbox->setToolTip(tr("Compiled without sqlite support (required for descriptor wallets)"));
ui->descriptor_checkbox->setEnabled(false);
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 32890ed0fe..b4afdbcc22 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -759,14 +759,14 @@ QString formatNiceTimeOffset(qint64 secs)
QString formatBytes(uint64_t bytes)
{
- if(bytes < 1024)
+ if (bytes < 1'000)
return QObject::tr("%1 B").arg(bytes);
- if(bytes < 1024 * 1024)
- return QObject::tr("%1 KB").arg(bytes / 1024);
- if(bytes < 1024 * 1024 * 1024)
- return QObject::tr("%1 MB").arg(bytes / 1024 / 1024);
+ if (bytes < 1'000'000)
+ return QObject::tr("%1 kB").arg(bytes / 1'000);
+ if (bytes < 1'000'000'000)
+ return QObject::tr("%1 MB").arg(bytes / 1'000'000);
- return QObject::tr("%1 GB").arg(bytes / 1024 / 1024 / 1024);
+ return QObject::tr("%1 GB").arg(bytes / 1'000'000'000);
}
qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize, qreal font_size) {
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 96f6202874..58f6c14e7a 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -235,9 +235,9 @@ void PaymentServer::handleURIOrFile(const QString& s)
if (!IsValidDestinationString(recipient.address.toStdString())) {
if (uri.hasQueryItem("r")) { // payment request
Q_EMIT message(tr("URI handling"),
- tr("Cannot process payment request because BIP70 is not supported.")+
- tr("Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.")+
- tr("If you are receiving this error you should request the merchant provide a BIP21 compatible URI."),
+ tr("Cannot process payment request because BIP70 is not supported.\n"
+ "Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.\n"
+ "If you are receiving this error you should request the merchant provide a BIP21 compatible URI."),
CClientUIInterface::ICON_WARNING);
}
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
@@ -258,9 +258,9 @@ void PaymentServer::handleURIOrFile(const QString& s)
if (QFile::exists(s)) // payment request file
{
Q_EMIT message(tr("Payment request file handling"),
- tr("Cannot process payment request because BIP70 is not supported.")+
- tr("Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.")+
- tr("If you are receiving this error you should request the merchant provide a BIP21 compatible URI."),
+ tr("Cannot process payment request because BIP70 is not supported.\n"
+ "Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.\n"
+ "If you are receiving this error you should request the merchant provide a BIP21 compatible URI."),
CClientUIInterface::ICON_WARNING);
}
}
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index aab8d8e4af..1d0605c903 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -18,7 +18,7 @@ static const struct {
/** Extra padding/spacing in transactionview */
const bool useExtraSpacing;
} platform_styles[] = {
- {"macosx", false, false, true},
+ {"macosx", false, true, true},
{"windows", true, false, false},
/* Other: linux, unix, ... */
{"other", true, true, false}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index b258219894..34d055e5a5 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -608,7 +608,6 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
// set up peer table
ui->peerWidget->setModel(model->getPeerTableModel());
ui->peerWidget->verticalHeader()->hide();
- ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -651,7 +650,6 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
// set up ban table
ui->banlistWidget->setModel(model->getBanTableModel());
ui->banlistWidget->verticalHeader()->hide();
- ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
deleted file mode 100644
index c76dee5091..0000000000
--- a/src/qt/test/compattests.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <qt/test/compattests.h>
-
-#include <compat/byteswap.h>
-
-void CompatTests::bswapTests()
-{
- // Sibling in bitcoin/src/test/bswap_tests.cpp
- uint16_t u1 = 0x1234;
- uint32_t u2 = 0x56789abc;
- uint64_t u3 = 0xdef0123456789abc;
- uint16_t e1 = 0x3412;
- uint32_t e2 = 0xbc9a7856;
- uint64_t e3 = 0xbc9a78563412f0de;
- QVERIFY(bswap_16(u1) == e1);
- QVERIFY(bswap_32(u2) == e2);
- QVERIFY(bswap_64(u3) == e3);
-}
diff --git a/src/qt/test/compattests.h b/src/qt/test/compattests.h
deleted file mode 100644
index 1af97696b2..0000000000
--- a/src/qt/test/compattests.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2009-2016 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_QT_TEST_COMPATTESTS_H
-#define BITCOIN_QT_TEST_COMPATTESTS_H
-
-#include <QObject>
-#include <QTest>
-
-class CompatTests : public QObject
-{
- Q_OBJECT
-
-private Q_SLOTS:
- void bswapTests();
-};
-
-#endif // BITCOIN_QT_TEST_COMPATTESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index a1baf6a402..eb86f027ef 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -11,7 +11,6 @@
#include <qt/test/apptests.h>
#include <qt/test/rpcnestedtests.h>
#include <qt/test/uritests.h>
-#include <qt/test/compattests.h>
#include <test/util/setup_common.h>
#ifdef ENABLE_WALLET
@@ -92,10 +91,6 @@ int main(int argc, char* argv[])
if (QTest::qExec(&test3) != 0) {
fInvalid = true;
}
- CompatTests test4;
- if (QTest::qExec(&test4) != 0) {
- fInvalid = true;
- }
#ifdef ENABLE_WALLET
WalletTests test5(app.node());
if (QTest::qExec(&test5) != 0) {
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index dabdf9d887..7e12410c80 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -79,7 +79,7 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *)
int base = floor(log10(fMax));
float val = pow(10.0f, base);
- const QString units = tr("KB/s");
+ const QString units = tr("kB/s");
const float yMarginText = 2.0;
// draw lines
@@ -128,10 +128,10 @@ void TrafficGraphWidget::updateRates()
quint64 bytesIn = clientModel->node().getTotalBytesRecv(),
bytesOut = clientModel->node().getTotalBytesSent();
- float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
- float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
- vSamplesIn.push_front(inRate);
- vSamplesOut.push_front(outRate);
+ float in_rate_kilobytes_per_sec = static_cast<float>(bytesIn - nLastBytesIn) / timer->interval();
+ float out_rate_kilobytes_per_sec = static_cast<float>(bytesOut - nLastBytesOut) / timer->interval();
+ vSamplesIn.push_front(in_rate_kilobytes_per_sec);
+ vSamplesOut.push_front(out_rate_kilobytes_per_sec);
nLastBytesIn = bytesIn;
nLastBytesOut = bytesOut;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index b90dc9bf42..3ba2fa46ae 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1050,15 +1050,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, "transactions", "The number of transactions with unspent outputs"},
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
{RPCResult::Type::NUM, "bogosize", "A meaningless metric for 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, "disk_size", "The estimated size of the chainstate on disk"},
- {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount"},
+ {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
}},
RPCExamples{
HelpExampleCli("gettxoutsetinfo", "")
diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp
index c89cb5488d..2dbca4e8b6 100644
--- a/src/test/bswap_tests.cpp
+++ b/src/test/bswap_tests.cpp
@@ -11,7 +11,6 @@ BOOST_FIXTURE_TEST_SUITE(bswap_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(bswap_tests)
{
- // Sibling in bitcoin/src/qt/test/compattests.cpp
uint16_t u1 = 0x1234;
uint32_t u2 = 0x56789abc;
uint64_t u3 = 0xdef0123456789abc;
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index b55f1c72b1..0baf30aef6 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -104,7 +104,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral<uint64_t>()});
+ addr_man.SetServices(*opt_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
}
},
[&] {
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 53726ca893..47b4323e81 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -34,7 +34,7 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
CBlockIndex current_block{*block_header};
{
- CBlockIndex* previous_block = !blocks.empty() ? &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)] : nullptr;
+ CBlockIndex* previous_block = blocks.empty() ? nullptr : &PickValue(fuzzed_data_provider, blocks);
const int current_height = (previous_block != nullptr && previous_block->nHeight != std::numeric_limits<int>::max()) ? previous_block->nHeight + 1 : 0;
if (fuzzed_data_provider.ConsumeBool()) {
current_block.pprev = previous_block;
@@ -66,9 +66,9 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
}
{
- const CBlockIndex* to = &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)];
- const CBlockIndex* from = &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)];
- const CBlockIndex* tip = &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)];
+ const CBlockIndex* to = &PickValue(fuzzed_data_provider, blocks);
+ const CBlockIndex* from = &PickValue(fuzzed_data_provider, blocks);
+ const CBlockIndex* tip = &PickValue(fuzzed_data_provider, blocks);
try {
(void)GetBlockProofEquivalentTime(*to, *from, *tip, consensus_params);
} catch (const uint_error&) {
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 04fc6da9b1..96e1cfa08f 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -68,8 +68,8 @@ void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
- TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate();
+ ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
+ TestChainState& chainstate = *static_cast<TestChainState*>(&g_setup->m_node.chainman->ActiveChainstate());
SetMockTime(1610000000); // any time to successfully reset ibd
chainstate.ResetIbd();
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index ee402dba38..203c0ef8e1 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -35,8 +35,8 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
- TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate();
+ ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
+ TestChainState& chainstate = *static_cast<TestChainState*>(&g_setup->m_node.chainman->ActiveChainstate());
SetMockTime(1610000000); // any time to successfully reset ibd
chainstate.ResetIbd();
@@ -65,7 +65,7 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
net_msg.m_type = random_message_type;
net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- CNode& random_node = *peers.at(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, peers.size() - 1));
+ CNode& random_node = *PickValue(fuzzed_data_provider, peers);
(void)connman.ReceiveMsgFrom(random_node, net_msg);
random_node.fPauseSend = false;
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
new file mode 100644
index 0000000000..f84d6702a7
--- /dev/null
+++ b/src/test/fuzz/tx_pool.cpp
@@ -0,0 +1,285 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <consensus/validation.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/mining.h>
+#include <test/util/script.h>
+#include <test/util/setup_common.h>
+#include <util/rbf.h>
+#include <validation.h>
+#include <validationinterface.h>
+
+namespace {
+
+const TestingSetup* g_setup;
+std::vector<COutPoint> g_outpoints_coinbase_init_mature;
+std::vector<COutPoint> g_outpoints_coinbase_init_immature;
+
+struct MockedTxPool : public CTxMemPool {
+ void RollingFeeUpdate()
+ {
+ lastRollingFeeUpdate = GetTime();
+ blockSinceLastRollingFeeBump = true;
+ }
+};
+
+void initialize_tx_pool()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+
+ for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
+ CTxIn in = MineBlock(g_setup->m_node, P2WSH_OP_TRUE);
+ // Remember the txids to avoid expensive disk acess later on
+ auto& outpoints = i < COINBASE_MATURITY ?
+ g_outpoints_coinbase_init_mature :
+ g_outpoints_coinbase_init_immature;
+ outpoints.push_back(in.prevout);
+ }
+ SyncWithValidationInterfaceQueue();
+}
+
+struct TransactionsDelta final : public CValidationInterface {
+ std::set<CTransactionRef>& m_removed;
+ std::set<CTransactionRef>& m_added;
+
+ explicit TransactionsDelta(std::set<CTransactionRef>& r, std::set<CTransactionRef>& a)
+ : m_removed{r}, m_added{a} {}
+
+ void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t /* mempool_sequence */) override
+ {
+ Assert(m_added.insert(tx).second);
+ }
+
+ void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
+ {
+ Assert(m_removed.insert(tx).second);
+ }
+};
+
+void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_provider)
+{
+ args.ForceSetArg("-limitancestorcount",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50)));
+ args.ForceSetArg("-limitancestorsize",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202)));
+ args.ForceSetArg("-limitdescendantcount",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50)));
+ args.ForceSetArg("-limitdescendantsize",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202)));
+ args.ForceSetArg("-maxmempool",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 200)));
+ args.ForceSetArg("-mempoolexpiry",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)));
+}
+
+FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+ auto& chainstate = node.chainman->ActiveChainstate();
+
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+
+ // All RBF-spendable outpoints
+ std::set<COutPoint> outpoints_rbf;
+ // All outpoints counting toward the total supply (subset of outpoints_rbf)
+ std::set<COutPoint> outpoints_supply;
+ for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
+ Assert(outpoints_supply.insert(outpoint).second);
+ }
+ outpoints_rbf = outpoints_supply;
+
+ // The sum of the values of all spendable outpoints
+ constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
+
+ CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1};
+ MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
+
+ // Helper to query an amount
+ const CCoinsViewMemPool amount_view{WITH_LOCK(::cs_main, return &chainstate.CoinsTip()), tx_pool};
+ const auto GetAmount = [&](const COutPoint& outpoint) {
+ Coin c;
+ Assert(amount_view.GetCoin(outpoint, c));
+ return c.out.nValue;
+ };
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ {
+ // Total supply is the mempool fee + all outpoints
+ CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())};
+ for (const auto& op : outpoints_supply) {
+ supply_now += GetAmount(op);
+ }
+ Assert(supply_now == SUPPLY_TOTAL);
+ }
+ Assert(!outpoints_supply.empty());
+
+ // Create transaction to add to the mempool
+ const CTransactionRef tx = [&] {
+ CMutableTransaction tx_mut;
+ tx_mut.nVersion = CTransaction::CURRENT_VERSION;
+ tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size());
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size() * 2);
+
+ CAmount amount_in{0};
+ for (int i = 0; i < num_in; ++i) {
+ // Pop random outpoint
+ auto pop = outpoints_rbf.begin();
+ std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints_rbf.size() - 1));
+ const auto outpoint = *pop;
+ outpoints_rbf.erase(pop);
+ amount_in += GetAmount(outpoint);
+
+ // Create input
+ const auto sequence = ConsumeSequence(fuzzed_data_provider);
+ const auto script_sig = CScript{};
+ const auto script_wit_stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
+ CTxIn in;
+ in.prevout = outpoint;
+ in.nSequence = sequence;
+ in.scriptSig = script_sig;
+ in.scriptWitness.stack = script_wit_stack;
+
+ tx_mut.vin.push_back(in);
+ }
+ const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-1000, amount_in);
+ const auto amount_out = (amount_in - amount_fee) / num_out;
+ for (int i = 0; i < num_out; ++i) {
+ tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);
+ }
+ const auto tx = MakeTransactionRef(tx_mut);
+ // Restore previously removed outpoints
+ for (const auto& in : tx->vin) {
+ Assert(outpoints_rbf.insert(in.prevout).second);
+ }
+ return tx;
+ }();
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ tx_pool.RollingFeeUpdate();
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ const auto& txid = fuzzed_data_provider.ConsumeBool() ?
+ tx->GetHash() :
+ PickValue(fuzzed_data_provider, outpoints_rbf).hash;
+ const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
+ tx_pool.PrioritiseTransaction(txid, delta);
+ }
+
+ // Remember all removed and added transactions
+ std::set<CTransactionRef> removed;
+ std::set<CTransactionRef> added;
+ auto txr = std::make_shared<TransactionsDelta>(removed, added);
+ RegisterSharedValidationInterface(txr);
+ const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
+ ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx_pool, tx, bypass_limits));
+ const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
+ SyncWithValidationInterfaceQueue();
+ UnregisterSharedValidationInterface(txr);
+
+ Assert(accepted != added.empty());
+ Assert(accepted == res.m_state.IsValid());
+ Assert(accepted != res.m_state.IsInvalid());
+ if (accepted) {
+ Assert(added.size() == 1); // For now, no package acceptance
+ Assert(tx == *added.begin());
+ } else {
+ // Do not consider rejected transaction removed
+ removed.erase(tx);
+ }
+
+ // Helper to insert spent and created outpoints of a tx into collections
+ using Sets = std::vector<std::reference_wrapper<std::set<COutPoint>>>;
+ const auto insert_tx = [](Sets created_by_tx, Sets consumed_by_tx, const auto& tx) {
+ for (size_t i{0}; i < tx.vout.size(); ++i) {
+ for (auto& set : created_by_tx) {
+ Assert(set.get().emplace(tx.GetHash(), i).second);
+ }
+ }
+ for (const auto& in : tx.vin) {
+ for (auto& set : consumed_by_tx) {
+ Assert(set.get().insert(in.prevout).second);
+ }
+ }
+ };
+ // Add created outpoints, remove spent outpoints
+ {
+ // Outpoints that no longer exist at all
+ std::set<COutPoint> consumed_erased;
+ // Outpoints that no longer count toward the total supply
+ std::set<COutPoint> consumed_supply;
+ for (const auto& removed_tx : removed) {
+ insert_tx(/* created_by_tx */ {consumed_erased}, /* consumed_by_tx */ {outpoints_supply}, /* tx */ *removed_tx);
+ }
+ for (const auto& added_tx : added) {
+ insert_tx(/* created_by_tx */ {outpoints_supply, outpoints_rbf}, /* consumed_by_tx */ {consumed_supply}, /* tx */ *added_tx);
+ }
+ for (const auto& p : consumed_erased) {
+ Assert(outpoints_supply.erase(p) == 1);
+ Assert(outpoints_rbf.erase(p) == 1);
+ }
+ for (const auto& p : consumed_supply) {
+ Assert(outpoints_supply.erase(p) == 1);
+ }
+ }
+ }
+ WITH_LOCK(::cs_main, tx_pool.check(chainstate));
+ const auto info_all = tx_pool.infoAll();
+ if (!info_all.empty()) {
+ const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
+ WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
+ std::vector<uint256> all_txids;
+ tx_pool.queryHashes(all_txids);
+ assert(all_txids.size() < info_all.size());
+ WITH_LOCK(::cs_main, tx_pool.check(chainstate));
+ }
+ SyncWithValidationInterfaceQueue();
+}
+
+FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+
+ std::vector<uint256> txids;
+ for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
+ txids.push_back(outpoint.hash);
+ }
+ for (int i{0}; i <= 3; ++i) {
+ // Add some immature and non-existent outpoints
+ txids.push_back(g_outpoints_coinbase_init_immature.at(i).hash);
+ txids.push_back(ConsumeUInt256(fuzzed_data_provider));
+ }
+
+ CTxMemPool tx_pool{/* estimator */ nullptr, /* check_ratio */ 1};
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
+
+ const auto tx = MakeTransactionRef(mut_tx);
+ const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
+ ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(node.chainman->ActiveChainstate(), tx_pool, tx, bypass_limits));
+ const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
+ if (accepted) {
+ txids.push_back(tx->GetHash());
+ }
+
+ SyncWithValidationInterfaceQueue();
+ }
+}
+} // namespace
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 0a541e4186..93418ab1ff 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -3,8 +3,11 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/fuzz/util.h>
+#include <test/util/script.h>
+#include <util/rbf.h>
#include <version.h>
+
void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept
{
const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
@@ -23,3 +26,78 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_v
node.m_tx_relay->fRelayTxes = filter_txs;
}
}
+
+CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
+{
+ CMutableTransaction tx_mut;
+ const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();
+ tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ?
+ CTransaction::CURRENT_VERSION :
+ fuzzed_data_provider.ConsumeIntegral<int32_t>();
+ tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in);
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out);
+ for (int i = 0; i < num_in; ++i) {
+ const auto& txid_prev = prevout_txids ?
+ PickValue(fuzzed_data_provider, *prevout_txids) :
+ ConsumeUInt256(fuzzed_data_provider);
+ const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);
+ const auto sequence = ConsumeSequence(fuzzed_data_provider);
+ const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);
+ CScriptWitness script_wit;
+ if (p2wsh_op_true) {
+ script_wit.stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
+ } else {
+ script_wit = ConsumeScriptWitness(fuzzed_data_provider);
+ }
+ CTxIn in;
+ in.prevout = COutPoint{txid_prev, index_out};
+ in.nSequence = sequence;
+ in.scriptSig = script_sig;
+ in.scriptWitness = script_wit;
+
+ tx_mut.vin.push_back(in);
+ }
+ for (int i = 0; i < num_out; ++i) {
+ const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
+ const auto script_pk = p2wsh_op_true ?
+ P2WSH_OP_TRUE :
+ ConsumeScript(fuzzed_data_provider, /* max_length */ 128, /* maybe_p2wsh */ true);
+ tx_mut.vout.emplace_back(amount, script_pk);
+ }
+ return tx_mut;
+}
+
+CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size) noexcept
+{
+ CScriptWitness ret;
+ const auto n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_stack_elem_size);
+ for (size_t i = 0; i < n_elements; ++i) {
+ ret.stack.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));
+ }
+ return ret;
+}
+
+CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length, const bool maybe_p2wsh) noexcept
+{
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ CScript r_script{b.begin(), b.end()};
+ if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {
+ uint256 script_hash;
+ CSHA256().Write(&r_script[0], r_script.size()).Finalize(script_hash.begin());
+ r_script.clear();
+ r_script << OP_0 << ToByteVector(script_hash);
+ }
+ return r_script;
+}
+
+uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return fuzzed_data_provider.ConsumeBool() ?
+ fuzzed_data_provider.PickValueInArray({
+ CTxIn::SEQUENCE_FINAL,
+ CTxIn::SEQUENCE_FINAL - 1,
+ MAX_BIP125_RBF_SEQUENCE,
+ }) :
+ fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index cdddad82b3..d5c54911c5 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -48,6 +48,16 @@ void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
return ((i++ == call_index ? callables() : void()), ...);
}
+template <typename Collection>
+auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
+{
+ const auto sz = col.size();
+ assert(sz >= 1);
+ auto it = col.begin();
+ std::advance(it, fuzzed_data_provider.ConsumeIntegralInRange<decltype(sz)>(0, sz - 1));
+ return *it;
+}
+
[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
@@ -125,11 +135,13 @@ template <typename WeakEnumType, size_t size>
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
}
-[[nodiscard]] inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- return {b.begin(), b.end()};
-}
+[[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
+
+[[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept;
+
+[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096, const bool maybe_p2wsh = false) noexcept;
+
+[[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
[[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
index a898e2782d..88c1a1a9cb 100644
--- a/src/test/fuzz/versionbits.cpp
+++ b/src/test/fuzz/versionbits.cpp
@@ -25,18 +25,18 @@ private:
const Consensus::Params dummy_params{};
public:
- const int64_t m_begin = 0;
- const int64_t m_end = 0;
- const int m_period = 0;
- const int m_threshold = 0;
- const int m_bit = 0;
+ const int64_t m_begin;
+ const int64_t m_end;
+ const int m_period;
+ const int m_threshold;
+ const int m_bit;
TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int bit)
: m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_bit{bit}
{
assert(m_period > 0);
assert(0 <= m_threshold && m_threshold <= m_period);
- assert(0 <= m_bit && m_bit <= 32 && m_bit < VERSIONBITS_NUM_BITS);
+ assert(0 <= m_bit && m_bit < 32 && m_bit < VERSIONBITS_NUM_BITS);
}
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); }
@@ -49,9 +49,10 @@ public:
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); }
BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindexPrev, dummy_params); }
- bool Condition(int64_t version) const
+ bool Condition(int32_t version) const
{
- return ((version >> m_bit) & 1) != 0 && (version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS;
+ uint32_t mask = ((uint32_t)1) << m_bit;
+ return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0);
}
bool Condition(const CBlockIndex* pindex) const { return Condition(pindex->nVersion); }
@@ -94,18 +95,20 @@ public:
}
};
+std::unique_ptr<const CChainParams> g_params;
+
void initialize()
{
- SelectParams(CBaseChainParams::MAIN);
+ // this is actually comparatively slow, so only do it once
+ g_params = CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN);
+ assert(g_params != nullptr);
}
-} // namespace
-constexpr uint32_t MAX_TIME = 4102444800; // 2100-01-01
+constexpr uint32_t MAX_START_TIME = 4102444800; // 2100-01-01
FUZZ_TARGET_INIT(versionbits, initialize)
{
- const CChainParams& params = Params();
-
+ const CChainParams& params = *g_params;
const int64_t interval = params.GetConsensus().nPowTargetSpacing;
assert(interval > 1); // need to be able to halve it
assert(interval < std::numeric_limits<int32_t>::max());
@@ -122,9 +125,9 @@ FUZZ_TARGET_INIT(versionbits, initialize)
// too many blocks at 10min each might cause uint32_t time to overflow if
// block_start_time is at the end of the range above
- assert(std::numeric_limits<uint32_t>::max() - MAX_TIME > interval * max_blocks);
+ assert(std::numeric_limits<uint32_t>::max() - MAX_START_TIME > interval * max_blocks);
- const int64_t block_start_time = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(params.GenesisBlock().nTime, MAX_TIME);
+ const int64_t block_start_time = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(params.GenesisBlock().nTime, MAX_START_TIME);
// what values for version will we use to signal / not signal?
const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
@@ -173,8 +176,10 @@ FUZZ_TARGET_INIT(versionbits, initialize)
if (checker.Condition(ver_nosignal)) return;
if (ver_nosignal < 0) return;
- // TOP_BITS should ensure version will be positive
+ // TOP_BITS should ensure version will be positive and meet min
+ // version requirement
assert(ver_signal > 0);
+ assert(ver_signal >= VERSIONBITS_LAST_OLD_BLOCK_VERSION);
// Now that we have chosen time and versions, setup to mine blocks
Blocks blocks(block_start_time, interval, ver_signal, ver_nosignal);
@@ -203,7 +208,7 @@ FUZZ_TARGET_INIT(versionbits, initialize)
}
// don't risk exceeding max_blocks or times may wrap around
- if (blocks.size() + period*2 > max_blocks) break;
+ if (blocks.size() + 2 * period > max_blocks) break;
}
// NOTE: fuzzed_data_provider may be fully consumed at this point and should not be used further
@@ -316,7 +321,7 @@ FUZZ_TARGET_INIT(versionbits, initialize)
assert(false);
}
- if (blocks.size() >= max_periods * period) {
+ if (blocks.size() >= period * max_periods) {
// we chose the timeout (and block times) so that by the time we have this many blocks it's all over
assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED);
}
@@ -343,3 +348,4 @@ FUZZ_TARGET_INIT(versionbits, initialize)
}
}
}
+} // namespace
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index c336705d50..858b90b8b2 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -396,6 +396,60 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.SetSpecial("totally bogus"));
}
+BOOST_AUTO_TEST_CASE(cnetaddr_tostring_canonical_ipv6)
+{
+ // Test that CNetAddr::ToString formats IPv6 addresses with zero compression as described in
+ // RFC 5952 ("A Recommendation for IPv6 Address Text Representation").
+ const std::map<std::string, std::string> canonical_representations_ipv6{
+ {"0000:0000:0000:0000:0000:0000:0000:0000", "::"},
+ {"000:0000:000:00:0:00:000:0000", "::"},
+ {"000:000:000:000:000:000:000:000", "::"},
+ {"00:00:00:00:00:00:00:00", "::"},
+ {"0:0:0:0:0:0:0:0", "::"},
+ {"0:0:0:0:0:0:0:1", "::1"},
+ {"2001:0:0:1:0:0:0:1", "2001:0:0:1::1"},
+ {"2001:0db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"},
+ {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:db8:85a3::8a2e:370:7334"},
+ {"2001:0db8::0001", "2001:db8::1"},
+ {"2001:0db8::0001:0000", "2001:db8::1:0"},
+ {"2001:0db8::1:0:0:1", "2001:db8::1:0:0:1"},
+ {"2001:db8:0000:0:1::1", "2001:db8::1:0:0:1"},
+ {"2001:db8:0000:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
+ {"2001:db8:0:0:0:0:2:1", "2001:db8::2:1"},
+ {"2001:db8:0:0:0::1", "2001:db8::1"},
+ {"2001:db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"},
+ {"2001:db8:0:0:1::1", "2001:db8::1:0:0:1"},
+ {"2001:DB8:0:0:1::1", "2001:db8::1:0:0:1"},
+ {"2001:db8:0:0::1", "2001:db8::1"},
+ {"2001:db8:0:0:aaaa::1", "2001:db8::aaaa:0:0:1"},
+ {"2001:db8:0:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
+ {"2001:db8:0::1", "2001:db8::1"},
+ {"2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334"},
+ {"2001:db8::0:1", "2001:db8::1"},
+ {"2001:db8::0:1:0:0:1", "2001:db8::1:0:0:1"},
+ {"2001:DB8::1", "2001:db8::1"},
+ {"2001:db8::1", "2001:db8::1"},
+ {"2001:db8::1:0:0:1", "2001:db8::1:0:0:1"},
+ {"2001:db8::1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
+ {"2001:db8::aaaa:0:0:1", "2001:db8::aaaa:0:0:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:0:1", "2001:db8:aaaa:bbbb:cccc:dddd:0:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd::1", "2001:db8:aaaa:bbbb:cccc:dddd:0:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
+ {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
+ };
+ for (const auto& [input_address, expected_canonical_representation_output] : canonical_representations_ipv6) {
+ CNetAddr net_addr;
+ BOOST_REQUIRE(LookupHost(input_address, net_addr, false));
+ BOOST_REQUIRE(net_addr.IsIPv6());
+ BOOST_CHECK_EQUAL(net_addr.ToString(), expected_canonical_representation_output);
+ }
+}
+
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
{
CNetAddr addr;
diff --git a/src/txmempool.h b/src/txmempool.h
index 9d4ea760e7..c3a9bd851d 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -476,7 +476,7 @@ enum class MemPoolRemovalReason {
*/
class CTxMemPool
{
-private:
+protected:
const int m_check_ratio; //!< Value n means that 1 times in n we check.
std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* minerPolicyEstimator;
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 4543f6fb4c..6a59bc2b38 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -76,7 +76,7 @@ bool VerifyWallets(interfaces::Chain& chain)
bilingual_str error_string;
if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
if (status == DatabaseStatus::FAILED_NOT_FOUND) {
- chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s\n", error_string.original)));
+ chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
} else {
chain.initError(error_string);
return false;