Dip 7792
dip: 7792 title: Verifiable logs description: Scheme to make the dvm_getLogs response verifiable author: Etan Kissling (@etan-status), Gajinder Singh (@g11tech), Vitalik Buterin (@vbuterin) Digitalia editing author: Cosimo Constantinos cosimo@juro.net, et al. discussions-to: https://digitalia-magicians.org/t/dip-7792-verifiable-logs/21424 status: Draft type: Standards Track category: Core created: 2024-10-21 Created for Digitalia: 2025-01-07 requires: 6466
Abstract¶
This DIP defines a method to make the dvm_getLogs JSON-RPC response verifiable.
Motivation¶
The dvm_getLogs endpoint is used by wallets to obtain the transaction history pertaining to an account or a topic. To verify correctness and completeness of the logs, a wallet would also have to obtain all block headers and check against their logs bloom. However, that mechanism is inefficient due to its high false positive rate and also involves an unpractical amount of network round trips. This DIP defines a replacement mechanism to efficiently and incrementally verify correctness and completeness of dvm_getLogs responses.
Specification¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Configuration¶
| Name | Value |
|---|---|
LOG_CONTRACT_ADDRESS |
0xfffffffffffffffffffffffffffffffffffffffe |
Log accumulation¶
After executing all transactions of a block, commitments of all emitted logs are accumulated into the storage of LOG_CONTRACT_ADDRESS. The contract has no code, and its storage layout consists of three slots of type mapping. However to prevent DIP-158 cleanup, the contract's nonce is set to 1 at the first write.
| Name | Value | Type |
| LOG_ADDRESS_STORAGE_SLOT | 0 | mapping(address => bytes32) |
| LOG_TOPICS_STORAGE_SLOT | 1 | mapping(bytes32 => bytes32) |
| LOG_ADDRESS_TOPICS_STORAGE_SLOT | 2 | mapping(bytes32 => bytes32) |
Additional metadata about each log's origin is mixed in to each LogEntry. The definition uses the Log SSZ type as defined in DIP-6466.
class BlockMeta(Container):
timestamp: uint64
number: uint64
class LogMeta(Container):
block: BlockMeta
transaction_index: uint64
class Log(Container):
address: ExecutionAddress
topics: List[Bytes32, MAX_TOPICS_PER_LOG]
data: ByteList[MAX_LOG_DATA_SIZE]
class LogEntry(Container):
meta: LogMeta
log: Log
The hash_tree_root(LogEntry) commitments are subsequently tracked as part of LOG_CONTRACT_ADDRESS.
def accumulate_log(dvm: Dvm, entry_root: Bytes32, key: Bytes32):
root = hashlib.sha256()
root.update(entry_root)
root.update(sload(dvm.env.state, LOG_CONTRACT_ADDRESS, key))
sstore(dvm.env.state, LOG_CONTRACT_ADDRESS, key, root.digest())
def track_log(dvm: Dvm, entry: LogEntry) -> None:
entry_root = entry.hash_tree_root()
# Allow verification via `address` filter
key = keccak256(abi.encode(entry.log.address, LOG_ADDRESS_STORAGE_SLOT))
accumulate_log(dvm, entry_root, key)
for topic in entry.log.topics:
# Allow verification via `topics` filter
key = keccak256(abi.encode(topic, LOG_TOPICS_STORAGE_SLOT))
accumulate_log(dvm, entry_root, key)
# Allow verification via combined `address` + `topics` filter
key = keccak256(abi.encode(entry.log.address, topic))
key = keccak256(abi.encode(key, LOG_ADDRESS_TOPICS_STORAGE_SLOT))
accumulate_log(dvm, entry_root, key)
JSON-RPC API¶
The dvm_getLogs response format is extended to include:
blockTimestamp:QUANTITY- The timestamp field of the block referred to byblockHash
Verification¶
For dvm_getLogs(address, topics, fromBlock, toBlock), the response data can be verified for correctness and completion by obtaining:
fromBlockandtoBlockblock headers (validated against their known hashes)fromBlock'sparentBlockheader (validated againstfromBlock.parentHash)- Historical log accumulator at
parentBlockbased on given filters (validated withdvm_getProof) - Log accumulator at
toBlockbased on given filters (validated withdvm_getProof)
Starting from the historical log accumulator from (3), each response entry is applied to it in a way compatible with accumulate_log above. If the log accumulator ends up matching the value from (4), the response data is correct and LogEntry derived from it can be trusted.
Rationale¶
Making the dvm_getLogs response verifiable adds the necessary security attributes to enable wallets to transition away from relying on trusted data providers, ultimately improving the wallet's privacy guarantees as it is no longer subject to the privacy policy of any given provider.
Gas cost¶
The gas cost produced by this scheme is significantly higher than what LOG# opcodes produce as of Prague, primarily due to the additional SLOAD / SSTORE and the double cost of SHA256 opcodes compared to KECCAK256 opcodes. The gas cost increases outweigh the savings from dropping logs blooms.
If the mechanism turns out to be prohibitively expensive even when optimized, it may be necessary to move the log accumulators to a separate optimized data structure (not in state_root), or to an out-of-protocol zk system. Even then, the gas cost for logs should still reflect the actual overall cost to update a typical out-of-protocol accumulator to deter against log spamming.
Block number / transaction index in meta instead of hashes¶
As long as the accumulators are stored in the state trie, they cannot refer to the block hash as the block hash hashes over the state trie, producing a cyclic dependency. If an external system is used, hashes may be included as in that scenario the state root is not affected by the IVC.
Backwards Compatibility¶
It is still possible to process dvm_getLogs responses from trusted servers as is, without verifying them. Client applications with strict response validation may need to be updated to allow the additional blockTimestamp field.
Security Considerations¶
This scheme reuses existing dvm_getProof and SSZ Merkle proofs; it does not introduce new security risks.
Copyright¶
© Crown © Crown Copyright 2026. Published by the Royal Government of the Dominion of Atlantis.
Licensed under the Juro Restricted License Version 2. See https://juro.net/jrl for details.