Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <qt/paymentserver.h>7#include <qt/bitcoinunits.h>8#include <qt/guiutil.h>9#include <qt/optionsmodel.h>11#include <chainparams.h>12#include <common/args.h>13#include <interfaces/node.h>14#include <key_io.h>15#include <node/interface_ui.h>16#include <policy/policy.h>17#include <wallet/wallet.h>19#include <cstdlib>20#include <memory>22#include <QApplication>23#include <QByteArray>24#include <QDataStream>25#include <QDebug>26#include <QFile>27#include <QFileOpenEvent>28#include <QHash>29#include <QList>30#include <QLocalServer>31#include <QLocalSocket>32#include <QStringList>33#include <QUrlQuery>35const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds36const QString BITCOIN_IPC_PREFIX("bitcoin:");38//39// Create a name that is unique for:40// testnet / non-testnet41// data directory42//43static QString ipcServerName()44{45QString name("BitcoinQt");47// Append a simple hash of the datadir48// Note that gArgs.GetDataDirNet() returns a different path49// for -testnet versus main net50QString ddir(GUIUtil::PathToQString(gArgs.GetDataDirNet()));51name.append(QString::number(qHash(ddir)));53return name;54}56//57// We store payment URIs and requests received before58// the main GUI window is up and ready to ask the user59// to send payment.61static QSet<QString> savedPaymentRequests;63//64// Sending to the server is done synchronously, at startup.65// If the server isn't already running, startup continues,66// and the items in savedPaymentRequest will be handled67// when uiReady() is called.68//69// Warning: ipcSendCommandLine() is called early in init,70// so don't use "Q_EMIT message()", but "QMessageBox::"!71//72void PaymentServer::ipcParseCommandLine(int argc, char* argv[])73{74for (int i = 1; i < argc; i++)75{76QString arg(argv[i]);77if (arg.startsWith("-")) continue;79if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI80{81savedPaymentRequests.insert(arg);82}83}84}86//87// Sending to the server is done synchronously, at startup.88// If the server isn't already running, startup continues,89// and the items in savedPaymentRequest will be handled90// when uiReady() is called.91//92bool PaymentServer::ipcSendCommandLine()93{94bool fResult = false;95for (const QString& r : savedPaymentRequests)96{97QLocalSocket* socket = new QLocalSocket();98socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);99if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))100{101delete socket;102socket = nullptr;103return false;104}106QByteArray block;107QDataStream out(&block, QIODevice::WriteOnly);108out.setVersion(QDataStream::Qt_4_0);109out << r;110out.device()->seek(0);112socket->write(block);113socket->flush();114socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT);115socket->disconnectFromServer();117delete socket;118socket = nullptr;119fResult = true;120}122return fResult;123}125PaymentServer::PaymentServer(QObject* parent, bool startLocalServer)126: QObject(parent)127{128// Install global event filter to catch QFileOpenEvents129// on Mac: sent when you click bitcoin: links130// other OSes: helpful when dealing with payment request files131if (parent)132parent->installEventFilter(this);134QString name = ipcServerName();136// Clean up old socket leftover from a crash:137QLocalServer::removeServer(name);139if (startLocalServer)140{141uriServer = new QLocalServer(this);143if (!uriServer->listen(name)) {144// constructor is called early in init, so don't use "Q_EMIT message()" here145QMessageBox::critical(nullptr, tr("Payment request error"),146tr("Cannot start bitcoin: click-to-pay handler"));147}148else {149connect(uriServer, &QLocalServer::newConnection, this, &PaymentServer::handleURIConnection);150}151}152}154PaymentServer::~PaymentServer() = default;156//157// OSX-specific way of handling bitcoin: URIs158//159bool PaymentServer::eventFilter(QObject *object, QEvent *event)160{161if (event->type() == QEvent::FileOpen) {162QFileOpenEvent *fileEvent = static_cast<QFileOpenEvent*>(event);163if (!fileEvent->file().isEmpty())164handleURIOrFile(fileEvent->file());165else if (!fileEvent->url().isEmpty())166handleURIOrFile(fileEvent->url().toString());168return true;169}171return QObject::eventFilter(object, event);172}174void PaymentServer::uiReady()175{176saveURIs = false;177for (const QString& s : savedPaymentRequests)178{179handleURIOrFile(s);180}181savedPaymentRequests.clear();182}184void PaymentServer::handleURIOrFile(const QString& s)185{186if (saveURIs)187{188savedPaymentRequests.insert(s);189return;190}192if (s.startsWith("bitcoin://", Qt::CaseInsensitive))193{194Q_EMIT message(tr("URI handling"), tr("'bitcoin://' is not a valid URI. Use 'bitcoin:' instead."),195CClientUIInterface::MSG_ERROR);196}197else if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI198{199QUrlQuery uri((QUrl(s)));200// normal URI201{202SendCoinsRecipient recipient;203if (GUIUtil::parseBitcoinURI(s, &recipient))204{205std::string error_msg;206const CTxDestination dest = DecodeDestination(recipient.address.toStdString(), error_msg);208if (!IsValidDestination(dest)) {209if (uri.hasQueryItem("r")) { // payment request210Q_EMIT message(tr("URI handling"),211tr("Cannot process payment request because BIP70 is not supported.\n"212"Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.\n"213"If you are receiving this error you should request the merchant provide a BIP21 compatible URI."),214CClientUIInterface::ICON_WARNING);215}216Q_EMIT message(tr("URI handling"), QString::fromStdString(error_msg),217CClientUIInterface::MSG_ERROR);218}219else220Q_EMIT receivedPaymentRequest(recipient);221}222else223Q_EMIT message(tr("URI handling"),224tr("URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),225CClientUIInterface::ICON_WARNING);227return;228}229}231if (QFile::exists(s)) // payment request file232{233Q_EMIT message(tr("Payment request file handling"),234tr("Cannot process payment request because BIP70 is not supported.\n"235"Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.\n"236"If you are receiving this error you should request the merchant provide a BIP21 compatible URI."),237CClientUIInterface::ICON_WARNING);238}239}241void PaymentServer::handleURIConnection()242{243QLocalSocket *clientConnection = uriServer->nextPendingConnection();245while (clientConnection->bytesAvailable() < (int)sizeof(quint32))246clientConnection->waitForReadyRead();248connect(clientConnection, &QLocalSocket::disconnected, clientConnection, &QLocalSocket::deleteLater);250QDataStream in(clientConnection);
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.