fix(chat): stop our own sent messages appearing as incoming duplicates

Two causes of the "every message I send shows up again as a reply from the peer":

1. Harvest bug — the full-refresh path fed a SENT tx's outgoing memos (from
   z_viewtransaction outgoing outputs) into the chat metadata extractor, and
   ChatService::ingest marks everything Incoming. So each send was re-ingested as
   a phantom "from peer" message. The recent-refresh path already omitted this, so
   it was accidental. Drop the outgoing chat-harvest (keep the tx-history harvest);
   genuine incoming still comes from z_listreceivedbyaddress, and our sends are
   recorded by the local echo.

2. Own-identity ingest filter — a memo whose sender public key equals our own
   identity is by definition something we sent (only we hold our key); it must
   never be ingested as incoming. Skip those in ingest. This also collapses
   same-seed self-chat (running the SAME wallet in the full node and Lite makes
   them one chat identity, so sends land on an address we also own and loop back).

For a real two-party chat use two DIFFERENT wallets/seeds — same-seed wallets are
one identity and can't be distinct peers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-16 21:21:41 -05:00
parent 76093fe82d
commit 7351d8a06d
2 changed files with 14 additions and 16 deletions

View File

@@ -29,8 +29,16 @@ int ChatService::ingest(const std::vector<HushChatTransactionMetadata>& metadata
std::vector<std::string>* newIncomingCids) {
if (!has_identity_) return 0;
const std::string myPubKey = chatIdentityPublicKeyHex(identity_);
int added = 0;
for (const auto& meta : metadata) {
// A memo whose sender is our OWN identity is something we sent (only we hold our key). The local
// echo already records it as outgoing — ingesting it as incoming would duplicate it as a phantom
// "from peer" message. (This also collapses same-seed self-chat, where the "peer" wallet shares
// our identity, so every message would otherwise loop back.)
if (!myPubKey.empty() && meta.sender_public_key_hex == myPubKey) continue;
ChatMessage message;
message.direction = ChatDirection::Incoming;
message.txid = meta.txid;