Chat sends move 0 value, so the network fee is structurally load-bearing (it's the only thing that forces a real shielded input; 0-value + 0-fee builds a degenerate, unrelayable tx). Three gaps addressed: 1. Fee floor — broadcastChatMemos now uses max(getDefaultFee(), kChatMinFeeDrgx), so a 0 / too-low global default-fee setting can't silently break chat. 2. Real delivery status — the echo was marked Sent on SUBMIT regardless of the on-chain outcome (the z_sendmany callback was empty), so failures were invisible and the Retry affordance never fired for async failures. Add a third ChatDelivery::Sending state (appended so persisted 0=Sent stays valid); record the echo in-memory as Sending, and resolve it to Sent/Failed from the z_sendmany completion callback — persisting only the final status (so a restart never shows a stuck spinner; a stray persisted Sending loads as Sent). A subtle "sending…" label shows while in flight. 3. Pay-from-funded + pre-check — z_sendmany spends from one z-address, and the identity reply address may be unfunded while funds sit elsewhere. chatPayFromZaddr picks a spendable z-address that can cover the fee (preferring the identity address); the memo still advertises the identity address as reply-to, so paying from a different note is transport-transparent. If nothing can cover the fee, a clear "need a small shielded balance" toast replaces the cryptic failure. Full node only for the callback path; lite resolves optimistically on queue. 8-language strings + CJK subset (+1 glyph 賄). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
1.5 KiB
C++
43 lines
1.5 KiB
C++
#pragma once
|
|
|
|
// DragonX Wallet - HushChat in-memory message store: the fast read model / dedup view. Durable
|
|
// persistence lives in ChatDatabase; ChatService rehydrates this store from it on unlock.
|
|
|
|
#include "chat_message.h"
|
|
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
namespace dragonx::chat {
|
|
|
|
// Threads messages by conversation_id (cid) and deduplicates by (txid, payload_position) so
|
|
// re-scanning the chain never double-inserts. Not thread-safe — drive from the main thread.
|
|
class ChatStore {
|
|
public:
|
|
// Returns true if newly inserted, false if a duplicate was ignored.
|
|
bool append(const ChatMessage& message);
|
|
|
|
// Messages in a conversation, in insertion order.
|
|
std::vector<ChatMessage> conversation(const std::string& conversationId) const;
|
|
|
|
// Update an outgoing echo's delivery status by its local txid. Returns a pointer to the updated
|
|
// message (for the caller to persist), or nullptr if no message has that txid.
|
|
const ChatMessage* updateDelivery(const std::string& txid, ChatDelivery delivery);
|
|
|
|
// Distinct conversation ids, in first-seen order.
|
|
std::vector<std::string> conversationIds() const;
|
|
|
|
std::size_t size() const { return messages_.size(); }
|
|
bool empty() const { return messages_.empty(); }
|
|
void clear();
|
|
|
|
private:
|
|
static std::string dedupKey(const ChatMessage& message);
|
|
|
|
std::vector<ChatMessage> messages_;
|
|
std::unordered_set<std::string> seen_;
|
|
};
|
|
|
|
} // namespace dragonx::chat
|