mirror of
https://github.com/logos-co/logos-cpp-sdk.git
synced 2026-08-31 09:41:06 +00:00
A universal module could take or return a single blob (`bstr`) but not a list
of them: `std::vector<std::vector<uint8_t>>` parsed to `[bstr]`, which the
cdylib gate rejected by name. Authors had to flatten to hex or base64 strings
by hand. logos-execution-zone-module hit this on
send_generic_private_transaction(..., program_dependencies), whose dependency
ELFs are exactly a list of blobs.
The gate excluded `[bstr]` because the array path decodes with a blanket
`expr.get<inner>()`, and `[bstr]` elements arrive as the canonical tagged
{"_bytes": base64url} OBJECT — nlohmann refuses that, and a number-array
element would silently bypass the base64 decode. So admitting the type needed
a per-element codec, not just a whitelist entry.
Adds one, on top of the scalar codecs already emitted:
- lidlBytesListFromJson: element-wise lidlBytesFromJson, so each element may
independently be tagged, a plain string or a number array; a non-array arg
yields an empty list instead of throwing, matching the scalar decoder.
- lidlBytesListToJson: element-wise lidlBytesToJson, so a returned or emitted
list carries the tagged form per element instead of nested number arrays
that no consumer decodes as bytes.
Wired into all three places the type can appear — method params, method
returns, event payloads — and both helpers are gated (usesBytesArray /
hasBytesArrayEventParam) so a module that never carries a byte-string array
gains no unused static function, matching how the scalar encoder is gated.
Nothing outside this generator needed changing: lidlTypeToStd already spelled
`[bstr]` as std::vector<std::vector<uint8_t>>, the wire form is protocol's
existing tagged-bytes encoding, and consumers see `[bstr]` as QVariantList
exactly like `[int]` — with nested QByteArray preserved through
qvariantToNlohmann since logos-protocol#23.
Tests: 171/171. New coverage for the param decode, the return encode, the event
encode, and the unused-helper gating; the test that enshrined the rejection is
now an eligibility + tagging assertion.
Verified end to end, not just as generated text — a module with `[bstr]` as
param, return and event payload, driven through logoscore over the real
transport:
param : json:[{"_bytes":"AH-A_w"},{"_bytes":""},{"_bytes":"3q2-7w"}]
-> "3|4:0:255:510|0👎-1:0|4:222:239:824" (byte-exact; the 0x80
and 0xff bytes survive, and the empty element stays an element)
return : [{"_bytes":"AH-A_w"},{"_bytes":""},{"_bytes":"3q2-7w"}]
event : {"arg0":[{"_bytes":"AH-A_w"},{"_bytes":""},{"_bytes":"3q2-7w"}]}
And lez_core's real header now generates, decoding program_elf with the scalar
codec and program_dependencies with the list one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>