packages/contracts-core/test/utils/proof/AttestationProofGenerator.t.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {SNAPSHOT_TREE_HEIGHT} from "../../../contracts/libs/Constants.sol";
import {MerkleMath} from "../../../contracts/libs/merkle/MerkleMath.sol";
import {StateLib} from "../../../contracts/libs/memory/State.sol";
import {ProofCutter} from "./ProofCutter.t.sol";
// TODO: move from test directory
contract AttestationProofGenerator is ProofCutter {
using StateLib for bytes;
bytes32 public root;
// (height => (index => node))
mapping(uint256 => mapping(uint256 => bytes32)) internal nodes;
function acceptSnapshot(bytes[] memory snapshotStates) external {
uint256 amount = 1 << SNAPSHOT_TREE_HEIGHT;
uint256 h = 0;
// Copy leafs
for (uint256 i = 0; i < snapshotStates.length; ++i) {
(nodes[h][2 * i], nodes[h][2 * i + 1]) = snapshotStates[i].castToState().subLeafs();
}
// Remaining leafs are ZERO
for (uint256 i = 2 * snapshotStates.length; i < amount; ++i) {
nodes[h][i] = bytes32(0);
}
// Save all parents all the way to the root
while (amount > 1) {
++h;
amount >>= 1;
for (uint256 i = 0; i < amount; ++i) {
nodes[h][i] = MerkleMath.getParent(nodes[h - 1][2 * i], nodes[h - 1][2 * i + 1]);
}
}
root = nodes[h][0];
}
function generateProof(uint256 stateIndex) external view returns (bytes32[] memory) {
// Index of State's left leaf
uint256 index = stateIndex * 2;
require(index < (1 << SNAPSHOT_TREE_HEIGHT), "Out of range");
bytes32[] memory proof = new bytes32[](SNAPSHOT_TREE_HEIGHT);
for (uint256 h = 0; h < SNAPSHOT_TREE_HEIGHT; ++h) {
// Get sibling on the current level
proof[h] = nodes[h][index ^ 1];
// Traverse to parent
index >>= 1;
}
return cutProof(proof);
}
}