Part of #3803. Draft PR: #3833.
A log contains the account that emitted it, a topic, and a payload.
For transactions on public accounts, ProvenTransaction contains the full logs. For transactions on private accounts, it contains only a salted hash of the logs. The full private logs remain available in local execution data. This also applies to logs emitted through FPI: visibility is determined by the account the transaction runs against.
Add four Rust types in miden_protocol::transaction:
LogTopic: the first two felts of MASM word(name), with the same derivation in Rust.
TransactionLog: the emitting account, topic, and payload words.
TransactionLogs: the logs in emission order, with cached hashes.
TransactionLogData: either public log contents or a private hash.
Follow Bobbin's two step approach: hash each log, then hash the list of log hashes in emission order. With Poseidon2:
P_i = hash_elements(flatten(payload_i))
M_i = [emitter_suffix, emitter_prefix, topic_0, topic_1]
L_i = merge_in_domain([M_i, P_i], 0x02_0002)
logs_commitment = hash_elements_in_domain(L_1 || ... || L_n, 0x02_0003)
Empty payloads and collections hash to zero. Cache the collection hash until another log is appended. Duplicate logs are allowed and distinguished by their position, without adding a counter to each log's hash.
Allow 64 logs per transaction, 256 payload words (8 KiB) per log, and 512 payload words (16 KiB) in total. Metadata is excluded from the payload budget.
Use existing primitive encodings, little endian u16 lengths, and submission tags 0 for public and 1 for private. Serialize TransactionLogs as records without the cached hashes. Keep fields private, validate constructors and appends, and reject excessive lengths before payload allocation or reads. Failed appends must leave the logs unchanged.
Test serialization, matching Rust/MASM hashes, ordering, empty and duplicate logs, limits, and cache invalidation.
This issue covers Rust types and serialization. #3831 covers log emission, the private salted hash, and transaction proof integration. BLAKE3 migration is separate work.
Part of #3803. Draft PR: #3833.
A log contains the account that emitted it, a topic, and a payload.
For transactions on public accounts,
ProvenTransactioncontains the full logs. For transactions on private accounts, it contains only a salted hash of the logs. The full private logs remain available in local execution data. This also applies to logs emitted through FPI: visibility is determined by the account the transaction runs against.Add four Rust types in
miden_protocol::transaction:LogTopic: the first two felts of MASMword(name), with the same derivation in Rust.TransactionLog: the emitting account, topic, and payload words.TransactionLogs: the logs in emission order, with cached hashes.TransactionLogData: either public log contents or a private hash.Follow Bobbin's two step approach: hash each log, then hash the list of log hashes in emission order. With Poseidon2:
Empty payloads and collections hash to zero. Cache the collection hash until another log is appended. Duplicate logs are allowed and distinguished by their position, without adding a counter to each log's hash.
Allow 64 logs per transaction, 256 payload words (8 KiB) per log, and 512 payload words (16 KiB) in total. Metadata is excluded from the payload budget.
Use existing primitive encodings, little endian
u16lengths, and submission tags0for public and1for private. SerializeTransactionLogsas records without the cached hashes. Keep fields private, validate constructors and appends, and reject excessive lengths before payload allocation or reads. Failed appends must leave the logs unchanged.Test serialization, matching Rust/MASM hashes, ordering, empty and duplicate logs, limits, and cache invalidation.
This issue covers Rust types and serialization. #3831 covers log emission, the private salted hash, and transaction proof integration. BLAKE3 migration is separate work.