Send TX and messages to .onion addresses
Build All Platforms / test-linux-unit (push) Failing after 40s
Build All Platforms / build-linux-qt (push) Failing after 40s
Build All Platforms / build-linux-daemon (push) Failing after 40s
Build All Platforms / build-windows-qt (push) Has been cancelled
Build All Platforms / build-windows-daemon (push) Has been cancelled
Build All Platforms / build-macos (push) Has been cancelled
Build All Platforms / release (push) Has been cancelled
Build All Platforms / Trigger TRI-PI ARM64 Build (push) Has been cancelled

- 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 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 23:07:12 -07:00
parent 310a2b7371
commit 0d6e143398
7 changed files with 99 additions and 5 deletions
+11
View File
@@ -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);
+33
View File
@@ -15,9 +15,11 @@
#include "coincontrol.h"
#include "coincontroldialog.h"
#include "tor/onion_v3.h"
#include <QMessageBox>
#include <QLocale>
#include <QApplication>
#include <QTextDocument>
#include <QScrollBar>
#include <QClipboard>
@@ -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)
+1 -1
View File
@@ -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);
+30
View File
@@ -8,6 +8,7 @@
#include "sendmessagesentry.h"
#include "dialog_move_handler.h"
#include "guiutil.h"
#include "tor/onion_v3.h"
#include <QMessageBox>
#include <QLocale>
@@ -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)
+1 -1
View File
@@ -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
+17 -1
View File
@@ -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<input.size(); ++idx)
{
int ch = input.at(idx).unicode();
if(((ch >= '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')
+6 -2
View File
@@ -9,6 +9,7 @@
#include "walletdb.h" // for BackupWallet
#include "base58.h"
#include "main.h"
#include "tor/onion_v3.h"
#include <QSet>
#include <QTimer>
@@ -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();
}