aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am9
-rw-r--r--src/Makefile.qt.include42
-rw-r--r--src/Makefile.qttest.include14
-rw-r--r--src/Makefile.test.include7
-rw-r--r--src/compat/byteswap.h9
-rw-r--r--src/consensus/tx_check.cpp19
-rw-r--r--src/consensus/tx_check.h2
-rw-r--r--src/httpserver.cpp1
-rw-r--r--src/init.cpp2
-rw-r--r--src/net.cpp7
-rw-r--r--src/qt/README.md2
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/clientmodel.cpp31
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/forms/openuridialog.ui22
-rw-r--r--src/qt/openuridialog.cpp9
-rw-r--r--src/qt/openuridialog.h3
-rw-r--r--src/qt/optionsmodel.cpp20
-rw-r--r--src/qt/optionsmodel.h5
-rw-r--r--src/qt/paymentrequest.proto48
-rw-r--r--src/qt/paymentrequestplus.cpp213
-rw-r--r--src/qt/paymentrequestplus.h52
-rw-r--r--src/qt/paymentserver.cpp553
-rw-r--r--src/qt/paymentserver.h55
-rw-r--r--src/qt/qrimagewidget.cpp1
-rw-r--r--src/qt/sendcoinsdialog.cpp14
-rw-r--r--src/qt/sendcoinsentry.cpp36
-rw-r--r--src/qt/test/compattests.cpp4
-rw-r--r--src/qt/test/paymentrequestdata.h465
-rw-r--r--src/qt/test/paymentservertests.cpp215
-rw-r--r--src/qt/test/paymentservertests.h35
-rw-r--r--src/qt/test/test_main.cpp9
-rw-r--r--src/qt/transactiondesc.cpp10
-rw-r--r--src/qt/utilitydialog.cpp3
-rw-r--r--src/qt/walletcontroller.cpp6
-rw-r--r--src/qt/walletmodel.cpp57
-rw-r--r--src/qt/walletmodel.h31
-rw-r--r--src/qt/walletmodeltransaction.cpp19
-rw-r--r--src/rpc/blockchain.cpp3
-rw-r--r--src/rpc/misc.cpp8
-rw-r--r--src/rpc/util.h13
-rw-r--r--src/test/compress_tests.cpp73
-rw-r--r--src/test/fuzz/script.cpp64
-rw-r--r--src/test/fuzz/transaction.cpp7
-rw-r--r--src/util/check.h41
-rw-r--r--src/validation.cpp10
47 files changed, 283 insertions, 1980 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d50524a8ae..82cc19d57c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,7 +19,7 @@ else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
-BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
@@ -206,6 +206,7 @@ BITCOIN_CORE_H = \
undo.h \
util/bip32.h \
util/bytevectorhash.h \
+ util/check.h \
util/error.h \
util/fees.h \
util/spanparsing.h \
@@ -701,12 +702,6 @@ if HARDEN
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
endif
-if ENABLE_BIP70
-%.pb.cc %.pb.h: %.proto
- @test -f $(PROTOC)
- $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(<D) $<
-endif
-
if EMBEDDED_LEVELDB
include Makefile.leveldb.include
endif
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 9ab7f02e22..13b1470b58 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -95,16 +95,6 @@ QT_QRC = qt/bitcoin.qrc
QT_QRC_LOCALE_CPP = qt/qrc_bitcoin_locale.cpp
QT_QRC_LOCALE = qt/bitcoin_locale.qrc
-if ENABLE_BIP70
-PROTOBUF_CC = qt/paymentrequest.pb.cc
-PROTOBUF_H = qt/paymentrequest.pb.h
-PROTOBUF_PROTO = qt/paymentrequest.proto
-else
-PROTOBUF_CC =
-PROTOBUF_H =
-PROTOBUF_PROTO =
-endif
-
BITCOIN_QT_H = \
qt/addressbookpage.h \
qt/addresstablemodel.h \
@@ -134,7 +124,6 @@ BITCOIN_QT_H = \
qt/optionsdialog.h \
qt/optionsmodel.h \
qt/overviewpage.h \
- qt/paymentrequestplus.h \
qt/paymentserver.h \
qt/peertablemodel.h \
qt/platformstyle.h \
@@ -269,18 +258,12 @@ BITCOIN_QT_WALLET_CPP = \
qt/walletmodeltransaction.cpp \
qt/walletview.cpp
-BITCOIN_QT_WALLET_BIP70_CPP = \
- qt/paymentrequestplus.cpp
-
BITCOIN_QT_CPP = $(BITCOIN_QT_BASE_CPP)
if TARGET_WINDOWS
BITCOIN_QT_CPP += $(BITCOIN_QT_WINDOWS_CPP)
endif
if ENABLE_WALLET
BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP)
-if ENABLE_BIP70
-BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_BIP70_CPP)
-endif # ENABLE_BIP70
endif # ENABLE_WALLET
RES_IMAGES =
@@ -292,18 +275,17 @@ BITCOIN_RC = qt/res/bitcoin-qt-res.rc
BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS
qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
+ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS)
qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
- $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
+ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
if TARGET_DARWIN
qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM)
endif
-nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
- $(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
+nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
# forms/foo.h -> forms/ui_foo.h
QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h))))
@@ -313,14 +295,9 @@ QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:
$(QT_MOC): $(QT_FORMS_H)
$(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) : | $(QT_MOC)
-#Generating these with a half-written protobuf header leads to wacky results.
-#This makes sure it's done.
-$(QT_MOC): $(PROTOBUF_H)
-$(QT_MOC_CPP): $(PROTOBUF_H)
-
# bitcoin-qt binary #
qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
+ $(QT_INCLUDES) $(QR_CFLAGS)
qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
qt_bitcoin_qt_SOURCES = qt/main.cpp
@@ -335,15 +312,8 @@ if ENABLE_ZMQ
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
-if ENABLE_BIP70
-qt_bitcoin_qt_LDADD += $(SSL_LIBS)
-else
-if TARGET_WINDOWS
-qt_bitcoin_qt_LDADD += $(SSL_LIBS)
-endif
-endif
qt_bitcoin_qt_LDADD += $(CRYPTO_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX
@@ -368,7 +338,7 @@ $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM)
$(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
@rm $(@D)/temp_$(<F)
-$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H)
+$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
@test -f $(RCC)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin $< | \
$(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 4acfff809e..c309340fd7 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -15,10 +15,6 @@ if ENABLE_WALLET
TEST_QT_MOC_CPP += \
qt/test/moc_addressbooktests.cpp \
qt/test/moc_wallettests.cpp
-if ENABLE_BIP70
-TEST_QT_MOC_CPP += \
- qt/test/moc_paymentservertests.cpp
-endif # ENABLE_BIP70
endif # ENABLE_WALLET
TEST_QT_H = \
@@ -28,8 +24,6 @@ TEST_QT_H = \
qt/test/rpcnestedtests.h \
qt/test/uritests.h \
qt/test/util.h \
- qt/test/paymentrequestdata.h \
- qt/test/paymentservertests.h \
qt/test/wallettests.h
TEST_BITCOIN_CPP = \
@@ -39,7 +33,7 @@ TEST_BITCOIN_H = \
test/setup_common.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
+ $(QT_INCLUDES) $(QT_TEST_INCLUDES)
qt_test_test_bitcoin_qt_SOURCES = \
qt/test/apptests.cpp \
@@ -56,10 +50,6 @@ qt_test_test_bitcoin_qt_SOURCES += \
qt/test/addressbooktests.cpp \
qt/test/wallettests.cpp \
wallet/test/wallet_test_fixture.cpp
-if ENABLE_BIP70
-qt_test_test_bitcoin_qt_SOURCES += \
- qt/test/paymentservertests.cpp
-endif # ENABLE_BIP70
endif # ENABLE_WALLET
nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
@@ -73,7 +63,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(QR_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 4d78ea95ed..019e832cc6 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -22,6 +22,7 @@ FUZZ_TARGETS = \
test/fuzz/inv_deserialize \
test/fuzz/messageheader_deserialize \
test/fuzz/netaddr_deserialize \
+ test/fuzz/script \
test/fuzz/script_flags \
test/fuzz/service_deserialize \
test/fuzz/spanparsing \
@@ -268,6 +269,12 @@ test_fuzz_netaddr_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_netaddr_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_netaddr_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_script_SOURCES = $(FUZZ_SUITE) test/fuzz/script.cpp
+test_fuzz_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_script_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_LDADD = $(FUZZ_SUITE_LD_COMMON)
+
test_fuzz_script_flags_SOURCES = $(FUZZ_SUITE) test/fuzz/script_flags.cpp
test_fuzz_script_flags_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_flags_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index fe47f4899f..c254fe7cbf 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -17,20 +17,13 @@
#if defined(MAC_OSX)
-#if !defined(bswap_16)
-
-// Mac OS X / Darwin features; we include a check for bswap_16 because if it is already defined, protobuf has
-// defined these macros for us already; if it isn't, we do it ourselves. In either case, we get the exact same
-// result regardless which path was taken
#include <libkern/OSByteOrder.h>
#define bswap_16(x) OSSwapInt16(x)
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)
-#endif // !defined(bswap_16)
-
#else
-// Non-Mac OS X / non-Darwin
+// Non-MacOS / non-Darwin
#if HAVE_DECL_BSWAP_16 == 0
inline uint16_t bswap_16(uint16_t x)
diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp
index 1206035839..6793f871cf 100644
--- a/src/consensus/tx_check.cpp
+++ b/src/consensus/tx_check.cpp
@@ -7,7 +7,7 @@
#include <primitives/transaction.h>
#include <consensus/validation.h>
-bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
+bool CheckTransaction(const CTransaction& tx, CValidationState& state)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
@@ -31,14 +31,15 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge");
}
- // Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
- if (fCheckDuplicateInputs) {
- std::set<COutPoint> vInOutPoints;
- for (const auto& txin : tx.vin)
- {
- if (!vInOutPoints.insert(txin.prevout).second)
- return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
- }
+ // Check for duplicate inputs (see CVE-2018-17144)
+ // While Consensus::CheckTxInputs does check if all inputs of a tx are available, and UpdateCoins marks all inputs
+ // of a tx as spent, it does not check if the tx has duplicate inputs.
+ // Failure to run this check will result in either a crash or an inflation bug, depending on the implementation of
+ // the underlying coins database.
+ std::set<COutPoint> vInOutPoints;
+ for (const auto& txin : tx.vin) {
+ if (!vInOutPoints.insert(txin.prevout).second)
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
}
if (tx.IsCoinBase())
diff --git a/src/consensus/tx_check.h b/src/consensus/tx_check.h
index bcfdf36bf9..6f3f8fe969 100644
--- a/src/consensus/tx_check.h
+++ b/src/consensus/tx_check.h
@@ -15,6 +15,6 @@
class CTransaction;
class CValidationState;
-bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
+bool CheckTransaction(const CTransaction& tx, CValidationState& state);
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 8113777187..d9c7113323 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -15,6 +15,7 @@
#include <sync.h>
#include <ui_interface.h>
+#include <deque>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/init.cpp b/src/init.cpp
index 035725b090..da4d322669 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -354,7 +354,7 @@ void SetupServerArgs()
std::vector<std::string> hidden_args = {
"-dbcrashratio", "-forcecompactdb",
// GUI args. These will be overwritten by SetupUIArgs for the GUI
- "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"};
+ "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-splash", "-uiplatform"};
gArgs.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#if HAVE_SYSTEM
diff --git a/src/net.cpp b/src/net.cpp
index c1c70facf4..c0b39925c6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1361,7 +1361,7 @@ void CConnman::SocketHandler()
{
// socket closed gracefully
if (!pnode->fDisconnect) {
- LogPrint(BCLog::NET, "socket closed\n");
+ LogPrint(BCLog::NET, "socket closed for peer=%d\n", pnode->GetId());
}
pnode->CloseSocketDisconnect();
}
@@ -1371,8 +1371,9 @@ void CConnman::SocketHandler()
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
- if (!pnode->fDisconnect)
- LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
+ if (!pnode->fDisconnect) {
+ LogPrint(BCLog::NET, "socket recv error for peer=%d: %s\n", pnode->GetId(), NetworkErrorString(nErr));
+ }
pnode->CloseSocketDisconnect();
}
}
diff --git a/src/qt/README.md b/src/qt/README.md
index 0eb18f7cd5..30c68db15b 100644
--- a/src/qt/README.md
+++ b/src/qt/README.md
@@ -50,7 +50,7 @@ Various dialogs, e.g. to open a URL. Inherit from [QDialog](https://doc.qt.io/qt
### paymentserver.(h/cpp)
-Used to process BIP21 and BIP70 (see https://github.com/bitcoin/bitcoin/pull/11622) payment URI / requests. Also handles URI based application switching (e.g. when following a bitcoin:... link from a browser).
+Used to process BIP21 payment URI requests. Also handles URI based application switching (e.g. when following a bitcoin:... link from a browser).
### walletview.(h/cpp)
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index f548dc9fe3..02a2a01bdd 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -337,10 +337,6 @@ void BitcoinApplication::initializeResult(bool success)
window->setWalletController(m_wallet_controller);
if (paymentServer) {
paymentServer->setOptionsModel(optionsModel);
-#ifdef ENABLE_BIP70
- PaymentServer::LoadRootCAs();
- connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK);
-#endif
}
}
#endif // ENABLE_WALLET
@@ -396,14 +392,10 @@ WId BitcoinApplication::getMainWinId() const
static void SetupUIArgs()
{
-#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
- gArgs.AddArg("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::GUI);
-#endif
gArgs.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
gArgs.AddArg("-lang=<lang>", "Set language, for example \"de_DE\" (default: system locale)", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
gArgs.AddArg("-min", "Start minimized", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
gArgs.AddArg("-resetguisettings", "Reset all settings changed in the GUI", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
- gArgs.AddArg("-rootcertificates=<file>", "Set SSL root certificates for payment request (default: -system-)", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
gArgs.AddArg("-splash", strprintf("Show splash screen on startup (default: %u)", DEFAULT_SPLASHSCREEN), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
gArgs.AddArg("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::GUI);
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index b280a0c14f..2aeba6d82c 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -330,7 +330,7 @@ void BitcoinGUI::createActions()
usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
openAction = new QAction(tr("Open &URI..."), this);
- openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
+ openAction->setStatusTip(tr("Open a bitcoin: URI"));
m_open_wallet_action = new QAction(tr("Open Wallet"), this);
m_open_wallet_action->setEnabled(false);
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 238be08480..5b216b2705 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <QDebug>
+#include <QThread>
#include <QTimer>
static int64_t nLastHeaderTipUpdateNotification = 0;
@@ -30,15 +31,26 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO
optionsModel(_optionsModel),
peerTableModel(nullptr),
banTableModel(nullptr),
- pollTimer(nullptr)
+ m_thread(new QThread(this))
{
cachedBestHeaderHeight = -1;
cachedBestHeaderTime = -1;
peerTableModel = new PeerTableModel(m_node, this);
banTableModel = new BanTableModel(m_node, this);
- pollTimer = new QTimer(this);
- connect(pollTimer, &QTimer::timeout, this, &ClientModel::updateTimer);
- pollTimer->start(MODEL_UPDATE_DELAY);
+
+ QTimer* timer = new QTimer;
+ timer->setInterval(MODEL_UPDATE_DELAY);
+ connect(timer, &QTimer::timeout, [this] {
+ // no locking required at this point
+ // the following calls will acquire the required lock
+ Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage());
+ Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent());
+ });
+ connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
+ connect(m_thread, &QThread::started, [timer] { timer->start(); });
+ // move timer to thread so that polling doesn't disturb main event loop
+ timer->moveToThread(m_thread);
+ m_thread->start();
subscribeToCoreSignals();
}
@@ -46,6 +58,9 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO
ClientModel::~ClientModel()
{
unsubscribeFromCoreSignals();
+
+ m_thread->quit();
+ m_thread->wait();
}
int ClientModel::getNumConnections(unsigned int flags) const
@@ -90,14 +105,6 @@ int64_t ClientModel::getHeaderTipTime() const
return cachedBestHeaderTime;
}
-void ClientModel::updateTimer()
-{
- // no locking required at this point
- // the following calls will acquire the required lock
- Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage());
- Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent());
-}
-
void ClientModel::updateNumConnections(int numConnections)
{
Q_EMIT numConnectionsChanged(numConnections);
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 95f4521f06..d3a95d531e 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -90,7 +90,8 @@ private:
PeerTableModel *peerTableModel;
BanTableModel *banTableModel;
- QTimer *pollTimer;
+ //! A thread to interact with m_node asynchronously
+ QThread* const m_thread;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
@@ -110,7 +111,6 @@ Q_SIGNALS:
void showProgress(const QString &title, int nProgress);
public Q_SLOTS:
- void updateTimer();
void updateNumConnections(int numConnections);
void updateNetworkActive(bool networkActive);
void updateAlert();
diff --git a/src/qt/forms/openuridialog.ui b/src/qt/forms/openuridialog.ui
index 0e1048bc07..2acec314fd 100644
--- a/src/qt/forms/openuridialog.ui
+++ b/src/qt/forms/openuridialog.ui
@@ -11,17 +11,10 @@
</rect>
</property>
<property name="windowTitle">
- <string>Open URI</string>
+ <string>Open bitcoin URI</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Open payment request from URI or file</string>
- </property>
- </widget>
- </item>
- <item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
@@ -33,19 +26,6 @@
<item>
<widget class="QValidatedLineEdit" name="uriEdit"/>
</item>
- <item>
- <widget class="QPushButton" name="selectFileButton">
- <property name="toolTip">
- <string>Select payment request file</string>
- </property>
- <property name="text">
- <string notr="true">…</string>
- </property>
- <property name="autoDefault">
- <bool>false</bool>
- </property>
- </widget>
- </item>
</layout>
</item>
<item>
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 48db95679f..199804f84d 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -39,12 +39,3 @@ void OpenURIDialog::accept()
ui->uriEdit->setValid(false);
}
}
-
-void OpenURIDialog::on_selectFileButton_clicked()
-{
- QString filename = GUIUtil::getOpenFileName(this, tr("Select payment request file to open"), "", "", nullptr);
- if(filename.isEmpty())
- return;
- QUrl fileUri = QUrl::fromLocalFile(filename);
- ui->uriEdit->setText("bitcoin:?r=" + QUrl::toPercentEncoding(fileUri.toString()));
-}
diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h
index e94593d5bb..8438f22bd7 100644
--- a/src/qt/openuridialog.h
+++ b/src/qt/openuridialog.h
@@ -24,9 +24,6 @@ public:
protected Q_SLOTS:
void accept();
-private Q_SLOTS:
- void on_selectFileButton_clicked();
-
private:
Ui::OpenURIDialog *ui;
};
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d047a82475..d74d0dbfeb 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -18,7 +18,7 @@
#include <netbase.h>
#include <txdb.h> // for -dbcache defaults
-#include <QNetworkProxy>
+#include <QDebug>
#include <QSettings>
#include <QStringList>
@@ -483,24 +483,6 @@ void OptionsModel::setDisplayUnit(const QVariant &value)
}
}
-bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
-{
- // Directly query current base proxy, because
- // GUI settings can be overridden with -proxy.
- proxyType curProxy;
- if (m_node.getProxy(NET_IPV4, curProxy)) {
- proxy.setType(QNetworkProxy::Socks5Proxy);
- proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP()));
- proxy.setPort(curProxy.proxy.GetPort());
-
- return true;
- }
- else
- proxy.setType(QNetworkProxy::NoProxy);
-
- return false;
-}
-
void OptionsModel::setRestartRequired(bool fRequired)
{
QSettings settings;
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index b1231b7c7d..5791b47f28 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -13,10 +13,6 @@ namespace interfaces {
class Node;
}
-QT_BEGIN_NAMESPACE
-class QNetworkProxy;
-QT_END_NAMESPACE
-
extern const char *DEFAULT_GUI_PROXY_HOST;
static constexpr unsigned short DEFAULT_GUI_PROXY_PORT = 9050;
@@ -73,7 +69,6 @@ public:
bool getMinimizeOnClose() const { return fMinimizeOnClose; }
int getDisplayUnit() const { return nDisplayUnit; }
QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; }
- bool getProxySettings(QNetworkProxy& proxy) const;
bool getCoinControlFeatures() const { return fCoinControlFeatures; }
const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; }
diff --git a/src/qt/paymentrequest.proto b/src/qt/paymentrequest.proto
deleted file mode 100644
index d2721a34bd..0000000000
--- a/src/qt/paymentrequest.proto
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Simple Bitcoin Payment Protocol messages
-//
-// Use fields 100+ for extensions;
-// to avoid conflicts, register extensions at:
-// https://en.bitcoin.it/wiki/Payment_Request
-//
-
-syntax = "proto2";
-
-package payments;
-option java_package = "org.bitcoin.protocols.payments";
-option java_outer_classname = "Protos";
-
-// Generalized form of "send payment to this/these bitcoin addresses"
-message Output {
- optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
- required bytes script = 2; // usually one of the standard Script forms
-}
-message PaymentDetails {
- optional string network = 1 [default = "main"]; // "main" or "test"
- repeated Output outputs = 2; // Where payment should be sent
- required uint64 time = 3; // Timestamp; when payment request created
- optional uint64 expires = 4; // Timestamp; when this request should be considered invalid
- optional string memo = 5; // Human-readable description of request for the customer
- optional string payment_url = 6; // URL to send Payment and get PaymentACK
- optional bytes merchant_data = 7; // Arbitrary data to include in the Payment message
-}
-message PaymentRequest {
- optional uint32 payment_details_version = 1 [default = 1];
- optional string pki_type = 2 [default = "none"]; // none / x509+sha256 / x509+sha1
- optional bytes pki_data = 3; // depends on pki_type
- required bytes serialized_payment_details = 4; // PaymentDetails
- optional bytes signature = 5; // pki-dependent signature
-}
-message X509Certificates {
- repeated bytes certificate = 1; // DER-encoded X.509 certificate chain
-}
-message Payment {
- optional bytes merchant_data = 1; // From PaymentDetails.merchant_data
- repeated bytes transactions = 2; // Signed transactions that satisfy PaymentDetails.outputs
- repeated Output refund_to = 3; // Where to send refunds, if a refund is necessary
- optional string memo = 4; // Human-readable message for the merchant
-}
-message PaymentACK {
- required Payment payment = 1; // Payment message that triggered this ACK
- optional string memo = 2; // human-readable message for customer
-}
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
deleted file mode 100644
index b962ab1ef2..0000000000
--- a/src/qt/paymentrequestplus.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-//
-// Wraps dumb protocol buffer paymentRequest
-// with some extra methods
-//
-
-#include <qt/paymentrequestplus.h>
-
-#include <util/system.h>
-
-#include <stdexcept>
-
-#include <openssl/x509_vfy.h>
-
-#include <QDateTime>
-#include <QDebug>
-#include <QSslCertificate>
-
-class SSLVerifyError : public std::runtime_error
-{
-public:
- explicit SSLVerifyError(std::string err) : std::runtime_error(err) { }
-};
-
-bool PaymentRequestPlus::parse(const QByteArray& data)
-{
- bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size());
- if (!parseOK) {
- qWarning() << "PaymentRequestPlus::parse: Error parsing payment request";
- return false;
- }
- if (paymentRequest.payment_details_version() > 1) {
- qWarning() << "PaymentRequestPlus::parse: Received up-version payment details, version=" << paymentRequest.payment_details_version();
- return false;
- }
-
- parseOK = details.ParseFromString(paymentRequest.serialized_payment_details());
- if (!parseOK)
- {
- qWarning() << "PaymentRequestPlus::parse: Error parsing payment details";
- paymentRequest.Clear();
- return false;
- }
- return true;
-}
-
-bool PaymentRequestPlus::SerializeToString(std::string* output) const
-{
- return paymentRequest.SerializeToString(output);
-}
-
-bool PaymentRequestPlus::IsInitialized() const
-{
- return paymentRequest.IsInitialized();
-}
-
-bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) const
-{
- merchant.clear();
-
- if (!IsInitialized())
- return false;
-
- // One day we'll support more PKI types, but just
- // x509 for now:
- const EVP_MD* digestAlgorithm = nullptr;
- if (paymentRequest.pki_type() == "x509+sha256") {
- digestAlgorithm = EVP_sha256();
- }
- else if (paymentRequest.pki_type() == "x509+sha1") {
- digestAlgorithm = EVP_sha1();
- }
- else if (paymentRequest.pki_type() == "none") {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: pki_type == none";
- return false;
- }
- else {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type());
- return false;
- }
-
- payments::X509Certificates certChain;
- if (!certChain.ParseFromString(paymentRequest.pki_data())) {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error parsing pki_data";
- return false;
- }
-
- std::vector<X509*> certs;
- const QDateTime currentTime = QDateTime::currentDateTime();
- for (int i = 0; i < certChain.certificate_size(); i++) {
- QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size());
- QSslCertificate qCert(certData, QSsl::Der);
- if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate expired or not yet active: " << qCert;
- return false;
- }
- if (qCert.isBlacklisted()) {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate blacklisted: " << qCert;
- return false;
- }
- const unsigned char *data = (const unsigned char *)certChain.certificate(i).data();
- X509 *cert = d2i_X509(nullptr, &data, certChain.certificate(i).size());
- if (cert)
- certs.push_back(cert);
- }
- if (certs.empty()) {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: empty certificate chain";
- return false;
- }
-
- // The first cert is the signing cert, the rest are untrusted certs that chain
- // to a valid root authority. OpenSSL needs them separately.
- STACK_OF(X509) *chain = sk_X509_new_null();
- for (int i = certs.size() - 1; i > 0; i--) {
- sk_X509_push(chain, certs[i]);
- }
- X509 *signing_cert = certs[0];
-
- // Now create a "store context", which is a single use object for checking,
- // load the signing cert into it and verify.
- X509_STORE_CTX *store_ctx = X509_STORE_CTX_new();
- if (!store_ctx) {
- qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error creating X509_STORE_CTX";
- return false;
- }
-
- char *website = nullptr;
- bool fResult = true;
- try
- {
- if (!X509_STORE_CTX_init(store_ctx, certStore, signing_cert, chain))
- {
- int error = X509_STORE_CTX_get_error(store_ctx);
- throw SSLVerifyError(X509_verify_cert_error_string(error));
- }
-
- // Now do the verification!
- int result = X509_verify_cert(store_ctx);
- if (result != 1) {
- int error = X509_STORE_CTX_get_error(store_ctx);
- // For testing payment requests, we allow self signed root certs!
- if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && gArgs.GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) {
- throw SSLVerifyError(X509_verify_cert_error_string(error));
- } else {
- qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true.";
- }
- }
- X509_NAME *certname = X509_get_subject_name(signing_cert);
-
- // Valid cert; check signature:
- payments::PaymentRequest rcopy(paymentRequest); // Copy
- rcopy.set_signature(std::string(""));
- std::string data_to_verify; // Everything but the signature
- rcopy.SerializeToString(&data_to_verify);
-
-#if HAVE_DECL_EVP_MD_CTX_NEW
- EVP_MD_CTX *ctx = EVP_MD_CTX_new();
- if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context.");
-#else
- EVP_MD_CTX _ctx;
- EVP_MD_CTX *ctx;
- ctx = &_ctx;
-#endif
- EVP_PKEY *pubkey = X509_get_pubkey(signing_cert);
- EVP_MD_CTX_init(ctx);
- if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, nullptr) ||
- !EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) ||
- !EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) {
- throw SSLVerifyError("Bad signature, invalid payment request.");
- }
-#if HAVE_DECL_EVP_MD_CTX_NEW
- EVP_MD_CTX_free(ctx);
-#endif
-
- // OpenSSL API for getting human printable strings from certs is baroque.
- int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, nullptr, 0);
- website = new char[textlen + 1];
- if (X509_NAME_get_text_by_NID(certname, NID_commonName, website, textlen + 1) == textlen && textlen > 0) {
- merchant = website;
- }
- else {
- throw SSLVerifyError("Bad certificate, missing common name.");
- }
- // TODO: detect EV certificates and set merchant = business name instead of unfriendly NID_commonName ?
- }
- catch (const SSLVerifyError& err) {
- fResult = false;
- qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what();
- }
-
- delete[] website;
- X509_STORE_CTX_free(store_ctx);
- for (unsigned int i = 0; i < certs.size(); i++)
- X509_free(certs[i]);
-
- return fResult;
-}
-
-QList<std::pair<CScript,CAmount> > PaymentRequestPlus::getPayTo() const
-{
- QList<std::pair<CScript,CAmount> > result;
- for (int i = 0; i < details.outputs_size(); i++)
- {
- const unsigned char* scriptStr = (const unsigned char*)details.outputs(i).script().data();
- CScript s(scriptStr, scriptStr+details.outputs(i).script().size());
-
- result.append(std::make_pair(s, details.outputs(i).amount()));
- }
- return result;
-}
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
deleted file mode 100644
index 3014628807..0000000000
--- a/src/qt/paymentrequestplus.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2011-2018 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_PAYMENTREQUESTPLUS_H
-#define BITCOIN_QT_PAYMENTREQUESTPLUS_H
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#include <qt/paymentrequest.pb.h>
-#pragma GCC diagnostic pop
-
-#include <amount.h>
-#include <script/script.h>
-
-#include <openssl/x509.h>
-
-#include <QByteArray>
-#include <QList>
-#include <QString>
-
-static const bool DEFAULT_SELFSIGNED_ROOTCERTS = false;
-
-//
-// Wraps dumb protocol buffer paymentRequest
-// with extra methods
-//
-
-class PaymentRequestPlus
-{
-public:
- PaymentRequestPlus() { }
-
- bool parse(const QByteArray& data);
- bool SerializeToString(std::string* output) const;
-
- bool IsInitialized() const;
- // Returns true if merchant's identity is authenticated, and
- // returns human-readable merchant identity in merchant
- bool getMerchant(X509_STORE* certStore, QString& merchant) const;
-
- // Returns list of outputs, amount
- QList<std::pair<CScript,CAmount> > getPayTo() const;
-
- const payments::PaymentDetails& getDetails() const { return details; }
-
-private:
- payments::PaymentRequest paymentRequest;
- payments::PaymentDetails details;
-};
-
-#endif // BITCOIN_QT_PAYMENTREQUESTPLUS_H
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 806cc3c41e..6ad219ca2d 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -23,8 +23,6 @@
#include <cstdlib>
#include <memory>
-#include <openssl/x509_vfy.h>
-
#include <QApplication>
#include <QByteArray>
#include <QDataStream>
@@ -36,28 +34,11 @@
#include <QList>
#include <QLocalServer>
#include <QLocalSocket>
-#include <QNetworkAccessManager>
-#include <QNetworkProxy>
-#include <QNetworkReply>
-#include <QNetworkRequest>
-#include <QSslCertificate>
-#include <QSslConfiguration>
-#include <QSslError>
#include <QStringList>
-#include <QTextDocument>
#include <QUrlQuery>
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
-#ifdef ENABLE_BIP70
-// BIP70 payment protocol messages
-const char* BIP70_MESSAGE_PAYMENTACK = "PaymentACK";
-const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
-// BIP71 payment protocol media types
-const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
-const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
-const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
-#endif
//
// Create a name that is unique for:
@@ -125,32 +106,6 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char*
}
}
}
-#ifdef ENABLE_BIP70
- else if (QFile::exists(arg)) // Filename
- {
- if (savedPaymentRequests.contains(arg)) continue;
- savedPaymentRequests.insert(arg);
-
- PaymentRequestPlus request;
- if (readPaymentRequestFromFile(arg, request))
- {
- if (request.getDetails().network() == "main")
- {
- node.selectParams(CBaseChainParams::MAIN);
- }
- else if (request.getDetails().network() == "test")
- {
- node.selectParams(CBaseChainParams::TESTNET);
- }
- }
- }
- else
- {
- // Printing to debug.log is about the best we can do here, the
- // GUI hasn't started yet so we can't pop up a message box.
- qWarning() << "PaymentServer::ipcSendCommandLine: Payment request file does not exist: " << arg;
- }
-#endif
}
}
@@ -198,16 +153,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
saveURIs(true),
uriServer(nullptr),
optionsModel(nullptr)
-#ifdef ENABLE_BIP70
- ,netManager(nullptr)
-#endif
{
-#ifdef ENABLE_BIP70
- // Verify that the version of the library that we linked against is
- // compatible with the version of the headers we compiled against.
- GOOGLE_PROTOBUF_VERIFY_VERSION;
-#endif
-
// Install global event filter to catch QFileOpenEvents
// on Mac: sent when you click bitcoin: links
// other OSes: helpful when dealing with payment request files
@@ -230,24 +176,16 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
}
else {
connect(uriServer, &QLocalServer::newConnection, this, &PaymentServer::handleURIConnection);
-#ifdef ENABLE_BIP70
- connect(this, &PaymentServer::receivedPaymentACK, this, &PaymentServer::handlePaymentACK);
-#endif
}
}
}
PaymentServer::~PaymentServer()
{
-#ifdef ENABLE_BIP70
- google::protobuf::ShutdownProtobufLibrary();
-#endif
}
//
-// OSX-specific way of handling bitcoin: URIs and PaymentRequest mime types.
-// Also used by paymentservertests.cpp and when opening a payment request file
-// via "Open URI..." menu entry.
+// OSX-specific way of handling bitcoin: URIs
//
bool PaymentServer::eventFilter(QObject *object, QEvent *event)
{
@@ -266,10 +204,6 @@ bool PaymentServer::eventFilter(QObject *object, QEvent *event)
void PaymentServer::uiReady()
{
-#ifdef ENABLE_BIP70
- initNetManager();
-#endif
-
saveURIs = false;
for (const QString& s : savedPaymentRequests)
{
@@ -294,48 +228,19 @@ void PaymentServer::handleURIOrFile(const QString& s)
else if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI
{
QUrlQuery uri((QUrl(s)));
-#ifdef ENABLE_BIP70
- if (uri.hasQueryItem("r")) // payment request URI
- {
- Q_EMIT message(tr("URI handling"),
- tr("You are using a BIP70 URL which will be unsupported in the future."),
- CClientUIInterface::ICON_WARNING);
- QByteArray temp;
- temp.append(uri.queryItemValue("r"));
- QString decoded = QUrl::fromPercentEncoding(temp);
- QUrl fetchUrl(decoded, QUrl::StrictMode);
-
- if (fetchUrl.isValid())
- {
- qDebug() << "PaymentServer::handleURIOrFile: fetchRequest(" << fetchUrl << ")";
- fetchRequest(fetchUrl);
- }
- else
- {
- qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl;
- Q_EMIT message(tr("URI handling"),
- tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
- CClientUIInterface::ICON_WARNING);
- }
- return;
- }
- else
-#endif
// normal URI
{
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
{
if (!IsValidDestinationString(recipient.address.toStdString())) {
-#ifndef ENABLE_BIP70
if (uri.hasQueryItem("r")) { // payment request
Q_EMIT message(tr("URI handling"),
- tr("Cannot process payment request because BIP70 support was not compiled in.")+
+ 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."),
CClientUIInterface::ICON_WARNING);
}
-#endif
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
@@ -353,26 +258,11 @@ void PaymentServer::handleURIOrFile(const QString& s)
if (QFile::exists(s)) // payment request file
{
-#ifdef ENABLE_BIP70
- PaymentRequestPlus request;
- SendCoinsRecipient recipient;
- if (!readPaymentRequestFromFile(s, request))
- {
- Q_EMIT message(tr("Payment request file handling"),
- tr("Payment request file cannot be read! This can be caused by an invalid payment request file."),
- CClientUIInterface::ICON_WARNING);
- }
- else if (processPaymentRequest(request, recipient))
- Q_EMIT receivedPaymentRequest(recipient);
-
- return;
-#else
Q_EMIT message(tr("Payment request file handling"),
- tr("Cannot process payment request because BIP70 support was not compiled in.")+
+ 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."),
CClientUIInterface::ICON_WARNING);
-#endif
}
}
@@ -400,440 +290,3 @@ void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
{
this->optionsModel = _optionsModel;
}
-
-#ifdef ENABLE_BIP70
-struct X509StoreDeleter {
- void operator()(X509_STORE* b) {
- X509_STORE_free(b);
- }
-};
-
-struct X509Deleter {
- void operator()(X509* b) { X509_free(b); }
-};
-
-namespace // Anon namespace
-{
- std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
-}
-
-static void ReportInvalidCertificate(const QSslCertificate& cert)
-{
- qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
-}
-
-//
-// Load OpenSSL's list of root certificate authorities
-//
-void PaymentServer::LoadRootCAs(X509_STORE* _store)
-{
- // Unit tests mostly use this, to pass in fake root CAs:
- if (_store)
- {
- certStore.reset(_store);
- return;
- }
-
- // Normal execution, use either -rootcertificates or system certs:
- certStore.reset(X509_STORE_new());
-
- // Note: use "-system-" default here so that users can pass -rootcertificates=""
- // and get 'I don't like X.509 certificates, don't trust anybody' behavior:
- QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
-
- // Empty store
- if (certFile.isEmpty()) {
- qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
- return;
- }
-
- QList<QSslCertificate> certList;
-
- if (certFile != "-system-") {
- qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
-
- certList = QSslCertificate::fromPath(certFile);
- // Use those certificates when fetching payment requests, too:
- QSslConfiguration::defaultConfiguration().setCaCertificates(certList);
- } else
- certList = QSslConfiguration::systemCaCertificates();
-
- int nRootCerts = 0;
- const QDateTime currentTime = QDateTime::currentDateTime();
-
- for (const QSslCertificate& cert : certList) {
- // Don't log NULL certificates
- if (cert.isNull())
- continue;
-
- // Not yet active/valid, or expired certificate
- if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
- ReportInvalidCertificate(cert);
- continue;
- }
-
- // Blacklisted certificate
- if (cert.isBlacklisted()) {
- ReportInvalidCertificate(cert);
- continue;
- }
-
- QByteArray certData = cert.toDer();
- const unsigned char *data = (const unsigned char *)certData.data();
-
- std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
- if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
- {
- // Note: X509_STORE increases the reference count to the X509 object,
- // we still have to release our reference to it.
- ++nRootCerts;
- }
- else
- {
- ReportInvalidCertificate(cert);
- continue;
- }
- }
- qInfo() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
-
- // Project for another day:
- // Fetch certificate revocation lists, and add them to certStore.
- // Issues to consider:
- // performance (start a thread to fetch in background?)
- // privacy (fetch through tor/proxy so IP address isn't revealed)
- // would it be easier to just use a compiled-in blacklist?
- // or use Qt's blacklist?
- // "certificate stapling" with server-side caching is more efficient
-}
-
-void PaymentServer::initNetManager()
-{
- if (!optionsModel)
- return;
- delete netManager;
-
- // netManager is used to fetch paymentrequests given in bitcoin: URIs
- netManager = new QNetworkAccessManager(this);
-
- QNetworkProxy proxy;
-
- // Query active SOCKS5 proxy
- if (optionsModel->getProxySettings(proxy)) {
- netManager->setProxy(proxy);
-
- qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
- }
- else
- qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
-
- connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished);
- connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors);
-}
-
-//
-// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
-// so don't use "Q_EMIT message()", but "QMessageBox::"!
-//
-bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request)
-{
- QFile f(filename);
- if (!f.open(QIODevice::ReadOnly)) {
- qWarning() << QString("PaymentServer::%1: Failed to open %2").arg(__func__).arg(filename);
- return false;
- }
-
- // BIP70 DoS protection
- if (!verifySize(f.size())) {
- return false;
- }
-
- QByteArray data = f.readAll();
-
- return request.parse(data);
-}
-
-bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient)
-{
- if (!optionsModel)
- return false;
-
- if (request.IsInitialized()) {
- // Payment request network matches client network?
- if (!verifyNetwork(optionsModel->node(), request.getDetails())) {
- Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
- CClientUIInterface::MSG_ERROR);
-
- return false;
- }
-
- // Make sure any payment requests involved are still valid.
- // This is re-checked just before sending coins in WalletModel::sendCoins().
- if (verifyExpired(request.getDetails())) {
- Q_EMIT message(tr("Payment request rejected"), tr("Payment request expired."),
- CClientUIInterface::MSG_ERROR);
-
- return false;
- }
- } else {
- Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."),
- CClientUIInterface::MSG_ERROR);
-
- return false;
- }
-
- recipient.paymentRequest = request;
- recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
-
- request.getMerchant(certStore.get(), recipient.authenticatedMerchant);
-
- QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
- QStringList addresses;
-
- for (const std::pair<CScript, CAmount>& sendingTo : sendingTos) {
- // Extract and check destination addresses
- CTxDestination dest;
- if (ExtractDestination(sendingTo.first, dest)) {
- // Append destination address
- addresses.append(QString::fromStdString(EncodeDestination(dest)));
- }
- else if (!recipient.authenticatedMerchant.isEmpty()) {
- // Unauthenticated payment requests to custom bitcoin addresses are not supported
- // (there is no good way to tell the user where they are paying in a way they'd
- // have a chance of understanding).
- Q_EMIT message(tr("Payment request rejected"),
- tr("Unverified payment requests to custom payment scripts are unsupported."),
- CClientUIInterface::MSG_ERROR);
- return false;
- }
-
- // Bitcoin amounts are stored as (optional) uint64 in the protobuf messages (see paymentrequest.proto),
- // but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range
- // and no overflow has happened.
- if (!verifyAmount(sendingTo.second)) {
- Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
- return false;
- }
-
- // Extract and check amounts
- CTxOut txOut(sendingTo.second, sendingTo.first);
- if (IsDust(txOut, optionsModel->node().getDustRelayFee())) {
- Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
- .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
- CClientUIInterface::MSG_ERROR);
-
- return false;
- }
-
- recipient.amount += sendingTo.second;
- // Also verify that the final amount is still in a valid range after adding additional amounts.
- if (!verifyAmount(recipient.amount)) {
- Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
- return false;
- }
- }
- // Store addresses and format them to fit nicely into the GUI
- recipient.address = addresses.join("<br />");
-
- if (!recipient.authenticatedMerchant.isEmpty()) {
- qDebug() << "PaymentServer::processPaymentRequest: Secure payment request from " << recipient.authenticatedMerchant;
- }
- else {
- qDebug() << "PaymentServer::processPaymentRequest: Insecure payment request to " << addresses.join(", ");
- }
-
- return true;
-}
-
-void PaymentServer::fetchRequest(const QUrl& url)
-{
- QNetworkRequest netRequest;
- netRequest.setAttribute(QNetworkRequest::User, BIP70_MESSAGE_PAYMENTREQUEST);
- netRequest.setUrl(url);
- netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
- netRequest.setRawHeader("Accept", BIP71_MIMETYPE_PAYMENTREQUEST);
- netManager->get(netRequest);
-}
-
-void PaymentServer::fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction)
-{
- const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
- if (!details.has_payment_url())
- return;
-
- QNetworkRequest netRequest;
- netRequest.setAttribute(QNetworkRequest::User, BIP70_MESSAGE_PAYMENTACK);
- netRequest.setUrl(QString::fromStdString(details.payment_url()));
- netRequest.setHeader(QNetworkRequest::ContentTypeHeader, BIP71_MIMETYPE_PAYMENT);
- netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
- netRequest.setRawHeader("Accept", BIP71_MIMETYPE_PAYMENTACK);
-
- payments::Payment payment;
- payment.set_merchant_data(details.merchant_data());
- payment.add_transactions(transaction.data(), transaction.size());
-
- // Create a new refund address, or re-use:
- CTxDestination dest;
- const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
- if (walletModel->wallet().getNewDestination(change_type, "", dest)) {
- // BIP70 requests encode the scriptPubKey directly, so we are not restricted to address
- // types supported by the receiver. As a result, we choose the address format we also
- // use for change. Despite an actual payment and not change, this is a close match:
- // it's the output type we use subject to privacy issues, but not restricted by what
- // other software supports.
- std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
- walletModel->wallet().setAddressBook(dest, label, "refund");
-
- CScript s = GetScriptForDestination(dest);
- payments::Output* refund_to = payment.add_refund_to();
- refund_to->set_script(&s[0], s.size());
- } else {
- // This should never happen, because sending coins should have
- // just unlocked the wallet and refilled the keypool.
- qWarning() << "PaymentServer::fetchPaymentACK: Error getting refund key, refund_to not set";
- }
-
- int length = payment.ByteSize();
- netRequest.setHeader(QNetworkRequest::ContentLengthHeader, length);
- QByteArray serData(length, '\0');
- if (payment.SerializeToArray(serData.data(), length)) {
- netManager->post(netRequest, serData);
- }
- else {
- // This should never happen, either.
- qWarning() << "PaymentServer::fetchPaymentACK: Error serializing payment message";
- }
-}
-
-void PaymentServer::netRequestFinished(QNetworkReply* reply)
-{
- reply->deleteLater();
-
- // BIP70 DoS protection
- if (!verifySize(reply->size())) {
- Q_EMIT message(tr("Payment request rejected"),
- tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).")
- .arg(reply->request().url().toString())
- .arg(reply->size())
- .arg(BIP70_MAX_PAYMENTREQUEST_SIZE),
- CClientUIInterface::MSG_ERROR);
- return;
- }
-
- if (reply->error() != QNetworkReply::NoError) {
- QString msg = tr("Error communicating with %1: %2")
- .arg(reply->request().url().toString())
- .arg(reply->errorString());
-
- qWarning() << "PaymentServer::netRequestFinished: " << msg;
- Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
- return;
- }
-
- QByteArray data = reply->readAll();
-
- QString requestType = reply->request().attribute(QNetworkRequest::User).toString();
- if (requestType == BIP70_MESSAGE_PAYMENTREQUEST)
- {
- PaymentRequestPlus request;
- SendCoinsRecipient recipient;
- if (!request.parse(data))
- {
- qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request";
- Q_EMIT message(tr("Payment request error"),
- tr("Payment request cannot be parsed!"),
- CClientUIInterface::MSG_ERROR);
- }
- else if (processPaymentRequest(request, recipient))
- Q_EMIT receivedPaymentRequest(recipient);
-
- return;
- }
- else if (requestType == BIP70_MESSAGE_PAYMENTACK)
- {
- payments::PaymentACK paymentACK;
- if (!paymentACK.ParseFromArray(data.data(), data.size()))
- {
- QString msg = tr("Bad response from server %1")
- .arg(reply->request().url().toString());
-
- qWarning() << "PaymentServer::netRequestFinished: " << msg;
- Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
- }
- else
- {
- Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
- }
- }
-}
-
-void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError> &errs)
-{
- Q_UNUSED(reply);
-
- QString errString;
- for (const QSslError& err : errs) {
- qWarning() << "PaymentServer::reportSslErrors: " << err;
- errString += err.errorString() + "\n";
- }
- Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
-}
-
-void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
-{
- // currently we don't further process or store the paymentACK message
- Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
-}
-
-bool PaymentServer::verifyNetwork(interfaces::Node& node, const payments::PaymentDetails& requestDetails)
-{
- bool fVerified = requestDetails.network() == node.getNetwork();
- if (!fVerified) {
- qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".")
- .arg(__func__)
- .arg(QString::fromStdString(requestDetails.network()))
- .arg(QString::fromStdString(node.getNetwork()));
- }
- return fVerified;
-}
-
-bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails)
-{
- bool fVerified = (requestDetails.has_expires() && (int64_t)requestDetails.expires() < GetTime());
- if (fVerified) {
- const QString requestExpires = QString::fromStdString(FormatISO8601DateTime((int64_t)requestDetails.expires()));
- qWarning() << QString("PaymentServer::%1: Payment request expired \"%2\".")
- .arg(__func__)
- .arg(requestExpires);
- }
- return fVerified;
-}
-
-bool PaymentServer::verifySize(qint64 requestSize)
-{
- bool fVerified = (requestSize <= BIP70_MAX_PAYMENTREQUEST_SIZE);
- if (!fVerified) {
- qWarning() << QString("PaymentServer::%1: Payment request too large (%2 bytes, allowed %3 bytes).")
- .arg(__func__)
- .arg(requestSize)
- .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
- }
- return fVerified;
-}
-
-bool PaymentServer::verifyAmount(const CAmount& requestAmount)
-{
- bool fVerified = MoneyRange(requestAmount);
- if (!fVerified) {
- qWarning() << QString("PaymentServer::%1: Payment request amount out of allowed range (%2, allowed 0 - %3).")
- .arg(__func__)
- .arg(requestAmount)
- .arg(MAX_MONEY);
- }
- return fVerified;
-}
-
-X509_STORE* PaymentServer::getCertStore()
-{
- return certStore.get();
-}
-#endif
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 30b5bc3b6d..8b2533508d 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -36,9 +36,6 @@
#include <config/bitcoin-config.h>
#endif
-#ifdef ENABLE_BIP70
-#include <qt/paymentrequestplus.h>
-#endif
#include <qt/walletmodel.h>
#include <QObject>
@@ -50,15 +47,9 @@ QT_BEGIN_NAMESPACE
class QApplication;
class QByteArray;
class QLocalServer;
-class QNetworkAccessManager;
-class QNetworkReply;
-class QSslError;
class QUrl;
QT_END_NAMESPACE
-// BIP70 max payment request size in bytes (DoS protection)
-static const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
-
class PaymentServer : public QObject
{
Q_OBJECT
@@ -82,27 +73,6 @@ public:
// OptionsModel is used for getting proxy settings and display unit
void setOptionsModel(OptionsModel *optionsModel);
-#ifdef ENABLE_BIP70
- // Load root certificate authorities. Pass nullptr (default)
- // to read from the file specified in the -rootcertificates setting,
- // or, if that's not set, to use the system default root certificates.
- // If you pass in a store, you should not X509_STORE_free it: it will be
- // freed either at exit or when another set of CAs are loaded.
- static void LoadRootCAs(X509_STORE* store = nullptr);
-
- // Return certificate store
- static X509_STORE* getCertStore();
-
- // Verify that the payment request network matches the client network
- static bool verifyNetwork(interfaces::Node& node, const payments::PaymentDetails& requestDetails);
- // Verify if the payment request is expired
- static bool verifyExpired(const payments::PaymentDetails& requestDetails);
- // Verify the payment request size is valid as per BIP70
- static bool verifySize(qint64 requestSize);
- // Verify the payment request amount is valid
- static bool verifyAmount(const CAmount& requestAmount);
-#endif
-
Q_SIGNALS:
// Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient);
@@ -110,11 +80,6 @@ Q_SIGNALS:
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
-#ifdef ENABLE_BIP70
- // Fired when a valid PaymentACK is received
- void receivedPaymentACK(const QString &paymentACKMsg);
-#endif
-
public Q_SLOTS:
// Signal this when the main window's UI is ready
// to display payment requests to the user
@@ -123,18 +88,8 @@ public Q_SLOTS:
// Handle an incoming URI, URI with local file scheme or file
void handleURIOrFile(const QString& s);
-#ifdef ENABLE_BIP70
- // Submit Payment message to a merchant, get back PaymentACK:
- void fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction);
-#endif
-
private Q_SLOTS:
void handleURIConnection();
-#ifdef ENABLE_BIP70
- void netRequestFinished(QNetworkReply*);
- void reportSslErrors(QNetworkReply*, const QList<QSslError> &);
- void handlePaymentACK(const QString& paymentACKMsg);
-#endif
protected:
// Constructor registers this on the parent QApplication to
@@ -145,16 +100,6 @@ private:
bool saveURIs; // true during startup
QLocalServer* uriServer;
OptionsModel *optionsModel;
-
-#ifdef ENABLE_BIP70
- static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
- bool processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient);
- void fetchRequest(const QUrl& url);
-
- // Setup networking
- void initNetManager();
- QNetworkAccessManager* netManager; // Used to fetch payment requests
-#endif
};
#endif // BITCOIN_QT_PAYMENTSERVER_H
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index bf1baf5470..2332d52b9a 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -71,6 +71,7 @@ bool QRImageWidget::setQR(const QString& data, const QString& text)
if (!text.isEmpty()) {
QFont font = GUIUtil::fixedPitchFont();
+ font.setStyleStrategy(QFont::NoAntialias);
QRect paddedRect = qrAddrImage.rect();
// calculate ideal font size
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 80ea6cd2e6..8edcca684d 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -291,9 +291,6 @@ void SendCoinsDialog::on_sendButton_clicked()
QString recipientElement;
-#ifdef ENABLE_BIP70
- if (!rcp.paymentRequest.IsInitialized()) // normal payment
-#endif
{
if(rcp.label.length() > 0) // label with address
{
@@ -305,17 +302,6 @@ void SendCoinsDialog::on_sendButton_clicked()
recipientElement.append(tr("%1 to %2").arg(amount, address));
}
}
-#ifdef ENABLE_BIP70
- else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request
- {
- recipientElement.append(tr("%1 to '%2'").arg(amount, rcp.authenticatedMerchant));
- }
- else // unauthenticated payment request
- {
- recipientElement.append(tr("%1 to %2").arg(amount, address));
- }
-#endif
-
formatted.append(recipientElement);
}
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 7324d759fb..be417655b4 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -137,12 +137,6 @@ bool SendCoinsEntry::validate(interfaces::Node& node)
// Check input validity
bool retval = true;
-#ifdef ENABLE_BIP70
- // Skip checks for payment request
- if (recipient.paymentRequest.IsInitialized())
- return retval;
-#endif
-
if (!model->validateAddress(ui->payTo->text()))
{
ui->payTo->setValid(false);
@@ -172,13 +166,6 @@ bool SendCoinsEntry::validate(interfaces::Node& node)
SendCoinsRecipient SendCoinsEntry::getValue()
{
-#ifdef ENABLE_BIP70
- // Payment request
- if (recipient.paymentRequest.IsInitialized())
- return recipient;
-#endif
-
- // Normal payment
recipient.address = ui->payTo->text();
recipient.label = ui->addAsLabel->text();
recipient.amount = ui->payAmount->value();
@@ -203,29 +190,6 @@ QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
recipient = value;
-
-#ifdef ENABLE_BIP70
- if (recipient.paymentRequest.IsInitialized()) // payment request
- {
- if (recipient.authenticatedMerchant.isEmpty()) // unauthenticated
- {
- ui->payTo_is->setText(recipient.address);
- ui->memoTextLabel_is->setText(recipient.message);
- ui->payAmount_is->setValue(recipient.amount);
- ui->payAmount_is->setReadOnly(true);
- setCurrentWidget(ui->SendCoins_UnauthenticatedPaymentRequest);
- }
- else // authenticated
- {
- ui->payTo_s->setText(recipient.authenticatedMerchant);
- ui->memoTextLabel_s->setText(recipient.message);
- ui->payAmount_s->setValue(recipient.amount);
- ui->payAmount_s->setReadOnly(true);
- setCurrentWidget(ui->SendCoins_AuthenticatedPaymentRequest);
- }
- }
- else // normal payment
-#endif
{
// message
ui->messageTextLabel->setText(recipient.message);
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
index 6750c543da..cf86a5bc1e 100644
--- a/src/qt/test/compattests.cpp
+++ b/src/qt/test/compattests.cpp
@@ -6,10 +6,6 @@
#include <config/bitcoin-config.h>
#endif
-#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
-#include <qt/paymentrequestplus.h> // this includes protobuf's port.h which defines its own bswap macos
-#endif
-
#include <qt/test/compattests.h>
#include <compat/byteswap.h>
diff --git a/src/qt/test/paymentrequestdata.h b/src/qt/test/paymentrequestdata.h
deleted file mode 100644
index 7f45d30973..0000000000
--- a/src/qt/test/paymentrequestdata.h
+++ /dev/null
@@ -1,465 +0,0 @@
-// Copyright (c) 2009-2018 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_PAYMENTREQUESTDATA_H
-#define BITCOIN_QT_TEST_PAYMENTREQUESTDATA_H
-
-//
-// Data for paymentservertests.cpp
-//
-
-// Base64/DER-encoded fake certificate authority certificates.
-// Convert pem to base64/der with:
-// openssl x509 -in cert.pem -inform PEM -outform DER | openssl enc -base64
-
-// Serial Number: 10302349811211485352 (0x8ef94c91b112c0a8)
-// Issuer: CN=PaymentRequest Test CA
-// Subject: CN=PaymentRequest Test CA
-// Not Valid After : Dec 8 16:37:24 2022 GMT
-//
-const char* caCert1_BASE64 =
-"\
-MIIB0DCCATmgAwIBAgIJAI75TJGxEsCoMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\
-BAMTFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTIxMjEwMTYzNzI0WhcNMjIx\
-MjA4MTYzNzI0WjAhMR8wHQYDVQQDExZQYXltZW50UmVxdWVzdCBUZXN0IENBMIGf\
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvua59nX9radoqDYyplcns5qdVDTN1\
-7tmcGixmMYOYU3UYMU55VSsJs0dWKnMm3COQDY+N63c0XSbRqarBcsLTkaNASuPX\
-FCv1VWuEKSyy5xe4zeoDU7CVSzlxtQD9wbZW/s3ISjgaXBpwn6eVmntb0JwYxxPc\
-M1u/hrMD8BDbSQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA\
-A4GBADSaRgK5xe47XxycXBhHhr0Wgl4pAsFsufqA9aB9r8KNEHJ0yUvvbD/jaJJM\
-RtQcf0AJ9olzUMY4syehxbzUJP6aeXhZEYiMvdvcv9D55clq6+WLLlNT3jBgAaVn\
-p3waRjPD4bUX3nv+ojz5s4puw7Qq5QUZlhGsMzPvwDGCmZkL\
-";
-
-// Serial Number: f0:da:97:e4:38:d7:64:16
-// Issuer: CN=PaymentRequest Test CA
-// Subject: CN=PaymentRequest Test CA
-// Not Valid After : Jan 8 18:21:06 2025 GMT
-//
-const char* caCert2_BASE64 =
-"\
-MIIC1TCCAb2gAwIBAgIJAPDal+Q412QWMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\
-BAMMFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTUwMTExMTgyMTA2WhcNMjUw\
-MTA4MTgyMTA2WjAhMR8wHQYDVQQDDBZQYXltZW50UmVxdWVzdCBUZXN0IENBMIIB\
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1S9wVLfTplJuT/1OaaBgl/Mb\
-I392v8S9kHbzYz7B4OTMslaO7piz0v3SO3TKMh0dswjiRdHrIgpO7XdIUQiU/ugg\
-xDw0kuNehfz1ycaGedlFFtFHTNXqLyIUF3dlwHhQwaomM6RXoJmxLny5BhYHEcmk\
-yWwr3Cdjd9gAZpblugVJB9C1e40uyL8ao4PHdLzOqO27iSe6riP8SwwisJZEbMaz\
-AZpgNEEMbIXPJEFvm5HTRXSMtQCOTSZYMFF0M2yrtmlECnz7hWP19b9bcoDzZQB4\
-ylIsFG/7q2jV7MC/e2STZv+niJiHL08RUdoFpAgzaxMgqj63C7B55HgNDNHJYQID\
-AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBGejPxLxj9\
-+crv6gUeEBMZPiUx7pUgcI22Wm5yymP96B4fwI3Y0DBehq20d76vbWGPN17Z6pH3\
-ge7PVY1SYqXtS6hXTo4olCm/BZADli+2Bs2xCiaa+Ltve4ufVej+bKJXN/YnrhvO\
-Kq+klQkuuHywU+GJV/NQeBqToIrSOBgi477NgLFCCCmmx2QWsxHoCFGfuRCBVseT\
-z2k/tMuALCDXGeZBRPTsGHu1y4cj84swAeoDK5QSQcI+Ub7GKc+zkoj02sdDLiMo\
-3wokYPcIy47oclhmb4xubHc+y7nF610yZBoC/zgbhbawnZ65hDDWkdQ/SVAnWZD7\
-9PFfmNnYPTQH\
-";
-
-//
-// This payment request validates directly against the
-// caCert1 certificate authority.
-//
-const char* paymentrequest1_cert1_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMjEyMTAx\
-NjM3MjRaFw0yMjEyMDgxNjM3MjRaMEMxGTAXBgNVBAMMEHRlc3RtZXJjaGFudC5v\
-cmcxJjAkBgNVBAoMHVBheW1lbnQgUmVxdWVzdCBUZXN0IE1lcmNoYW50MIGfMA0G\
-CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHkMy8W1u6HsWlSqdWTmMKf54gICxNfxbY\
-+rcMtAftr62hCYx2d2QiSRd1pCUzmo12IiSX3WxSHwaTnT3MFD6jRx6+zM6XdGar\
-I2zpYle11ANzu4gAthN17uRQHV2O5QxVtzNaMdKeJLXT2L9tfEdyL++9ZUqoQmdA\
-YG9ix330hQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GB\
-AIkyO99KC68bi9PFRyQQ7nvn5GlQEb3Ca1bRG5+AKN9N5vc8rZ9G2hejtM8wEXni\
-eGBP+chVMsbTPEHKLrwREn7IvcyCcbAStaklPC3w0B/2idQSHskb6P3X13OR2bTH\
-a2+6wuhsOZRUrVNr24rM95DKx/eCC6JN1VW+qRPU6fqzIjQSHwiw2wYSGXapFJVg\
-igPI+6XpExtNLO/i1WFV8ZmoiKwYsuHFiwUqC1VuaXRUZXN0T25lKoABS0j59iMU\
-Uc9MdIfwsO1BskIET0eJSGNZ7eXb9N62u+qf831PMpEHkmlGpk8rHy92nPcgua/U\
-Yt8oZMn3QaTZ5A6HjJbc3A73eLylp1a0SwCl+KDMEvDQhqMn1jAVu2v92AH3uB7n\
-SiWVbw0tX/68iSQEGGfh9n6ee/8Myb3ICdw=\
-";
-
-//
-// Signed, but expired, merchant cert in the request
-//
-const char* paymentrequest2_cert1_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrsAwrpAzCCAeUwggFOoAMCAQICAQMwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzAyMjMy\
-MTI2NDNaFw0xMzAyMjQyMTI2NDNaMD4xHDAaBgNVBAMME2V4cGlyZWRtZXJjaGFu\
-dC5vcmcxHjAcBgNVBAoMFUV4cGlyZWQgVGVzdCBNZXJjaGFudDCBnzANBgkqhkiG\
-9w0BAQEFAAOBjQAwgYkCgYEAx5DMvFtbuh7FpUqnVk5jCn+eICAsTX8W2Pq3DLQH\
-7a+toQmMdndkIkkXdaQlM5qNdiIkl91sUh8Gk509zBQ+o0cevszOl3RmqyNs6WJX\
-tdQDc7uIALYTde7kUB1djuUMVbczWjHSniS109i/bXxHci/vvWVKqEJnQGBvYsd9\
-9IUCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAaU137\
-j53rvSjlmYZpZ4RWTP7EdD6fl5ZxBeXHytN6DQL33H0eD7OFHt+ofc7E6D7keubl\
-UfCu+jOvt/MvvPUmtCI9yXZ0dNC4sjyETv+wQpxO0UNZwOM4uegdCzlo6Bi3pD4/\
-KKLdMkWuUfuPBmoammny74lZaOVr5deKXztTuCI0Eh8IsNsGEhl2qRSVYIoDyPul\
-6RMbTSzv4tVhVfGZqIisGLLhxYsFKgtVbml0VGVzdFR3byqAAXHuo4nZEPniLpkd\
-y30TkwBxVgprWJ18a9z/7Py35Qss/JMbOXbnBhJtmJCdIowHRI0aa+zqt3KKKAXi\
-mm+V4seMgxTcxMS+eDDkiTcB/RtWWSyRcS2ANjFeY0T4SLMwiCL9qWPi03hr8j96\
-tejrSPOBNSJ3Mi/q5u2Yl4gJZY2b\
-";
-
-//
-// 10-long certificate chain, all intermediates valid
-//
-const char* paymentrequest3_cert1_BASE64 =
-"\
-Egt4NTA5K3NoYTI1Nhq8JAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\
-dWVzdCBJbnRlcm1lZGlhdGUgODAeFw0xMzAyMjMyMjQyMzFaFw0yMzAyMjEyMjQy\
-MzFaMDYxGjAYBgNVBAMMEXRlc3RtZXJjaGFudDgub3JnMRgwFgYDVQQKDA9UZXN0\
-IE1lcmNoYW50IDgwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMMCHA3hiHbS\
-TKZ5K9jHRwE8NxkGp3IOx56PDB2diNkldG8XweTcRq7bBm7pdiBt4IVggtfs+6hE\
-hDYIOecyoAnVzPFTdvQ7KQdQ/fD9YLe6lk+o0edOqutPMyrxLFjSluXxEQyk7fdt\
-URloMMYfp3p1/hFCboA1rAsQ2RW38hR5AgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w\
-DQYJKoZIhvcNAQELBQADgYEAPsdFatnc2RJSpvZsw+nCiPVsllycw5ELglq9vfJz\
-nJJucRxgzmqI2iuas1ugwbXn0BEIRLK7vMF/qBzQR6M/nTxttah+KEu+okjps9vJ\
-cIyhfTyGPC5xkHaHZ7sG+UHOFhPw0/kXn0x+pbVgBZ5315axqcp1R+DTSj/whMAr\
-n0AKiAQwggIEMIIBbaADAgECAgECMA0GCSqGSIb3DQEBCwUAMD8xFDASBgNVBAMM\
-C3Rlc3RjYTcub3JnMScwJQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRp\
-YXRlIDcwHhcNMTMwMjIzMjI0MjMxWhcNMjMwMjIxMjI0MjMxWjA/MRQwEgYDVQQD\
-DAt0ZXN0Y2E4Lm9yZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVk\
-aWF0ZSA4MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDexUFfxb1sThvabp7u\
-dZz59ciThGmmAW0nP4tjrgEACgvWIInr2dZpTHbiQNF34ycsk0le1JD93D7Qb8rd\
-25OrpaO8XS2Li2zjR9cleixXjSLwV/zv8zJ8yPl/27XL++PDTKBXVpJ8/Syp+9Ty\
-plV1BqDhqtIHb/QSHEkTQXjeYQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqG\
-SIb3DQEBCwUAA4GBACMooQVbkbIZ2DaPwHDc4ULwguG3VI2Kzj50UdExmHtzm2S4\
-MQei+n+HEPjtJAx5OY520+10nfuP+12H2DRLQmWmdvDpeQ/Cv0yavlw4ZRejRFo7\
-KS83C0wo5rd+qTvvOmAN4UTArWkzYcEUulPdiXnRamb0WQHTeVdIbHVkMormCogE\
-MIICBDCCAW2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA/MRQwEgYDVQQDDAt0ZXN0\
-Y2E2Lm9yZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVkaWF0ZSA2\
-MB4XDTEzMDIyMzIyNDIzMVoXDTIzMDIyMTIyNDIzMVowPzEUMBIGA1UEAwwLdGVz\
-dGNhNy5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUg\
-NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtjBRazrkebXAhXsbjimrMIRm\
-W/f9SwAHwXfc042keNtl0t2z6XE6UPcR2v/KrssXuCZgodeYxz6IM6lWosCM1xot\
-C3ChKKFBfVO30reuKBRUxXfKAFqxaG0YOAEzdZkkY9AGhqWloeSmgxpIfhInU0EF\
-JjCwrJ6IkijBatGoAAECAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B\
-AQsFAAOBgQDBRTi1MolmOA0niHYX0A2lN5QWHkCfX0A7GwyoMA3dvM45m/NYd4WB\
-X+HwfnfYcI6X9jOgNo5OWmc4GGsld0HlxwMYEKISBS9PbSHPBrb3TBOlw5ztQpXZ\
-91+bOhLux52Fr03sK7v9qExmBM12M8UR2ltpzAMiUgLLMHyPfiWkvQqIBDCCAgQw\
-ggFtoAMCAQICAQIwDQYJKoZIhvcNAQELBQAwPzEUMBIGA1UEAwwLdGVzdGNhNS5v\
-cmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUgNTAeFw0x\
-MzAyMjMyMjQyMzBaFw0yMzAyMjEyMjQyMzBaMD8xFDASBgNVBAMMC3Rlc3RjYTYu\
-b3JnMScwJQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDYwgZ8w\
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANJSH3xivX1t9olIdHsznI1aE9SD7t9i\
-SZJsIB0otoETHZRVv9M9LvyzBNK98ZV+kTOlST7PJgC0d9BQM9sgYApSRq5oqKDM\
-9FXbOm/yaReAbU3mkFNFw5roTlJ5ThEy0yOGT/DS0YBRaGIvRPRj2DiqDVdCZZ+w\
-4jo1IYHkZt4FAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQAD\
-gYEATm6+J1OmbrothO60xALKonWMBKr6hudb4amkFBqKbA9wMeM3jl+I/yKfz/Uf\
-xWuJ071IhiNv6Gxx5YwNvhUe1xMhUqHv0gpyK1Z47bD+kYS2se5sWNPNo3Y9qZDG\
-IXiGQxwHmrzaFk79Uy1xsmvsEz42w6hr25Yaw7HkIgrFveoKiAQwggIEMIIBbaAD\
-AgECAgECMA0GCSqGSIb3DQEBCwUAMD8xFDASBgNVBAMMC3Rlc3RjYTQub3JnMScw\
-JQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDQwHhcNMTMwMjIz\
-MjI0MjMwWhcNMjMwMjIxMjI0MjMwWjA/MRQwEgYDVQQDDAt0ZXN0Y2E1Lm9yZzEn\
-MCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVkaWF0ZSA1MIGfMA0GCSqG\
-SIb3DQEBAQUAA4GNADCBiQKBgQC7vVUFpxHzz2Tr/xij3k58s8d/BPA0R6D5RXTV\
-vmhAzc1Zuin4zUKRFs/aCj/0yED8Wu/COfNGF4tVlRNMdl9EcFsxa8XGEL4eAZa+\
-H/rOHH+7/1EINrrVWhZlUecyhilN8jmCZmqEM3ecuD0NAViqyMrgmaiFmsLoQZpE\
-GepDUQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAEdJ\
-Ss8jWiooja3WZzHXeF95QkBJNjIlpDLGcpl4opOYLSuEl9Uxp//LaQQiXuzpj4/I\
-pkWGQmMy5HOyH1lqDyiMgXpcG8PE0jEQAoEUGZ0QEqB1mZ6BCrYvmUuf/5aSVd8Y\
-6lKMR3WzFDYU9Zy0nzuHB/3nvp6MeDRQeRMtYvz4CogEMIICBDCCAW2gAwIBAgIB\
-AjANBgkqhkiG9w0BAQsFADA/MRQwEgYDVQQDDAt0ZXN0Y2EzLm9yZzEnMCUGA1UE\
-CgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVkaWF0ZSAzMB4XDTEzMDIyMzIyNDIy\
-OVoXDTIzMDIyMTIyNDIyOVowPzEUMBIGA1UEAwwLdGVzdGNhNC5vcmcxJzAlBgNV\
-BAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUgNDCBnzANBgkqhkiG9w0B\
-AQEFAAOBjQAwgYkCgYEAxYYo3w2UXiYg6O8b4QgwN/vgreTkiW122Ep/z2TiDrhV\
-MhfOOiKdwYESPflfnXnVaQQzCGexYTQqsvqvzHSyna5hL0zPTRJxSKmTVrXRsWtp\
-dCRhjxCGipS3tlQBDi7vb+7SNRIBK4dBjjGzALNk7gMCpy+yM8f6I043jTlmGb0C\
-AwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQDU+IQxt3Oh\
-KqaUYWC23+cB2gekvWqwMBnrCNrX/Dp+kjoJKUoR2Fs3qw53raHES4SIhpGT9l9l\
-rppNQgFe/JMHeYqOZMZO+6kuU0olJanBJ14tPIc7zlMTQ9OfmZ6v07IpyFbsQDtR\
-hpe80DpuvSFPfJ4fh0WrQf6kn3KDVpGDnAqIBDCCAgQwggFtoAMCAQICAQIwDQYJ\
-KoZIhvcNAQELBQAwPzEUMBIGA1UEAwwLdGVzdGNhMi5vcmcxJzAlBgNVBAoMHlBh\
-eW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUgMjAeFw0xMzAyMjMyMjQyMjlaFw0y\
-MzAyMjEyMjQyMjlaMD8xFDASBgNVBAMMC3Rlc3RjYTMub3JnMScwJQYDVQQKDB5Q\
-YXltZW50IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDMwgZ8wDQYJKoZIhvcNAQEBBQAD\
-gY0AMIGJAoGBANzgVP99Qg98e6NsKEz1v5KqRB7NTBRRsYnBvb/TSWipvMQaCYuE\
-yk1xG57x++QuASKeR3QHRQJOoAhQaj9JLUhSSv9GQ5PrFLLsOFv7L1tpzXHh2dOB\
-IW92X2yFRW2s39q+Q21yvN+N8uoKdqXhzRA+dDoXh3cavaVeHX1G+IrlAgMBAAGj\
-EDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEASTwg84cX+1UhOG9s\
-ejFV3m34QuI1hPZ+qhqVJlRYUtego8Wng1BburDSwqVAv4ch2wi3c2s4e8J7AXyL\
-tzSbSQG4RN0oZi0mR8EtTTN+Mix/hBIk79dMZg85+I29uFA6Zj2d9oAhQv2qkHhc\
-6tcaheNvkQRlCyH68k3iF1Fqf+4KiAQwggIEMIIBbaADAgECAgECMA0GCSqGSIb3\
-DQEBCwUAMD8xFDASBgNVBAMMC3Rlc3RjYTEub3JnMScwJQYDVQQKDB5QYXltZW50\
-IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDEwHhcNMTMwMjIzMjI0MjI5WhcNMjMwMjIx\
-MjI0MjI5WjA/MRQwEgYDVQQDDAt0ZXN0Y2EyLm9yZzEnMCUGA1UECgweUGF5bWVu\
-dCBSZXF1ZXN0IEludGVybWVkaWF0ZSAyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\
-iQKBgQDaV8zhfyQuSf/f+fauMfgs3g/RnWy9yxxUkvQneQQPH3uZzCyk3A6q72ip\
-TtwNqiibG9455L9A7SaUjGtnpUz0NKT/VWUdqbfCl1PqXjEZbDobbAQ5hxLGOTyL\
-RQhLIcgeq2/BnmeCqHsC4md04nUp+nBo1HwKyygvK+9sMbCp/wIDAQABoxAwDjAM\
-BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBACvYyE+PPmWFkbjyRu9LAt8D\
-crtyYYLRClKSg6tVvutwukLG2l//kDOohYkJtgTqr6LnCIIIwYdXN+4wxugmw4cn\
-PIZmP6kovxjhhVM95okilor1zniTAo3RN7JDIfTGNgxLdGu1btt7DOFL4zTbeSJM\
-b8M1JpPftehH+x/VLyuUCuoDMIIB5jCCAU+gAwIBAgIBBTANBgkqhkiG9w0BAQsF\
-ADAhMR8wHQYDVQQDExZQYXltZW50UmVxdWVzdCBUZXN0IENBMB4XDTEzMDIyMzIy\
-NDIyOFoXDTIzMDIyMTIyNDIyOFowPzEUMBIGA1UEAwwLdGVzdGNhMS5vcmcxJzAl\
-BgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUgMTCBnzANBgkqhkiG\
-9w0BAQEFAAOBjQAwgYkCgYEAo5Vy9H3nA/OOkF5Ap89yfVNSiTay/LYCaB0eALpc\
-U690U75O9Q3w2M+2AN8wpbbHsJHZMIjEeBRoQfjlYXW1ucQTxWKyT+liu0D25mGX\
-X27CBXBd4iXTxVII/iX+u3lcjORjoHOBy7QgeIDIIS9y0vYu8eArpjh7m4thrVgI\
-RtMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQB9LKcV\
-JK9sjASNzpQlpUp7nCiw5FSjVY+XMRIKK/kavzlKjZ+InsmmyRVGjDoZi9GrqG9P\
-VHgLBxi2VtVjmokZoNPqao3OfhqORAubC+JR/JLepM7aDaxDdTHVhSUk4lgNAvi2\
-6dGY7nZMsnHlPQ2tPp/HvRRiMq1oDjlylc8VTCI2Eh8IsNsGEhl2qRSVYIoDyPul\
-6RMbTSzv4tVhVfGZqIisGLLhxYsFKg1Vbml0VGVzdFRocmVlKoABn2HTsUQtMNI4\
-yNvkfkFNka3pRvTUTydJrvyfmEeLzImfM1BWddZjnywku9RToNFZZNgow5QnljmF\
-chhR/aHOuEMTxmc12K4rNlgYtHCsxLP9zd+6u0cva3TucZ6EzS8PKEib/+r12/52\
-664NuWA9WtsK7QCFrK2K95PnVCRmWl0=\
-";
-
-//
-// Long certificate chain, with an expired certificate in the middle
-//
-const char* paymentrequest4_cert1_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhqeJAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\
-dWVzdCBJbnRlcm1lZGlhdGUgODAeFw0xMzAyMjMyMjQyMzFaFw0yMzAyMjEyMjQy\
-MzFaMDYxGjAYBgNVBAMMEXRlc3RtZXJjaGFudDgub3JnMRgwFgYDVQQKDA9UZXN0\
-IE1lcmNoYW50IDgwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMMCHA3hiHbS\
-TKZ5K9jHRwE8NxkGp3IOx56PDB2diNkldG8XweTcRq7bBm7pdiBt4IVggtfs+6hE\
-hDYIOecyoAnVzPFTdvQ7KQdQ/fD9YLe6lk+o0edOqutPMyrxLFjSluXxEQyk7fdt\
-URloMMYfp3p1/hFCboA1rAsQ2RW38hR5AgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w\
-DQYJKoZIhvcNAQELBQADgYEAPsdFatnc2RJSpvZsw+nCiPVsllycw5ELglq9vfJz\
-nJJucRxgzmqI2iuas1ugwbXn0BEIRLK7vMF/qBzQR6M/nTxttah+KEu+okjps9vJ\
-cIyhfTyGPC5xkHaHZ7sG+UHOFhPw0/kXn0x+pbVgBZ5315axqcp1R+DTSj/whMAr\
-n0AKiAQwggIEMIIBbaADAgECAgECMA0GCSqGSIb3DQEBCwUAMD8xFDASBgNVBAMM\
-C3Rlc3RjYTcub3JnMScwJQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRp\
-YXRlIDcwHhcNMTMwMjIzMjI0MjMxWhcNMjMwMjIxMjI0MjMxWjA/MRQwEgYDVQQD\
-DAt0ZXN0Y2E4Lm9yZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVk\
-aWF0ZSA4MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDexUFfxb1sThvabp7u\
-dZz59ciThGmmAW0nP4tjrgEACgvWIInr2dZpTHbiQNF34ycsk0le1JD93D7Qb8rd\
-25OrpaO8XS2Li2zjR9cleixXjSLwV/zv8zJ8yPl/27XL++PDTKBXVpJ8/Syp+9Ty\
-plV1BqDhqtIHb/QSHEkTQXjeYQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqG\
-SIb3DQEBCwUAA4GBACMooQVbkbIZ2DaPwHDc4ULwguG3VI2Kzj50UdExmHtzm2S4\
-MQei+n+HEPjtJAx5OY520+10nfuP+12H2DRLQmWmdvDpeQ/Cv0yavlw4ZRejRFo7\
-KS83C0wo5rd+qTvvOmAN4UTArWkzYcEUulPdiXnRamb0WQHTeVdIbHVkMormCogE\
-MIICBDCCAW2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA/MRQwEgYDVQQDDAt0ZXN0\
-Y2E2Lm9yZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVkaWF0ZSA2\
-MB4XDTEzMDIyMzIyNDIzMVoXDTIzMDIyMTIyNDIzMVowPzEUMBIGA1UEAwwLdGVz\
-dGNhNy5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUg\
-NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtjBRazrkebXAhXsbjimrMIRm\
-W/f9SwAHwXfc042keNtl0t2z6XE6UPcR2v/KrssXuCZgodeYxz6IM6lWosCM1xot\
-C3ChKKFBfVO30reuKBRUxXfKAFqxaG0YOAEzdZkkY9AGhqWloeSmgxpIfhInU0EF\
-JjCwrJ6IkijBatGoAAECAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B\
-AQsFAAOBgQDBRTi1MolmOA0niHYX0A2lN5QWHkCfX0A7GwyoMA3dvM45m/NYd4WB\
-X+HwfnfYcI6X9jOgNo5OWmc4GGsld0HlxwMYEKISBS9PbSHPBrb3TBOlw5ztQpXZ\
-91+bOhLux52Fr03sK7v9qExmBM12M8UR2ltpzAMiUgLLMHyPfiWkvQqIBDCCAgQw\
-ggFtoAMCAQICAQIwDQYJKoZIhvcNAQELBQAwPzEUMBIGA1UEAwwLdGVzdGNhNS5v\
-cmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUgNTAeFw0x\
-MzAyMjMyMjQyMzBaFw0yMzAyMjEyMjQyMzBaMD8xFDASBgNVBAMMC3Rlc3RjYTYu\
-b3JnMScwJQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDYwgZ8w\
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANJSH3xivX1t9olIdHsznI1aE9SD7t9i\
-SZJsIB0otoETHZRVv9M9LvyzBNK98ZV+kTOlST7PJgC0d9BQM9sgYApSRq5oqKDM\
-9FXbOm/yaReAbU3mkFNFw5roTlJ5ThEy0yOGT/DS0YBRaGIvRPRj2DiqDVdCZZ+w\
-4jo1IYHkZt4FAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQAD\
-gYEATm6+J1OmbrothO60xALKonWMBKr6hudb4amkFBqKbA9wMeM3jl+I/yKfz/Uf\
-xWuJ071IhiNv6Gxx5YwNvhUe1xMhUqHv0gpyK1Z47bD+kYS2se5sWNPNo3Y9qZDG\
-IXiGQxwHmrzaFk79Uy1xsmvsEz42w6hr25Yaw7HkIgrFveoK6gMwggHmMIIBT6AD\
-AgECAgEGMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNVBAMTFlBheW1lbnRSZXF1ZXN0\
-IFRlc3QgQ0EwHhcNMTMwMjIzMjI1OTUxWhcNMTMwMjI0MjI1OTUxWjA/MRQwEgYD\
-VQQDDAt0ZXN0Y2E1Lm9yZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVy\
-bWVkaWF0ZSA1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vVUFpxHzz2Tr\
-/xij3k58s8d/BPA0R6D5RXTVvmhAzc1Zuin4zUKRFs/aCj/0yED8Wu/COfNGF4tV\
-lRNMdl9EcFsxa8XGEL4eAZa+H/rOHH+7/1EINrrVWhZlUecyhilN8jmCZmqEM3ec\
-uD0NAViqyMrgmaiFmsLoQZpEGepDUQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G\
-CSqGSIb3DQEBCwUAA4GBAEmcUEnhua/oiXy1fwScLgMqt+jk9mHRpE6SVsIop23Q\
-CY2JfpG6RxhMMzzzhGklEGN6cxG0HCi6B3HJx6PYrFEfTB0rW4K6m0Tvx3WpS9mN\
-uoEuJHLy18ausI/sYAPDHCL+SfBVcqorpaIG2sSpZouRBjRHAyqFAYlwlW87uq5n\
-CogEMIICBDCCAW2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA/MRQwEgYDVQQDDAt0\
-ZXN0Y2EzLm9yZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVkaWF0\
-ZSAzMB4XDTEzMDIyMzIyNDIyOVoXDTIzMDIyMTIyNDIyOVowPzEUMBIGA1UEAwwL\
-dGVzdGNhNC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlh\
-dGUgNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxYYo3w2UXiYg6O8b4Qgw\
-N/vgreTkiW122Ep/z2TiDrhVMhfOOiKdwYESPflfnXnVaQQzCGexYTQqsvqvzHSy\
-na5hL0zPTRJxSKmTVrXRsWtpdCRhjxCGipS3tlQBDi7vb+7SNRIBK4dBjjGzALNk\
-7gMCpy+yM8f6I043jTlmGb0CAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG\
-9w0BAQsFAAOBgQDU+IQxt3OhKqaUYWC23+cB2gekvWqwMBnrCNrX/Dp+kjoJKUoR\
-2Fs3qw53raHES4SIhpGT9l9lrppNQgFe/JMHeYqOZMZO+6kuU0olJanBJ14tPIc7\
-zlMTQ9OfmZ6v07IpyFbsQDtRhpe80DpuvSFPfJ4fh0WrQf6kn3KDVpGDnAqIBDCC\
-AgQwggFtoAMCAQICAQIwDQYJKoZIhvcNAQELBQAwPzEUMBIGA1UEAwwLdGVzdGNh\
-Mi5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1lZGlhdGUgMjAe\
-Fw0xMzAyMjMyMjQyMjlaFw0yMzAyMjEyMjQyMjlaMD8xFDASBgNVBAMMC3Rlc3Rj\
-YTMub3JnMScwJQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDMw\
-gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANzgVP99Qg98e6NsKEz1v5KqRB7N\
-TBRRsYnBvb/TSWipvMQaCYuEyk1xG57x++QuASKeR3QHRQJOoAhQaj9JLUhSSv9G\
-Q5PrFLLsOFv7L1tpzXHh2dOBIW92X2yFRW2s39q+Q21yvN+N8uoKdqXhzRA+dDoX\
-h3cavaVeHX1G+IrlAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL\
-BQADgYEASTwg84cX+1UhOG9sejFV3m34QuI1hPZ+qhqVJlRYUtego8Wng1BburDS\
-wqVAv4ch2wi3c2s4e8J7AXyLtzSbSQG4RN0oZi0mR8EtTTN+Mix/hBIk79dMZg85\
-+I29uFA6Zj2d9oAhQv2qkHhc6tcaheNvkQRlCyH68k3iF1Fqf+4KiAQwggIEMIIB\
-baADAgECAgECMA0GCSqGSIb3DQEBCwUAMD8xFDASBgNVBAMMC3Rlc3RjYTEub3Jn\
-MScwJQYDVQQKDB5QYXltZW50IFJlcXVlc3QgSW50ZXJtZWRpYXRlIDEwHhcNMTMw\
-MjIzMjI0MjI5WhcNMjMwMjIxMjI0MjI5WjA/MRQwEgYDVQQDDAt0ZXN0Y2EyLm9y\
-ZzEnMCUGA1UECgweUGF5bWVudCBSZXF1ZXN0IEludGVybWVkaWF0ZSAyMIGfMA0G\
-CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaV8zhfyQuSf/f+fauMfgs3g/RnWy9yxxU\
-kvQneQQPH3uZzCyk3A6q72ipTtwNqiibG9455L9A7SaUjGtnpUz0NKT/VWUdqbfC\
-l1PqXjEZbDobbAQ5hxLGOTyLRQhLIcgeq2/BnmeCqHsC4md04nUp+nBo1HwKyygv\
-K+9sMbCp/wIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GB\
-ACvYyE+PPmWFkbjyRu9LAt8DcrtyYYLRClKSg6tVvutwukLG2l//kDOohYkJtgTq\
-r6LnCIIIwYdXN+4wxugmw4cnPIZmP6kovxjhhVM95okilor1zniTAo3RN7JDIfTG\
-NgxLdGu1btt7DOFL4zTbeSJMb8M1JpPftehH+x/VLyuUCuoDMIIB5jCCAU+gAwIB\
-AgIBBTANBgkqhkiG9w0BAQsFADAhMR8wHQYDVQQDExZQYXltZW50UmVxdWVzdCBU\
-ZXN0IENBMB4XDTEzMDIyMzIyNDIyOFoXDTIzMDIyMTIyNDIyOFowPzEUMBIGA1UE\
-AwwLdGVzdGNhMS5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVxdWVzdCBJbnRlcm1l\
-ZGlhdGUgMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAo5Vy9H3nA/OOkF5A\
-p89yfVNSiTay/LYCaB0eALpcU690U75O9Q3w2M+2AN8wpbbHsJHZMIjEeBRoQfjl\
-YXW1ucQTxWKyT+liu0D25mGXX27CBXBd4iXTxVII/iX+u3lcjORjoHOBy7QgeIDI\
-IS9y0vYu8eArpjh7m4thrVgIRtMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkq\
-hkiG9w0BAQsFAAOBgQB9LKcVJK9sjASNzpQlpUp7nCiw5FSjVY+XMRIKK/kavzlK\
-jZ+InsmmyRVGjDoZi9GrqG9PVHgLBxi2VtVjmokZoNPqao3OfhqORAubC+JR/JLe\
-pM7aDaxDdTHVhSUk4lgNAvi26dGY7nZMsnHlPQ2tPp/HvRRiMq1oDjlylc8VTCI1\
-Eh8IsNsGEhl2qRSVYIoDyPul6RMbTSzv4tVhVfGZqIisGLLhxYsFKgxVbml0VGVz\
-dEZvdXIqgAEBE1PP93Tkpif35F+dYmXn9kLA/1djcPjCs2o2rwRMM4Uk356O5dgu\
-HXQjsfdR58qZQS9CS5DAtRUf0R8+43/wijO/hb49VNaNXmY+/cPHMkahP2aV3tZi\
-FAyZblLik9A7ZvF+UsjeFQiHB5wzWQvbqk5wQ4yabHIXoYv/E0q+eQ==\
-";
-
-//
-// Validly signed, but by a CA not in our root CA list
-//
-const char* paymentrequest5_cert1_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzA0MTkx\
-NzIwMDZaFw0yMzA0MTcxNzIwMDZaMEMxGTAXBgNVBAMMEHRlc3RtZXJjaGFudC5v\
-cmcxJjAkBgNVBAoMHVBheW1lbnQgUmVxdWVzdCBUZXN0IE1lcmNoYW50MIGfMA0G\
-CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhV6Yn47aEEmbl50YLvXoqGEJA51I/40wr\
-Z6VQGdXYaRqYktagrWDlgYY9h0JQ1bQhm8HgW7ju0R4NaDTXUqxg4HjprF0z3Mfm\
-/6mmebkLOOptfkVD7ceAteNI7cyuqWGIAZA7D9mV97mXoCAtTlBUycvkmoiClCCS\
-h0EpF/UTaQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GB\
-AGIRwW7I0QvLga+RnJoJSZNZQbtu4rQW3xmoz8WfZMBYXX3QBYg5ftycbdK+/IbP\
-qozfjGW2AS6DNArvpveSPDTK9+GJBNo1paiNtVqwXkC3Ddscv5AIms1eZGiIOQNC\
-mUvdLkpoXo48WAer3EGsZ3B15GyNEELc0q9W5yUebba1IjUSHwiw2wYSGXapFJVg\
-igPI+6XpExtNLO/i1WFV8ZmoiKwYuPvFiwUqDFVuaXRUZXN0Rml2ZSqAAXdsMgdG\
-ssymvca1S/1KeM3n8Ydi2fi1JUzAAr59xPvNJRUeqCLP9upHn5z7br3P12Oz9A20\
-5/4wL4ClPRPVnOHgij0bEg+y0tGESqmF1rfOfXDszlo2U92wCxS07kq79YAZJ1Zo\
-XYh860/Q4wvc7lfiTe+dXBzPKAKhMy91yETY\
-";
-
-//
-// Contains a testnet paytoaddress, so payment request network doesn't match client network
-//
-const char* paymentrequest1_cert2_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
-ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
-IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
-mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
-wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
-RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
-KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
-+S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
-3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
-tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
-yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
-dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iPQoEdGVzdBIhCIDWwowE\
-Ehl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGNeMy6UFKgxKdXN0IFRlc3Rpbmcq\
-gAFwThsozZxkZxzCn4R8WxNiLFV6m0ye9fEtSbolfaW+EjBMpO03lr/dwNnrclhg\
-ew+A05xfZztrAt16XKEY7qKJ/eY2nLd0fVAIu/nIt+7/VYVXT83zLrWc150aRS7W\
-AdJbL3JOJLs6Eyp5zrPbfI8faRttFAdONKDrJgIpuW1E3g==\
-";
-
-//
-// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01)
-//
-const char* paymentrequest2_cert2_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
-ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
-IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
-mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
-wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
-RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
-KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
-+S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
-3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
-tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
-yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
-dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iQgoEdGVzdBIgCICt4gQS\
-GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYiNLUpQUgASoQVGVzdGluZyB0ZXN0\
-bmV0ISqAATXq9A5nmJgtmee/bQTeHeif4w1YYFPBlKghwx6qbVgXTWnwBJtOQhhV\
-sZdzbTl95ENR7/Y7VJupW9kDWobCK7zUUhLAzUlwmLlcx6itHw8LTUF5HK+AwsZm\
-Zs85lISGvOS0NZW/ENa6l+oQRnL87oqVZr/EDGiuqjz6T0ThQi0l\
-";
-
-//
-// Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t)
-//
-const char* paymentrequest3_cert2_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
-ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
-IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
-mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
-wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
-RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
-KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
-+S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
-3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
-tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
-yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
-dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iSgoEdGVzdBIgCICt4gQS\
-GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYyNfZpQUg//////////9/KhBUZXN0\
-aW5nIHRlc3RuZXQhKoABNwi8WnMW4aMvbmvorTiiWJLFhofLFnsoWCJnj3rWLnLh\
-n3w6q/fZ26p50ERL/noxdTUfeFsKnlECkUu/fOcOrqyYDiwvxI0SZ034DleVyFU1\
-Z3T+X0zcL8oe7bX01Yf+s2V+5JXQXarKnKBrZCGgv2ARjFNSZe7E7vGg5K4Q6Q8=\
-";
-
-//
-// Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64)
-//
-const char* paymentrequest4_cert2_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
-ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
-IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
-mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
-wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
-RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
-KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
-+S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
-3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
-tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
-yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
-dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iSwoEdGVzdBIgCICt4gQS\
-GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYt+HZpQUggICAgICAgICAASoQVGVz\
-dGluZyB0ZXN0bmV0ISqAAXSQG8+GFA18VaKarlYrOz293rNMIub0swKGcQm8jAGX\
-HSLaRgHfUDeEPr4hydy4dtfu59KNwe2xsHOHu/SpO4L8SrA4Dm9A7SlNBVWdcLbw\
-d2hj739GDLz0b5KuJ2SG6VknMRQM976w/m2qlq0ccVGaaZ2zMIGfpzL3p6adwx/5\
-";
-
-//
-// Payment request with amount overflow (amount is set to 21000001 BTC)
-//
-const char* paymentrequest5_cert2_BASE64 =
-"\
-Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
-BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
-ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
-IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
-mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
-wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
-RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
-KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
-+S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
-3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
-tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
-yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
-dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iTAoEdGVzdBIkCIDC9P+F\
-vt0DEhl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGLzcrKYFKhhUZXN0aW5nIGFt\
-b3VudCBvdmVyZmxvdyEqgAG8S7WEDUC6tCL6q2CTBjop/AitgEy31RL9IqYruytR\
-iEBFUrBDJZU+UEezGwr7/zoECjo5ZY3PmtZcM2sILNjyweJF6XVzGqTxUw6pN6sW\
-XR2T3Gy2LzRvhVA25QgGqpz0/juS2BtmNbsZPkN9gMMwKimgzc+PuCzmEKwPK9cQ\
-YQ==\
-";
-
-#endif // BITCOIN_QT_TEST_PAYMENTREQUESTDATA_H
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
deleted file mode 100644
index ef0808054d..0000000000
--- a/src/qt/test/paymentservertests.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) 2009-2018 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 <qt/test/paymentservertests.h>
-
-#include <qt/optionsmodel.h>
-#include <qt/test/paymentrequestdata.h>
-
-#include <amount.h>
-#include <interfaces/node.h>
-#include <random.h>
-#include <script/script.h>
-#include <script/standard.h>
-#include <test/setup_common.h>
-#include <util/strencodings.h>
-
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-#include <openssl/x509_vfy.h>
-
-#include <QFileOpenEvent>
-#include <QTemporaryFile>
-
-X509 *parse_b64der_cert(const char* cert_data)
-{
- std::vector<unsigned char> data = DecodeBase64(cert_data);
- assert(data.size() > 0);
- const unsigned char* dptr = data.data();
- X509 *cert = d2i_X509(nullptr, &dptr, data.size());
- assert(cert);
- return cert;
-}
-
-//
-// Test payment request handling
-//
-
-static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsigned char>& data)
-{
- RecipientCatcher sigCatcher;
- QObject::connect(server, &PaymentServer::receivedPaymentRequest,
- &sigCatcher, &RecipientCatcher::getRecipient);
-
- // Write data to a temp file:
- QTemporaryFile f;
- f.open();
- f.write((const char*)data.data(), data.size());
- f.close();
-
- // Create a QObject, install event filter from PaymentServer
- // and send a file open event to the object
- QObject object;
- object.installEventFilter(server);
- QFileOpenEvent event(f.fileName());
- // If sending the event fails, this will cause sigCatcher to be empty,
- // which will lead to a test failure anyway.
- QCoreApplication::sendEvent(&object, &event);
-
- QObject::disconnect(server, &PaymentServer::receivedPaymentRequest,
- &sigCatcher, &RecipientCatcher::getRecipient);
-
- // Return results from sigCatcher
- return sigCatcher.recipient;
-}
-
-void PaymentServerTests::paymentServerTests()
-{
- SSL_library_init();
- BasicTestingSetup testing_setup(CBaseChainParams::MAIN);
- auto node = interfaces::MakeNode();
- OptionsModel optionsModel(*node);
- PaymentServer* server = new PaymentServer(nullptr, false);
- X509_STORE* caStore = X509_STORE_new();
- X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
- PaymentServer::LoadRootCAs(caStore);
- server->setOptionsModel(&optionsModel);
- server->uiReady();
-
- std::vector<unsigned char> data;
- SendCoinsRecipient r;
- QString merchant;
-
- // Now feed PaymentRequests to server, and observe signals it produces
-
- // This payment request validates directly against the
- // caCert1 certificate authority:
- data = DecodeBase64(paymentrequest1_cert1_BASE64);
- r = handleRequest(server, data);
- r.paymentRequest.getMerchant(caStore, merchant);
- QCOMPARE(merchant, QString("testmerchant.org"));
-
- // Signed, but expired, merchant cert in the request:
- data = DecodeBase64(paymentrequest2_cert1_BASE64);
- r = handleRequest(server, data);
- r.paymentRequest.getMerchant(caStore, merchant);
- QCOMPARE(merchant, QString(""));
-
- // 10-long certificate chain, all intermediates valid:
- data = DecodeBase64(paymentrequest3_cert1_BASE64);
- r = handleRequest(server, data);
- r.paymentRequest.getMerchant(caStore, merchant);
- QCOMPARE(merchant, QString("testmerchant8.org"));
-
- // Long certificate chain, with an expired certificate in the middle:
- data = DecodeBase64(paymentrequest4_cert1_BASE64);
- r = handleRequest(server, data);
- r.paymentRequest.getMerchant(caStore, merchant);
- QCOMPARE(merchant, QString(""));
-
- // Validly signed, but by a CA not in our root CA list:
- data = DecodeBase64(paymentrequest5_cert1_BASE64);
- r = handleRequest(server, data);
- r.paymentRequest.getMerchant(caStore, merchant);
- QCOMPARE(merchant, QString(""));
-
- // Try again with no root CA's, verifiedMerchant should be empty:
- caStore = X509_STORE_new();
- PaymentServer::LoadRootCAs(caStore);
- data = DecodeBase64(paymentrequest1_cert1_BASE64);
- r = handleRequest(server, data);
- r.paymentRequest.getMerchant(caStore, merchant);
- QCOMPARE(merchant, QString(""));
-
- // Load second root certificate
- caStore = X509_STORE_new();
- X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
- PaymentServer::LoadRootCAs(caStore);
-
- QByteArray byteArray;
-
- // For the tests below we just need the payment request data from
- // paymentrequestdata.h parsed + stored in r.paymentRequest.
- //
- // These tests require us to bypass the following normal client execution flow
- // shown below to be able to explicitly just trigger a certain condition!
- //
- // handleRequest()
- // -> PaymentServer::eventFilter()
- // -> PaymentServer::handleURIOrFile()
- // -> PaymentServer::readPaymentRequestFromFile()
- // -> PaymentServer::processPaymentRequest()
-
- // Contains a testnet paytoaddress, so payment request network doesn't match client network:
- data = DecodeBase64(paymentrequest1_cert2_BASE64);
- byteArray = QByteArray((const char*)data.data(), data.size());
- r.paymentRequest.parse(byteArray);
- // Ensure the request is initialized, because network "main" is default, even for
- // uninitialized payment requests and that will fail our test here.
- QVERIFY(r.paymentRequest.IsInitialized());
- QCOMPARE(PaymentServer::verifyNetwork(*node, r.paymentRequest.getDetails()), false);
-
- // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
- data = DecodeBase64(paymentrequest2_cert2_BASE64);
- byteArray = QByteArray((const char*)data.data(), data.size());
- r.paymentRequest.parse(byteArray);
- // Ensure the request is initialized
- QVERIFY(r.paymentRequest.IsInitialized());
- // compares 1 < GetTime() == false (treated as expired payment request)
- QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);
-
- // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t):
- // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
- // -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
- data = DecodeBase64(paymentrequest3_cert2_BASE64);
- byteArray = QByteArray((const char*)data.data(), data.size());
- r.paymentRequest.parse(byteArray);
- // Ensure the request is initialized
- QVERIFY(r.paymentRequest.IsInitialized());
- // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request)
- QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false);
-
- // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64):
- // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
- // 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
- data = DecodeBase64(paymentrequest4_cert2_BASE64);
- byteArray = QByteArray((const char*)data.data(), data.size());
- r.paymentRequest.parse(byteArray);
- // Ensure the request is initialized
- QVERIFY(r.paymentRequest.IsInitialized());
- // compares -9223372036854775808 < GetTime() == true (treated as expired payment request)
- QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);
-
- // Test BIP70 DoS protection:
- auto randdata = FastRandomContext().randbytes(BIP70_MAX_PAYMENTREQUEST_SIZE + 1);
-
- // Write data to a temp file:
- QTemporaryFile tempFile;
- tempFile.open();
- tempFile.write((const char*)randdata.data(), randdata.size());
- tempFile.close();
- // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
- QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);
-
- // Payment request with amount overflow (amount is set to 21000001 BTC):
- data = DecodeBase64(paymentrequest5_cert2_BASE64);
- byteArray = QByteArray((const char*)data.data(), data.size());
- r.paymentRequest.parse(byteArray);
- // Ensure the request is initialized
- QVERIFY(r.paymentRequest.IsInitialized());
- // Extract address and amount from the request
- QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
- for (const std::pair<CScript, CAmount>& sendingTo : sendingTos) {
- CTxDestination dest;
- if (ExtractDestination(sendingTo.first, dest))
- QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
- }
-
- delete server;
-}
-
-void RecipientCatcher::getRecipient(const SendCoinsRecipient& r)
-{
- recipient = r;
-}
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
deleted file mode 100644
index 7ef7a0a641..0000000000
--- a/src/qt/test/paymentservertests.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2009-2018 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_PAYMENTSERVERTESTS_H
-#define BITCOIN_QT_TEST_PAYMENTSERVERTESTS_H
-
-#include <qt/paymentserver.h>
-
-#include <QObject>
-#include <QTest>
-
-class PaymentServerTests : public QObject
-{
- Q_OBJECT
-
-private Q_SLOTS:
- void paymentServerTests();
-};
-
-// Dummy class to receive paymentserver signals.
-// If SendCoinsRecipient was a proper QObject, then
-// we could use QSignalSpy... but it's not.
-class RecipientCatcher : public QObject
-{
- Q_OBJECT
-
-public Q_SLOTS:
- void getRecipient(const SendCoinsRecipient& r);
-
-public:
- SendCoinsRecipient recipient;
-};
-
-#endif // BITCOIN_QT_TEST_PAYMENTSERVERTESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index c39266a397..f272627f96 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -16,9 +16,6 @@
#ifdef ENABLE_WALLET
#include <qt/test/addressbooktests.h>
-#ifdef ENABLE_BIP70
-#include <qt/test/paymentservertests.h>
-#endif // ENABLE_BIP70
#include <qt/test/wallettests.h>
#endif // ENABLE_WALLET
@@ -79,12 +76,6 @@ int main(int argc, char *argv[])
if (QTest::qExec(&test1) != 0) {
fInvalid = true;
}
-#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
- PaymentServerTests test2;
- if (QTest::qExec(&test2) != 0) {
- fInvalid = true;
- }
-#endif
RPCNestedTests test3;
if (QTest::qExec(&test3) != 0) {
fInvalid = true;
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 44ce5265cd..318b0756c7 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -48,7 +48,6 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i
}
}
-#ifndef ENABLE_BIP70
// Takes an encoded PaymentRequest as a string and tries to find the Common Name of the X.509 certificate
// used to sign the PaymentRequest.
bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant)
@@ -76,7 +75,6 @@ bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant)
}
return false;
}
-#endif
QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
{
@@ -294,19 +292,11 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
if (r.first == "PaymentRequest")
{
QString merchant;
-#ifdef ENABLE_BIP70
- PaymentRequestPlus req;
- req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
- if (!req.getMerchant(PaymentServer::getCertStore(), merchant)) {
- merchant.clear();
- }
-#else
if (!GetPaymentRequestMerchant(r.second, merchant)) {
merchant.clear();
} else {
merchant += tr(" (Certificate was not verified)");
}
-#endif
if (!merchant.isNull()) {
strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
}
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 6509a701f3..095c98d26f 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -11,9 +11,6 @@
#include <qt/forms/ui_helpmessagedialog.h>
#include <qt/bitcoingui.h>
-#ifdef ENABLE_BIP70
-#include <qt/paymentrequestplus.h>
-#endif
#include <clientversion.h>
#include <init.h>
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index a7edf442e5..4c253f8ddd 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -109,6 +109,12 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
wallet_model->setParent(this);
m_wallets.push_back(wallet_model);
+ // WalletModel::startPollBalance needs to be called in a thread managed by
+ // Qt because of startTimer. Considering the current thread can be a RPC
+ // thread, better delegate the calling to Qt with Qt::AutoConnection.
+ const bool called = QMetaObject::invokeMethod(wallet_model, "startPollBalance");
+ assert(called);
+
connect(wallet_model, &WalletModel::unload, [this, wallet_model] {
// Defer removeAndDeleteWallet when no modal widget is active.
// TODO: remove this workaround by removing usage of QDiallog::exec.
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 5bc72125f6..33801d3907 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -44,11 +44,6 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces:
transactionTableModel = new TransactionTableModel(platformStyle, this);
recentRequestsTableModel = new RecentRequestsTableModel(this);
- // This timer will be fired repeatedly to update the balance
- pollTimer = new QTimer(this);
- connect(pollTimer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged);
- pollTimer->start(MODEL_UPDATE_DELAY);
-
subscribeToCoreSignals();
}
@@ -57,6 +52,14 @@ WalletModel::~WalletModel()
unsubscribeFromCoreSignals();
}
+void WalletModel::startPollBalance()
+{
+ // This timer will be fired repeatedly to update the balance
+ QTimer* timer = new QTimer(this);
+ connect(timer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged);
+ timer->start(MODEL_UPDATE_DELAY);
+}
+
void WalletModel::updateStatus()
{
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
@@ -143,31 +146,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
if (rcp.fSubtractFeeFromAmount)
fSubtractFeeFromAmount = true;
-
-#ifdef ENABLE_BIP70
- if (rcp.paymentRequest.IsInitialized())
- { // PaymentRequest...
- CAmount subtotal = 0;
- const payments::PaymentDetails& details = rcp.paymentRequest.getDetails();
- for (int i = 0; i < details.outputs_size(); i++)
- {
- const payments::Output& out = details.outputs(i);
- if (out.amount() <= 0) continue;
- subtotal += out.amount();
- const unsigned char* scriptStr = (const unsigned char*)out.script().data();
- CScript scriptPubKey(scriptStr, scriptStr+out.script().size());
- CAmount nAmount = out.amount();
- CRecipient recipient = {scriptPubKey, nAmount, rcp.fSubtractFeeFromAmount};
- vecSend.push_back(recipient);
- }
- if (subtotal <= 0)
- {
- return InvalidAmount;
- }
- total += subtotal;
- }
- else
-#endif
{ // User-entered bitcoin address / amount:
if(!validateAddress(rcp.address))
{
@@ -240,21 +218,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
std::vector<std::pair<std::string, std::string>> vOrderForm;
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
-#ifdef ENABLE_BIP70
- if (rcp.paymentRequest.IsInitialized())
- {
- // Make sure any payment requests involved are still valid.
- if (PaymentServer::verifyExpired(rcp.paymentRequest.getDetails())) {
- return PaymentRequestExpired;
- }
-
- // Store PaymentRequests in wtx.vOrderForm in wallet.
- std::string value;
- rcp.paymentRequest.SerializeToString(&value);
- vOrderForm.emplace_back("PaymentRequest", std::move(value));
- }
- else
-#endif
if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
vOrderForm.emplace_back("Message", rcp.message.toStdString());
}
@@ -271,10 +234,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
// and emit coinsSent signal for each recipient
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
- // Don't touch the address book when we have a payment request
-#ifdef ENABLE_BIP70
- if (!rcp.paymentRequest.IsInitialized())
-#endif
{
std::string strAddress = rcp.address.toStdString();
CTxDestination dest = DecodeDestination(strAddress);
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index d180c9f8c4..d21dec118a 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -5,18 +5,15 @@
#ifndef BITCOIN_QT_WALLETMODEL_H
#define BITCOIN_QT_WALLETMODEL_H
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <amount.h>
#include <key.h>
#include <serialize.h>
#include <script/standard.h>
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#ifdef ENABLE_BIP70
-#include <qt/paymentrequestplus.h>
-#endif
#include <qt/walletmodeltransaction.h>
#include <interfaces/wallet.h>
@@ -67,15 +64,9 @@ public:
CAmount amount;
// If from a payment request, this is used for storing the memo
QString message;
-
-#ifdef ENABLE_BIP70
- // If from a payment request, paymentRequest.IsInitialized() will be true
- PaymentRequestPlus paymentRequest;
-#else
// If building with BIP70 is disabled, keep the payment request around as
// serialized string to ensure load/store is lossless
std::string sPaymentRequest;
-#endif
// Empty if no authentication or invalid signature/cert/etc.
QString authenticatedMerchant;
@@ -91,11 +82,6 @@ public:
std::string sAddress = address.toStdString();
std::string sLabel = label.toStdString();
std::string sMessage = message.toStdString();
-#ifdef ENABLE_BIP70
- std::string sPaymentRequest;
- if (!ser_action.ForRead() && paymentRequest.IsInitialized())
- paymentRequest.SerializeToString(&sPaymentRequest);
-#endif
std::string sAuthenticatedMerchant = authenticatedMerchant.toStdString();
READWRITE(this->nVersion);
@@ -111,10 +97,6 @@ public:
address = QString::fromStdString(sAddress);
label = QString::fromStdString(sLabel);
message = QString::fromStdString(sMessage);
-#ifdef ENABLE_BIP70
- if (!sPaymentRequest.empty())
- paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size()));
-#endif
authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
}
}
@@ -253,8 +235,6 @@ private:
EncryptionStatus cachedEncryptionStatus;
int cachedNumBlocks;
- QTimer *pollTimer;
-
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
void checkBalanceChanged(const interfaces::WalletBalances& new_balances);
@@ -290,6 +270,9 @@ Q_SIGNALS:
void canGetAddressesChanged();
public Q_SLOTS:
+ /* Starts a timer to periodically update the balance */
+ void startPollBalance();
+
/* Wallet status might have changed */
void updateStatus();
/* New transaction, or transaction changed status */
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index d00ccf70d9..eba95bd27c 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -48,25 +48,6 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
for (QList<SendCoinsRecipient>::iterator it = recipients.begin(); it != recipients.end(); ++it)
{
SendCoinsRecipient& rcp = (*it);
-
-#ifdef ENABLE_BIP70
- if (rcp.paymentRequest.IsInitialized())
- {
- CAmount subtotal = 0;
- const payments::PaymentDetails& details = rcp.paymentRequest.getDetails();
- for (int j = 0; j < details.outputs_size(); j++)
- {
- const payments::Output& out = details.outputs(j);
- if (out.amount() <= 0) continue;
- if (i == nChangePosRet)
- i++;
- subtotal += walletTransaction->vout[i].nValue;
- i++;
- }
- rcp.amount = subtotal;
- }
- else // normal recipient (no payment request)
-#endif
{
if (i == nChangePosRet)
i++;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 4bbd4aaf64..fac6bcd60d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -10,11 +10,11 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
-#include <node/coinstats.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <hash.h>
#include <index/blockfilterindex.h>
+#include <node/coinstats.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@@ -34,7 +34,6 @@
#include <validationinterface.h>
#include <warnings.h>
-#include <assert.h>
#include <stdint.h>
#include <univalue.h>
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index d289274a37..d73dd6e52d 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -3,15 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <key_io.h>
#include <httpserver.h>
+#include <key_io.h>
#include <outputtype.h>
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
-#include <util/system.h>
+#include <util/check.h>
#include <util/strencodings.h>
+#include <util/system.h>
#include <util/validation.h>
#include <stdint.h>
@@ -540,6 +541,7 @@ static UniValue echo(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"echo|echojson ...",
"\nSimply echo back the input arguments. This command is for testing.\n"
+ "\nIt will return an internal bug report when exactly 100 arguments are passed.\n"
"\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
"bitcoin-cli and the GUI. There is no server-side difference.",
{},
@@ -548,6 +550,8 @@ static UniValue echo(const JSONRPCRequest& request)
}.ToString()
);
+ CHECK_NONFATAL(request.params.size() != 100);
+
return request.params;
}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 72fc7b6286..ec36956c95 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -7,14 +7,15 @@
#include <node/transaction.h>
#include <outputtype.h>
-#include <pubkey.h>
#include <protocol.h>
+#include <pubkey.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/standard.h>
#include <univalue.h>
+#include <util/check.h>
#include <string>
#include <vector>
@@ -146,7 +147,7 @@ struct RPCArg {
m_oneline_description{oneline_description},
m_type_str{type_str}
{
- assert(type != Type::ARR && type != Type::OBJ);
+ CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ);
}
RPCArg(
@@ -165,7 +166,7 @@ struct RPCArg {
m_oneline_description{oneline_description},
m_type_str{type_str}
{
- assert(type == Type::ARR || type == Type::OBJ);
+ CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ);
}
bool IsOptional() const;
@@ -194,14 +195,14 @@ struct RPCResult {
explicit RPCResult(std::string result)
: m_cond{}, m_result{std::move(result)}
{
- assert(!m_result.empty());
+ CHECK_NONFATAL(!m_result.empty());
}
RPCResult(std::string cond, std::string result)
: m_cond{std::move(cond)}, m_result{std::move(result)}
{
- assert(!m_cond.empty());
- assert(!m_result.empty());
+ CHECK_NONFATAL(!m_cond.empty());
+ CHECK_NONFATAL(!m_result.empty());
}
};
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index e8f149470e..c6a08b293f 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -4,6 +4,7 @@
#include <compressor.h>
#include <test/setup_common.h>
+#include <script/standard.h>
#include <stdint.h>
@@ -61,4 +62,76 @@ BOOST_AUTO_TEST_CASE(compress_amounts)
BOOST_CHECK(TestDecode(i));
}
+BOOST_AUTO_TEST_CASE(compress_script_to_ckey_id)
+{
+ // case CKeyID
+ CKey key;
+ key.MakeNewKey(true);
+ CPubKey pubkey = key.GetPubKey();
+
+ CScript script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK_EQUAL(script.size(), 25);
+
+ std::vector<unsigned char> out;
+ bool done = CompressScript(script, out);
+ BOOST_CHECK_EQUAL(done, true);
+
+ // Check compressed script
+ BOOST_CHECK_EQUAL(out.size(), 21);
+ BOOST_CHECK_EQUAL(out[0], 0x00);
+ BOOST_CHECK_EQUAL(memcmp(&out[1], &script[3], 20), 0); // compare the 20 relevant chars of the CKeyId in the script
+}
+
+BOOST_AUTO_TEST_CASE(compress_script_to_cscript_id)
+{
+ // case CScriptID
+ CScript script, redeemScript;
+ script << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK_EQUAL(script.size(), 23);
+
+ std::vector<unsigned char> out;
+ bool done = CompressScript(script, out);
+ BOOST_CHECK_EQUAL(done, true);
+
+ // Check compressed script
+ BOOST_CHECK_EQUAL(out.size(), 21);
+ BOOST_CHECK_EQUAL(out[0], 0x01);
+ BOOST_CHECK_EQUAL(memcmp(&out[1], &script[2], 20), 0); // compare the 20 relevant chars of the CScriptId in the script
+}
+
+BOOST_AUTO_TEST_CASE(compress_script_to_compressed_pubkey_id)
+{
+ CKey key;
+ key.MakeNewKey(true); // case compressed PubKeyID
+
+ CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // COMPRESSED_PUBLIC_KEY_SIZE (33)
+ BOOST_CHECK_EQUAL(script.size(), 35);
+
+ std::vector<unsigned char> out;
+ bool done = CompressScript(script, out);
+ BOOST_CHECK_EQUAL(done, true);
+
+ // Check compressed script
+ BOOST_CHECK_EQUAL(out.size(), 33);
+ BOOST_CHECK_EQUAL(memcmp(&out[0], &script[1], 1), 0);
+ BOOST_CHECK_EQUAL(memcmp(&out[1], &script[2], 32), 0); // compare the 32 chars of the compressed CPubKey
+}
+
+BOOST_AUTO_TEST_CASE(compress_script_to_uncompressed_pubkey_id)
+{
+ CKey key;
+ key.MakeNewKey(false); // case uncompressed PubKeyID
+ CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // PUBLIC_KEY_SIZE (65)
+ BOOST_CHECK_EQUAL(script.size(), 67); // 1 char code + 65 char pubkey + OP_CHECKSIG
+
+ std::vector<unsigned char> out;
+ bool done = CompressScript(script, out);
+ BOOST_CHECK_EQUAL(done, true);
+
+ // Check compressed script
+ BOOST_CHECK_EQUAL(out.size(), 33);
+ BOOST_CHECK_EQUAL(memcmp(&out[1], &script[2], 32), 0); // first 32 chars of CPubKey are copied into out[1:]
+ BOOST_CHECK_EQUAL(out[0], 0x04 | (script[65] & 0x01)); // least significant bit (lsb) of last char of pubkey is mapped into out[0]
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
new file mode 100644
index 0000000000..0469e87de6
--- /dev/null
+++ b/src/test/fuzz/script.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 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.
+
+#include <chainparams.h>
+#include <compressor.h>
+#include <core_io.h>
+#include <core_memusage.h>
+#include <policy/policy.h>
+#include <pubkey.h>
+#include <script/descriptor.h>
+#include <script/script.h>
+#include <script/sign.h>
+#include <script/signingprovider.h>
+#include <script/standard.h>
+#include <streams.h>
+#include <test/fuzz/fuzz.h>
+#include <util/memory.h>
+
+void initialize()
+{
+ // Fuzzers using pubkey must hold an ECCVerifyHandle.
+ static const auto verify_handle = MakeUnique<ECCVerifyHandle>();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ const CScript script(buffer.begin(), buffer.end());
+
+ std::vector<unsigned char> compressed;
+ (void)CompressScript(script, compressed);
+
+ CTxDestination address;
+ (void)ExtractDestination(script, address);
+
+ txnouttype type_ret;
+ std::vector<CTxDestination> addresses;
+ int required_ret;
+ (void)ExtractDestinations(script, type_ret, addresses, required_ret);
+
+ (void)GetScriptForWitness(script);
+
+ const FlatSigningProvider signing_provider;
+ (void)InferDescriptor(script, signing_provider);
+
+ (void)IsSegWitOutput(signing_provider, script);
+
+ (void)IsSolvable(signing_provider, script);
+
+ txnouttype which_type;
+ (void)IsStandard(script, which_type);
+
+ (void)RecursiveDynamicUsage(script);
+
+ std::vector<std::vector<unsigned char>> solutions;
+ (void)Solver(script, solutions);
+
+ (void)script.HasValidOps();
+ (void)script.IsPayToScriptHash();
+ (void)script.IsPayToWitnessScriptHash();
+ (void)script.IsPushOnly();
+ (void)script.IsUnspendable();
+ (void)script.GetSigOpCount(/* fAccurate= */ false);
+}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 96d7947b07..383d879040 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -43,12 +43,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
CValidationState state_with_dupe_check;
- const bool valid_with_dupe_check = CheckTransaction(tx, state_with_dupe_check, /* fCheckDuplicateInputs= */ true);
- CValidationState state_without_dupe_check;
- const bool valid_without_dupe_check = CheckTransaction(tx, state_without_dupe_check, /* fCheckDuplicateInputs= */ false);
- if (valid_with_dupe_check) {
- assert(valid_without_dupe_check);
- }
+ (void)CheckTransaction(tx, state_with_dupe_check);
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
std::string reason;
diff --git a/src/util/check.h b/src/util/check.h
new file mode 100644
index 0000000000..d18887ae95
--- /dev/null
+++ b/src/util/check.h
@@ -0,0 +1,41 @@
+// Copyright (c) 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.
+
+#ifndef BITCOIN_UTIL_CHECK_H
+#define BITCOIN_UTIL_CHECK_H
+
+#include <tinyformat.h>
+
+#include <stdexcept>
+
+class NonFatalCheckError : public std::runtime_error
+{
+ using std::runtime_error::runtime_error;
+};
+
+/**
+ * Throw a NonFatalCheckError when the condition evaluates to false
+ *
+ * This should only be used
+ * - where the condition is assumed to be true, not for error handling or validating user input
+ * - where a failure to fulfill the condition is recoverable and does not abort the program
+ *
+ * For example in RPC code, where it is undersirable to crash the whole program, this can be generally used to replace
+ * asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC
+ * caller, which can then report the issue to the developers.
+ */
+#define CHECK_NONFATAL(condition) \
+ do { \
+ if (!(condition)) { \
+ throw NonFatalCheckError( \
+ strprintf("%s:%d (%s)\n" \
+ "Internal bug detected: '%s'\n" \
+ "You may report this issue here: %s\n", \
+ __FILE__, __LINE__, __func__, \
+ (#condition), \
+ PACKAGE_BUGREPORT)); \
+ } \
+ } while (false)
+
+#endif // BITCOIN_UTIL_CHECK_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 70b847d3b0..9301066c6a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -392,7 +392,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
// were somehow broken and returning the wrong scriptPubKeys
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
- unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
+ unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
// pool.cs should be locked already, but go ahead and re-take the lock here
@@ -422,7 +422,8 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
}
}
- return CheckInputs(tx, state, view, flags, cacheSigStore, true, txdata);
+ // Call CheckInputs() to cache signature and script validity against current tip consensus rules.
+ return CheckInputs(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata);
}
namespace {
@@ -959,7 +960,7 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp
// invalid blocks (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack.
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(::ChainActive().Tip(), chainparams.GetConsensus());
- if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, true, txdata)) {
+ if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata)) {
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
}
@@ -3301,9 +3302,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
// Check transactions
- // Must check for duplicate inputs (see CVE-2018-17144)
for (const auto& tx : block.vtx)
- if (!CheckTransaction(*tx, state, true))
+ if (!CheckTransaction(*tx, state))
return state.Invalid(state.GetReason(), false, state.GetRejectReason(),
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));