build(agent): jabba#56a767 iteration

This commit is contained in:
agent-56a7678c6cd71659 2026-04-30 08:43:31 +02:00
parent 77f5b06711
commit 45bc190445
2 changed files with 42 additions and 10 deletions

View File

@ -98,17 +98,34 @@ def verify_inclusion(chain_head_hash: str, proof_hashes: List[str], chain_map: O
if chain_map is None:
# best-effort: we have only hashes; accept if tip matches
return True
# verify backward links using chain_map
# verify forward links using chain_map
# proof_hashes = [h_target, h_next, ..., h_head]
# For each adjacent pair, the later entry's prev_hash must equal the
# earlier entry's hash. We consult chain_map which maps hash->entry.
for i in range(len(proof_hashes) - 1):
h = proof_hashes[i]
next_h = proof_hashes[i + 1]
entry = chain_map.get(h)
if entry is None:
h_curr = proof_hashes[i]
h_next = proof_hashes[i + 1]
# ensure the provided map contains the entry and that the entry's
# recorded hash matches the canonical hash of its payload. This
# prevents silent tampering where prev_hash is changed but hash left
# un-updated.
next_entry = chain_map.get(h_next)
if next_entry is None:
return False
# recompute the entry hash and ensure it matches the expected key
try:
# debug: show object id
# print(f"verify_inclusion: next_entry id={id(next_entry)}")
recomputed = _entry_hash(next_entry)
except Exception:
print(f"verify_inclusion: failed to recompute hash for {h_next}")
return False
if recomputed != h_next:
return False
# next_entry.prev_hash should point to current hash
prev = next_entry.get("prev_hash", "")
# debug print
# print(f"verify link: next={h_next} prev={prev} expected={h_curr}")
if prev != h_curr:
return False
if entry.get("prev_hash", "") != (chain_map.get(next_h, {}).get("prev_hash", entry.get("prev_hash", "")) and None):
# We cannot reliably reconstruct prev pointers from hashes alone
# so this strict check is left as a placeholder. For now we require
# that next hash exists in the map (sanity) and tip matches.
pass
return True

View File

@ -23,3 +23,18 @@ def test_inclusion_proof_and_head():
assert proof[-1] == head
# verify inclusion using head-only verification (best-effort)
assert verify_inclusion(head, proof)
def test_verify_inclusion_with_chain_map():
ops = [("opA", "X"), ("opB", "Y"), ("opC", "Z")]
chain = build_chain(ops)
head = head_hash(chain)
target = chain[0]
proof = inclusion_proof(chain, target_entry_id=target["entry_id"])
# build chain_map: hash -> entry
chain_map = {e["hash"]: e for e in chain}
# verification should succeed when supplying chain_map
assert verify_inclusion(head, proof, chain_map=chain_map)
# build a clean chain_map and verify inclusion with the map provided
chain_map = {e["hash"]: e for e in chain}
assert verify_inclusion(head, proof, chain_map=chain_map)