Portaldot Hacker House 2026· Track: Modular Cloud & Middleware
Rootmark

rootmark / console
chain 420420777 · evm + ink!
Every record leaves a mark.
The verifiable index for the Portaldot V3 chain. One query across EVM and ink! events, and every result carries a Merkle proof you check against an on-chain root.
26
records in one index
2
VMs, one record shape
32
bytes per anchored root
4
batches anchored on chain
01 — How it works
Both worlds,
no blind trust.
The indexer reads two runtimes as one ledger. One shape, one proof, no privileged view.
Indexing is clerical work. The machine reads both execution environments, writes every event into one ledger, and stamps each batch with a root nobody can rewrite.
First
Milliseconds
both VMs read at once
Then
One query
logs and events, one shape
Finally
Every batch
hashed, committed on chain
02 — Verification
The proof,
in one sentence.
Checked against the leaf, the siblings, the batch root, the anchor contract, your own browser.
A result is not a row the server vouches for. It is a leaf, a Merkle path, and a root your tab rebuilds itself, then compares with the root the anchor contract holds. If the index invented a record, the roots would not match.
Four hashes. When all four agree the panel says verified. When they do not, it says so plainly.
Open the verifier →- Root
- 0x3aa9be706278...38c0c7f21083
- Records
- 1
- Transaction
- 0x3f5a2af5c30d...d374475c35f7
03 — In figures
Small numbers,
each one checkable.
26
records in one index, both VMs
2
execution environments, one record shape
32
bytes per anchored root, the only thing to trust
4
batches anchored on chain
04 — Questions
Asked before
you ask.
Why do I need to verify an index at all?
Portaldot V3 runs two event models on one chain: Solidity logs on the EVM side, typed pallet events on the ink! side. Any app reading through an indexer has to believe what it is told. Rootmark reduces every batch to a Merkle root on chain, so a result carries its own check.
What exactly am I checking in the console?
Four hashes: the leaf of the record, the root your tab rebuilds from the leaf and its sibling path, the batch root, and the root read from the anchor contract. When all four agree, the panel says verified. When they do not, it says so plainly.
What if a batch is not anchored yet?
The panel says so: the proof is internally consistent, but there is no root on chain to check it against. Unsigned batches are the normal state on a quiet chain, not an error, and the page never implies proof it does not have.
How do two environments become one record?
The indexer tails eth_getBlockByNumber plus receipts on the EVM side and system.events on the Substrate side, then normalises both into one EventRecord: vm, chain, block, transaction, contract, event, arguments, leaf. Known contracts decode by ABI; unknown ones are kept by topic hash rather than dropped.
What is the anchor contract?
PortalAnchor.sol on the EVM side holds one 32 byte root per batch, plus the block range it covers. Anchoring is permissionless and a batch id can only be claimed once, so nobody can rewrite a root after it is committed. The ink! counterpart follows the same shape.
Is this live on the Portaldot testnet?
Yes. The indexer reads the live V3 testnet and PortalAnchor holds 4 real roots. Three Ping batches cover records in blocks 204669 to 204686 (anchor txs mined in 204686, 204709 and 204768) plus the tip root 0x3aa9be70 covering block 204924 (anchor tx mined in 204947). The 8 snapshot batches on this page are unsigned by design, and the rehearsal chain proves the full anchored path end to end.