synapsecns/sanguine

View on GitHub
packages/contracts-core/test/utils/proof/AttestationProofGenerator.t.sol

Summary

Maintainability
Test Coverage
// 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);
    }
}