synapsecns/sanguine

View on GitHub
packages/contracts-core/test/suite/libs/merkle/MerkleTree.t.sol

Summary

Maintainability
Test Coverage
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {AGENT_TREE_HEIGHT, ORIGIN_TREE_HEIGHT} from "../../../../contracts/libs/merkle/MerkleTree.sol";

import {MerkleMathHarness} from "../../../harnesses/libs/merkle/MerkleMathHarness.t.sol";
import {MerkleTreeHarness} from "../../../harnesses/libs/merkle/MerkleTreeHarness.t.sol";

import {Random} from "../../../utils/libs/Random.t.sol";
import {SynapseLibraryTest} from "../../../utils/SynapseLibraryTest.t.sol";

// solhint-disable func-name-mixedcase
contract MerkleTreeTest is SynapseLibraryTest {
    uint256 public constant RUNS = 1000;
    uint256 public constant DYNAMIC_AMOUNT = 200;

    MerkleTreeHarness public libHarness;
    MerkleMathHarness public mathHarness;
    bytes32[] public leafs;

    function setUp() public {
        libHarness = new MerkleTreeHarness();
        mathHarness = new MerkleMathHarness();
    }

    function test_baseTree() public {
        assertEq(libHarness.rootBase(0), 0);
        for (uint256 i = 0; i < RUNS; ++i) {
            bytes32 leaf = getLeaf(i);
            leafs.push(leaf);
            libHarness.insertBase(i + 1, leaf);
            assertEq(libHarness.rootBase(i + 1), mathHarness.calculateRoot(leafs, ORIGIN_TREE_HEIGHT));
        }
    }

    function test_historicalTree() public {
        bytes32[] memory roots = new bytes32[](RUNS + 1);
        roots[0] = 0;
        libHarness.initializeRoots();
        for (uint256 i = 0; i < RUNS; ++i) {
            bytes32 leaf = getLeaf(i);
            leafs.push(leaf);
            libHarness.insert(leaf);
            roots[i + 1] = mathHarness.calculateRoot(leafs, ORIGIN_TREE_HEIGHT);
        }
        for (uint256 i = 0; i <= RUNS; ++i) {
            assertEq(libHarness.root(i), roots[i]);
        }
    }

    function test_historicalTree_revert_initializeTwice() public {
        libHarness.initializeRoots();
        vm.expectRevert();
        libHarness.initializeRoots();
    }

    function test_dynamicTree() public {
        for (uint256 i = 0; i < DYNAMIC_AMOUNT; ++i) {
            leafs.push(0);
        }
        Random memory random = Random("very random seed");
        for (uint256 i = 0; i < RUNS; ++i) {
            uint256 index = random.nextUint256() % DYNAMIC_AMOUNT;
            bytes32 oldValue = leafs[index];
            bytes32 newValue = random.next();
            bytes32[] memory proof = mathHarness.calculateProof(leafs, index);
            bytes32 newRoot = libHarness.update(index, oldValue, proof, newValue);
            leafs[index] = newValue;
            assertEq(newRoot, mathHarness.calculateRoot(leafs, AGENT_TREE_HEIGHT));
        }
    }

    function getLeaf(uint256 index) public pure returns (bytes32) {
        return keccak256(abi.encode("Leaf", index));
    }
}