// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract BurialChainReceipts { bytes32 public latestHash; uint256 public totalCount; uint256 public immutable BURIAL_DEPTH; event ReceiptAppended( uint256 indexed index, bytes32 indexed receiptHash, bytes32 previousHead, bytes32 newHead ); constructor(uint256 burialDepth) { require(burialDepth > 0, "depth > 0"); BURIAL_DEPTH = burialDepth; latestHash = bytes32(0); totalCount = 0; } function append(bytes32 receiptHash) external returns (uint256 index, bytes32 newHead) { bytes32 prevHead = latestHash; newHead = keccak256(abi.encodePacked(prevHead, receiptHash)); latestHash = newHead; index = totalCount; totalCount += 1; emit ReceiptAppended(index, receiptHash, prevHead, newHead); } function verify( bytes32 receiptHash, uint256 index, bytes32 prevHead, bytes32[] calldata subsequentReceiptHashes ) external view returns (bool) { require(index < totalCount, "index out of range"); uint256 remaining = totalCount - index - 1; require(subsequentReceiptHashes.length == remaining, "bad proof length"); require(remaining >= BURIAL_DEPTH, "not buried"); bytes32 current = keccak256(abi.encodePacked(prevHead, receiptHash)); uint256 len = subsequentReceiptHashes.length; for (uint256 i = 0; i < len; ++i) { current = keccak256(abi.encodePacked(current, subsequentReceiptHashes[i])); } return current == latestHash; } }