From 743e7f8b6545482812e3c7ebab56b6cc1a972eb8 Mon Sep 17 00:00:00 2001 From: DanS Date: Sat, 24 Oct 2026 11:19:45 -0500 Subject: [PATCH] feat(chat): raise the composer cap to the tier-2 larger-message capacity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The composer byte cap was 236 (one memo). With larger-messages tier 2 a body can span up to 16 memo outputs in one tx, so kChatBodyMaxBytes rises to 4000 (a touch under the ~4063 protocol max so the composer never produces a body compose would reject). The compose buffer grows to match, guarded by a static_assert, and the emoji picker / byte gauge follow the single constant. sendChatMessage now shows a specific "message too long" toast on a TooLong compose instead of the generic compose-failed one (English string added; the 8 locales fall back until translated). Broadcast is unchanged — both chatSendOutputs call sites already iterate the N outputs. (Lite backend acceptance of >2 duplicate-address 0-value outputs is the one bit needing a live smoke test, like the other lite broadcast paths.) Larger-messages tiers 1-2 are now usable end to end on the full node. Co-Authored-By: Claude Opus 4.8 --- src/app_network.cpp | 8 +++++--- src/ui/windows/chat_tab.cpp | 11 +++++++---- src/util/i18n.cpp | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/app_network.cpp b/src/app_network.cpp index 1db3405..8fe4504 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -4660,9 +4660,11 @@ void App::sendChatMessage(const std::string& conversationId, const std::string& } chat::OutgoingChatMemos memos; - if (chat_service_.composeMessage(myReply, peerPubKey, peerZaddr, conversationId, text, memos) - != chat::ChatComposeStatus::Ok) { - ui::Notifications::instance().error(TR("chat_toast_compose_failed")); + const auto composeStatus = + chat_service_.composeMessage(myReply, peerPubKey, peerZaddr, conversationId, text, memos); + if (composeStatus != chat::ChatComposeStatus::Ok) { + ui::Notifications::instance().error(TR(composeStatus == chat::ChatComposeStatus::TooLong + ? "chat_toast_too_long" : "chat_toast_compose_failed")); return; } chat::ChatMessage echo; diff --git a/src/ui/windows/chat_tab.cpp b/src/ui/windows/chat_tab.cpp index 63eb13d..92d77af 100644 --- a/src/ui/windows/chat_tab.cpp +++ b/src/ui/windows/chat_tab.cpp @@ -63,15 +63,18 @@ int s_msgsel_head = 0; // drag-current byte offset bool s_msgsel_dragging = false; // Composer + new-conversation UI state. -char s_compose[512] = ""; +char s_compose[4100] = ""; // must be >= kChatBodyMaxBytes + 1 (static_assert'd below) std::string s_compose_cid; // the conversation s_compose is a draft for; draft is wiped when it changes // Live byte offset of the composer's text caret, kept in sync by composeInputCallback while the composer // is active (the callback only fires then). The emoji picker uses it to splice a glyph at the cursor // instead of always appending. -1 = unknown/never-focused => append at the end. int s_composeCursor = -1; -// On-chain chat body cap in bytes = (512 − len("utf8:"))/2 − secretstream ABYTES (see chat_outgoing.cpp). -// The composer hard-caps input to this; the emoji picker respects it too. -constexpr int kChatBodyMaxBytes = (512 - 5) / 2 - 17; // = 236 +// On-chain chat body cap in bytes. Larger-messages tier 2 splits the ciphertext across up to +// kHushChatMaxMessageParts (16) memo outputs in one tx, so the body can be a few KB (protocol max ~4063: +// 16 × 255 cipher bytes − 17 secretstream tag). Kept a touch under that so the composer never produces a +// body that compose would reject as TooLong. The composer hard-caps input here; the emoji picker too. +constexpr int kChatBodyMaxBytes = 4000; +static_assert(sizeof(s_compose) >= kChatBodyMaxBytes + 1, "compose buffer too small for the body cap"); float s_composerAnimH = 0.0f; // animated composer-box height — grows with newlines, pushing the thread up float s_composerTargetH = 0.0f; // target height measured in the composer block (wrapped content), consumed next frame diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index d5fef45..12dee80 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -265,6 +265,7 @@ void I18n::loadBuiltinEnglish() strings_["chat_toast_lite_busy"] = "A send is already in progress, or no wallet is open."; strings_["chat_toast_waiting_reply"] = "Waiting for the contact to reply before you can message them."; strings_["chat_toast_compose_failed"] = "Could not compose the message (too long?)."; + strings_["chat_toast_too_long"] = "Message too long — shorten it and send again."; strings_["chat_toast_request_compose_failed"] = "Could not compose the contact request (invalid address / text?)."; strings_["chat_toast_request_queued"] = "Contact request queued."; strings_["chat_toast_need_funds"] = "Need a small shielded balance to send chat (to cover the fee).";