From 0d6e143398870787bbcecccc4f5f9f4b9c2589df Mon Sep 17 00:00:00 2001 From: Sami Ahmed Date: Thu, 9 Apr 2026 23:07:12 -0700 Subject: [PATCH] Send TX and messages to .onion addresses - Address validator accepts V3 .onion format (62 chars, base32 + .onion) - WalletModel::validateAddress() recognizes .onion via ValidateOnionAddress() - Send coins/messages dialogs resolve .onion to TRI before sending - Auto-request getwalletaddr from onion peers after version handshake - Placeholder text updated to "Enter a TRI address or .onion address" - Shows info dialog if resolution is pending (async connect + resolve) Co-Authored-By: Claude Opus 4.6 --- src/main.cpp | 11 ++++++++++ src/qt/sendcoinsdialog.cpp | 33 ++++++++++++++++++++++++++++ src/qt/sendcoinsentry.cpp | 2 +- src/qt/sendmessagesdialog.cpp | 30 +++++++++++++++++++++++++ src/qt/sendmessagesentry.cpp | 2 +- src/qt/trianglesaddressvalidator.cpp | 18 ++++++++++++++- src/qt/walletmodel.cpp | 8 +++++-- 7 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index be7ee5d..ad712f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4064,6 +4064,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->fSuccessfullyConnected = true; + // If this is an onion peer and we have a pending resolve, request their wallet address + { + std::string peerAddr = pfrom->addr.ToStringIP(); + if (peerAddr.find(".onion") != std::string::npos) + { + CTorV3Manager* torMgr = CTorV3Manager::GetInstance(); + if (torMgr) + torMgr->RequestWalletAddress(pfrom); + } + } + printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); cPeerBlockCounts.input(pfrom->nStartingHeight); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 98680d3..40ecf38 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -15,9 +15,11 @@ #include "coincontrol.h" #include "coincontroldialog.h" +#include "tor/onion_v3.h" #include #include +#include #include #include #include @@ -145,6 +147,37 @@ void SendCoinsDialog::on_sendButton_clicked() return; } + // Resolve any .onion addresses to TRI addresses + CTorV3Manager* torMgr = CTorV3Manager::GetInstance(); + for(int i = 0; i < recipients.size(); ++i) + { + std::string addr = recipients[i].address.toStdString(); + if (addr.size() == 62 && addr.substr(addr.size() - 6) == ".onion") + { + std::string triAddr; + if (torMgr && torMgr->LookupCachedOnionAddress(addr, triAddr)) + { + // Found in cache — substitute + recipients[i].address = QString::fromStdString(triAddr); + if (recipients[i].label.isEmpty()) + recipients[i].label = QString::fromStdString(addr); + } + else + { + // Not cached — initiate async resolution and tell user to wait + if (torMgr) + torMgr->ResolveOnionAddress(addr, triAddr); + + QMessageBox::information(this, tr("Resolving .onion Address"), + tr("Connecting to %1 to resolve their TRI address.\n\n" + "Please wait a moment and try again.") + .arg(recipients[i].address)); + fNewRecipientAllowed = true; + return; + } + } + } + // Format confirmation message QStringList formatted; foreach(const SendCoinsRecipient &rcp, recipients) diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 30d7931..78481cd 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -23,7 +23,7 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) : #if QT_VERSION >= 0x040700 /* Do not move this to the XML file, Qt before 4.7 will choke on it */ ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); - ui->payTo->setPlaceholderText(tr("Enter a TRI address (e.g. TXc7mPCNFFpinDonuSH5PNVY9S8nBcvGQm)")); + ui->payTo->setPlaceholderText(tr("Enter a TRI address or .onion address")); ui->narration->setPlaceholderText(tr("Enter a short note to send with payment. This feature will be enabled later.")); ui->narration->setEnabled(false); ui->narration->setVisible(false); diff --git a/src/qt/sendmessagesdialog.cpp b/src/qt/sendmessagesdialog.cpp index cee0b5f..f079c4b 100644 --- a/src/qt/sendmessagesdialog.cpp +++ b/src/qt/sendmessagesdialog.cpp @@ -8,6 +8,7 @@ #include "sendmessagesentry.h" #include "dialog_move_handler.h" #include "guiutil.h" +#include "tor/onion_v3.h" #include #include @@ -155,6 +156,35 @@ void SendMessagesDialog::on_sendButton_clicked() if(!valid || recipients.isEmpty()) return; + // Resolve any .onion addresses to TRI addresses + CTorV3Manager* torMgr = CTorV3Manager::GetInstance(); + for(int i = 0; i < recipients.size(); ++i) + { + std::string addr = recipients[i].address.toStdString(); + if (addr.size() == 62 && addr.substr(addr.size() - 6) == ".onion") + { + std::string triAddr; + if (torMgr && torMgr->LookupCachedOnionAddress(addr, triAddr)) + { + recipients[i].address = QString::fromStdString(triAddr); + if (recipients[i].label.isEmpty()) + recipients[i].label = QString::fromStdString(addr); + } + else + { + if (torMgr) + torMgr->ResolveOnionAddress(addr, triAddr); + + QMessageBox::information(this, tr("Resolving .onion Address"), + tr("Connecting to %1 to resolve their TRI address.\n\n" + "Please wait a moment and try again.") + .arg(recipients[i].address)); + fNewRecipientAllowed = true; + return; + } + } + } + // Format confirmation message QStringList formatted; foreach(const SendMessagesRecipient &rcp, recipients) diff --git a/src/qt/sendmessagesentry.cpp b/src/qt/sendmessagesentry.cpp index ab3719a..5b99184 100644 --- a/src/qt/sendmessagesentry.cpp +++ b/src/qt/sendmessagesentry.cpp @@ -25,7 +25,7 @@ SendMessagesEntry::SendMessagesEntry(QWidget *parent) : #if QT_VERSION >= 0x040700 /* Do not move this to the XML file, Qt before 4.7 will choke on it */ ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); - ui->sendTo->setPlaceholderText(tr("Enter a TRI address (e.g. TXc7mPCNFFpinDonuSH5PNVY9S8nBcvGQm)")); + ui->sendTo->setPlaceholderText(tr("Enter a TRI address or .onion address")); ui->publicKey->setPlaceholderText(tr("Enter the public key for the address above, it is not in the blockchain")); ui->messageText->setErrorText(tr("You cannot send a blank message!")); #endif diff --git a/src/qt/trianglesaddressvalidator.cpp b/src/qt/trianglesaddressvalidator.cpp index 50a7492..d6179a1 100644 --- a/src/qt/trianglesaddressvalidator.cpp +++ b/src/qt/trianglesaddressvalidator.cpp @@ -50,11 +50,27 @@ QValidator::State TrianglesAddressValidator::validate(QString &input, int &pos) // Validation QValidator::State state = QValidator::Acceptable; + + // Allow .onion addresses (base32 lowercase + digits 2-7 + period) + bool isOnion = input.endsWith(".onion"); + for(int idx=0; idx= '0' && ch<='9') || + if (isOnion) + { + // V3 onion: base32 (a-z, 2-7) + ".onion" suffix + if ((ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7') || ch == '.') + { + // Valid onion character + } + else + { + state = QValidator::Invalid; + } + } + else if(((ch >= '0' && ch<='9') || (ch >= 'a' && ch<='z') || (ch >= 'A' && ch<='Z')) && ch != 'l' && ch != 'I' && ch != '0' && ch != 'O') diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 11ae465..c7fdeed 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -9,6 +9,7 @@ #include "walletdb.h" // for BackupWallet #include "base58.h" #include "main.h" +#include "tor/onion_v3.h" #include #include @@ -281,8 +282,11 @@ void WalletModel::updateAddressBook(const QString &address, const QString &label bool WalletModel::validateAddress(const QString &address) { std::string sAddr = address.toStdString(); - - + + // Accept V3 .onion addresses (56-char base32 + ".onion" = 62 chars) + if (sAddr.size() == 62 && sAddr.substr(sAddr.size() - 6) == ".onion") + return CTorV3Service::ValidateOnionAddress(sAddr); + CTrianglesAddress addressParsed(sAddr); return addressParsed.IsValid(); }