Skip to content

fix!: make verify_hash_tree check the entire hash tree - #410

Closed
diegonehab wants to merge 1 commit into
mainfrom
feature/verify-merkle-tree
Closed

diegonehab wants to merge 1 commit into
mainfrom
feature/verify-merkle-tree

Conversation

@diegonehab

@diegonehab diegonehab commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Summary

verify_hash_tree compared each page hash with memory and nothing else. A machine could pass it with a corrupted dense inner node, sparse node, padding page, dirty page tree, or page hash-tree cache entry, and get_root_hash would then return a wrong hash. Loading a stored machine from damaged .dht, .dpt, hash_tree.sht, or hash_tree.phtc files is one way to get there.

verify_hash_tree now updates the hash tree and then checks all of it against memory. If it passes, every hash the machine reports matches the machine state.

  • Dense trees. Every page node matches memory, padding pages are pristine, and every inner node matches its children.
  • Dirty page trees. No dirty node has a clean parent. Otherwise, later writes would stop marking at that node and never reach the root.
  • Sparse tree. Every address-range node matches the root of its dense tree, and every inner node matches its children.
  • Page hash-tree cache. Every entry is returned, is indexed by its page address, holds the page as it is in memory, and has a page hash tree that matches that page.

On the first mismatch, it raises an error naming the node, for example dense hash tree node at address 0x80002000 with log2_size 13 (in RAM) does not match its children. On success, it returns the root hash, just like get_root_hash.

The error messages use a new to_hex_string helper in algorithm.hpp.

Breaking changes

  • cm_verify_hash_tree(cm_machine *m, cm_hash *hash) returns the root hash instead of a bool, and fails instead of reporting false
  • machine:verify_hash_tree() in Lua and machine.verify_hash_tree in JSON-RPC return the root hash and raise an error on mismatch

Tests

spec-hash-tree.lua stores a machine, corrupts one structure on disk in a copy, loads the copy, and checks the error message. The cases cover the dense root, a dense inner node, a dense page node, a padding page node, a dirty node under a clean parent, the sparse root, and the page data, root hash, word hash, and borrowed flag of a cache entry. Two more cases check that an uncorrupted copy returns the stored root hash, and that a corrupted sparse leaf is repaired from its dense root. Existing callers in the Lua and C API tests now compare the returned hash with get_root_hash.

@diegonehab diegonehab added this to the v0.23.0 milestone Oct 16, 2026
@diegonehab diegonehab self-assigned this Oct 16, 2026
@diegonehab diegonehab added the enhancement New feature or request label Oct 16, 2026
@diegonehab diegonehab added the bug Something isn't working label Oct 16, 2026
@diegonehab diegonehab changed the title fix: make verify_hash_tree check the entire hash tree fix!: make verify_hash_tree check the entire hash tree Oct 16, 2026
@diegonehab
diegonehab requested a review from edubart October 16, 2026 12:50
verify_hash_tree only compared page hashes with memory, so corrupted
inner nodes, sparse nodes, padding pages, dirty page trees, or page
hash-tree cache entries went undetected while the root hash was wrong.

It now updates the hash tree, checks every dense, sparse, and cached
node against memory, checks that dirty nodes have dirty parents,
raises an error naming the first inconsistent node, and returns the
root hash. The C API now takes a cm_hash output instead of a bool.
@diegonehab
diegonehab force-pushed the feature/verify-merkle-tree branch from aa359c6 to 5d07821 Compare October 16, 2026 13:07
Comment thread src/cm.h
CM_API cm_error cm_verify_hash_tree(cm_machine *m, bool *result);
/// \details Fails if any node in the sparse tree, the dense trees, or the page hash-tree cache does not match the
/// machine state, or if any dirty page tree has a dirty node with a clean parent.
/// On success, every hash the machine reports matches the machine state.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a comment mentioning this operation should be used sporadically because unlikely other hash tree operations it is does not have multi-threaded acceleration.

@diegonehab

Copy link
Copy Markdown
Member Author

I'm starting to think that, if you don't trust the machine, you should just clear the hash-tree. What do you think, Eduardo? Then we can leave this "verify" function to do what it was meant to do. Which is to see if we screwed up ourselves, not if somebody else screwed with us.

@diegonehab

Copy link
Copy Markdown
Member Author

I think this is not worth it. It's best to clear and start from scratch.

@diegonehab diegonehab closed this Oct 16, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in Machine Unit Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants