tests for the weaver logic
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
f4801edf73
commit
cb7c52f655
@ -2,6 +2,7 @@
|
||||
src = "src"
|
||||
out = "out"
|
||||
libs = ["lib", "dependencies"]
|
||||
gas_limit = "18446744073709551615"
|
||||
|
||||
optimizer = true
|
||||
optimizer_runs = 10000
|
||||
@ -18,6 +19,7 @@ gas_reports = [
|
||||
"GhostBondingCalculator",
|
||||
"GhostTreasury",
|
||||
"GhostGovernorExposed",
|
||||
"GatekeeperVerification",
|
||||
]
|
||||
remappings = [
|
||||
"@openzeppelin-contracts/=dependencies/@openzeppelin-contracts-5.0.2/",
|
||||
|
||||
212
test/gatekeeper/GatekeeperWeaver.t.sol
Normal file
212
test/gatekeeper/GatekeeperWeaver.t.sol
Normal file
@ -0,0 +1,212 @@
|
||||
pragma solidity 0.8.20;
|
||||
|
||||
import {Test} from "forge-std/Test.sol";
|
||||
|
||||
import {Gatekeeper} from "../../src/Gatekeeper.sol";
|
||||
import {Hashes} from "../../src/libraries/Hashes.sol";
|
||||
import {Checkpoints} from "../../src/libraries/Checkpoints.sol";
|
||||
|
||||
contract GatekeeperVerification is Gatekeeper {
|
||||
using Checkpoints for Checkpoints.Trace256;
|
||||
using Checkpoints for Checkpoints.Trace160;
|
||||
|
||||
constructor(
|
||||
address staking,
|
||||
uint256 ghostedSupply,
|
||||
uint256 existential,
|
||||
uint48 deployedAt,
|
||||
uint104 amountIn,
|
||||
uint104 amountOut
|
||||
) Gatekeeper(
|
||||
staking,
|
||||
ghostedSupply,
|
||||
existential,
|
||||
deployedAt,
|
||||
amountIn,
|
||||
amountOut
|
||||
) {}
|
||||
|
||||
function filledEntries(uint256 session) public view returns (uint256) {
|
||||
return _filledEntries[session];
|
||||
}
|
||||
|
||||
function slotLengths(uint256 session, uint256 globalIndex) public view returns (uint160) {
|
||||
uint256 slotIndex = globalIndex % SLOTS;
|
||||
return _slotLenghts[session][slotIndex].latest();
|
||||
}
|
||||
|
||||
function slotValues(uint256 session, uint256 globalIndex) public view returns (bytes32) {
|
||||
uint256 slotIndex = globalIndex % SLOTS;
|
||||
uint256 valueIndex = globalIndex / SLOTS;
|
||||
return _slotValues[session][slotIndex][valueIndex];
|
||||
}
|
||||
|
||||
function treeNodesLatest(uint256 session, uint256 globalIndex) public view returns (bytes32) {
|
||||
uint256 slotIndex = globalIndex % SLOTS;
|
||||
return bytes32(_treeNodes[session][slotIndex].latest());
|
||||
}
|
||||
|
||||
function computePreimage(uint256 globalIndex, uint256 a, bytes32 r) public pure returns (bytes32) {
|
||||
uint256 valueIndex = globalIndex / SLOTS;
|
||||
return _computeArgumentsHash(valueIndex, a, r);
|
||||
}
|
||||
|
||||
function testVerify(
|
||||
bytes32[] calldata proof,
|
||||
bytes32[] calldata values,
|
||||
uint256 globalIndex,
|
||||
uint256 amount,
|
||||
bytes32 who
|
||||
) public pure returns (bytes32) {
|
||||
if (proof.length != DEPTH) { return bytes32(0); }
|
||||
if (values.length == 0) { return bytes32(0); }
|
||||
|
||||
uint256 slotIndex = globalIndex % SLOTS;
|
||||
uint256 valueIndex = globalIndex / SLOTS;
|
||||
if (valueIndex >= values.length) { return bytes32(0); }
|
||||
|
||||
bytes32 computedHash = _computeArgumentsHash(valueIndex, amount, who);
|
||||
if (computedHash != values[valueIndex]) { return bytes32(0); }
|
||||
computedHash = bytes32(0);
|
||||
|
||||
uint256 i;
|
||||
for (; i < values.length;) {
|
||||
bytes32 currHash = Hashes.efficientKeccak256(values[i]);
|
||||
computedHash = Hashes.efficientKeccak256(computedHash, currHash);
|
||||
unchecked { ++i; }
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (; i < proof.length; ) {
|
||||
if (slotIndex % 2 == 0) {
|
||||
computedHash = Hashes.efficientKeccak256(computedHash, proof[i]);
|
||||
} else {
|
||||
computedHash = Hashes.efficientKeccak256(proof[i], computedHash);
|
||||
}
|
||||
slotIndex >>= 1;
|
||||
unchecked { ++i; }
|
||||
}
|
||||
|
||||
return computedHash;
|
||||
}
|
||||
}
|
||||
|
||||
contract GatekeeperWeaverTest is Test {
|
||||
address constant ALICE = 0x0000000000000000000000000000000000000001;
|
||||
address constant BOB = 0x0000000000000000000000000000000000000002;
|
||||
uint256 constant EXISTENTIAL = 1337;
|
||||
uint256 constant AMOUNT = 1 * 1e7;
|
||||
|
||||
GatekeeperVerification gatekeeper;
|
||||
|
||||
function setUp() public {
|
||||
gatekeeper = new GatekeeperVerification(ALICE, 0, EXISTENTIAL, 0, 0, 0);
|
||||
}
|
||||
|
||||
function test_insertationWorksAsExpected() public {
|
||||
uint256 currentSession = gatekeeper.currentSession();
|
||||
uint256 maxCount = gatekeeper.ENTRIES();
|
||||
uint256 globalIndex;
|
||||
|
||||
(bytes32[] memory whos, uint256[] memory amounts) = _prepareArrays(maxCount);
|
||||
|
||||
for (uint256 i = 0; i < maxCount; i++) {
|
||||
if (i % 5 == 0) { vm.roll(block.number + 1); }
|
||||
globalIndex = _insertWithAssert(currentSession, amounts[i], whos[i]);
|
||||
assertTrue(_verifyProof(globalIndex, currentSession, block.number, amounts[i], whos[i]));
|
||||
}
|
||||
|
||||
globalIndex = _insertWithAssert(currentSession, amounts[69], whos[69]);
|
||||
uint256 newSession = gatekeeper.currentSession();
|
||||
|
||||
assertEq(currentSession + 1, newSession);
|
||||
vm.roll(block.number + 1337);
|
||||
|
||||
assertTrue(_verifyProof(globalIndex, newSession, block.number, amounts[69], whos[69]));
|
||||
assertTrue(_verifyProof(0, currentSession, block.number, amounts[0], whos[0]));
|
||||
assertTrue(_verifyProof(69, currentSession, block.number, amounts[69], whos[69]));
|
||||
assertTrue(_verifyProof(420, currentSession, block.number, amounts[420], whos[420]));
|
||||
assertTrue(_verifyProof(1337, currentSession, block.number, amounts[1337], whos[1337]));
|
||||
assertTrue(_verifyProof(2047, currentSession, block.number, amounts[2047], whos[2047]));
|
||||
|
||||
assertTrue(_verifyProof(0, currentSession, 100, amounts[0], whos[0]));
|
||||
assertTrue(_verifyProof(69, currentSession, 100, amounts[69], whos[69]));
|
||||
assertTrue(_verifyProof(420, currentSession, 100, amounts[420], whos[420]));
|
||||
|
||||
assertFalse(_verifyProof(globalIndex, newSession, 100, amounts[69], whos[69]));
|
||||
assertFalse(_verifyProof(1337, currentSession, 100, amounts[1337], whos[1337]));
|
||||
assertFalse(_verifyProof(2047, currentSession, 100, amounts[2047], whos[2047]));
|
||||
}
|
||||
|
||||
function _verifyProof(
|
||||
uint256 globalIndex,
|
||||
uint256 session,
|
||||
uint256 atBlock,
|
||||
uint256 amount,
|
||||
bytes32 who
|
||||
) private view returns (bool) {
|
||||
bytes32[] memory proof = gatekeeper.getProof(globalIndex, session, atBlock);
|
||||
bytes32[] memory values = gatekeeper.getSlotValues(globalIndex, session, atBlock);
|
||||
|
||||
bytes32 root1 = gatekeeper.testVerify(proof, values, globalIndex, amount, who);
|
||||
(bytes32 root2, uint256 entries) = gatekeeper.getRoot(session, atBlock);
|
||||
assertTrue(entries <= gatekeeper.ENTRIES());
|
||||
|
||||
return root1 == root2;
|
||||
}
|
||||
|
||||
function _insertWithAssert(
|
||||
uint256 session,
|
||||
uint256 amount,
|
||||
bytes32 who
|
||||
) private returns (uint256 globalIndex) {
|
||||
uint256 targetSlot = gatekeeper.filledEntries(session);
|
||||
bytes32 previousHash = gatekeeper.treeNodesLatest(session, targetSlot);
|
||||
uint256 prevEntries = gatekeeper.filledEntries(session);
|
||||
uint160 prevLength = gatekeeper.slotLengths(session, targetSlot);
|
||||
|
||||
vm.prank(ALICE);
|
||||
globalIndex = gatekeeper.ghost(who, amount);
|
||||
|
||||
if (session + 1 == gatekeeper.currentSession()) {
|
||||
assertEq(prevLength, gatekeeper.DEPTH());
|
||||
assertEq(gatekeeper.slotLengths(session + 1, 0), 1);
|
||||
assertEq(prevEntries, gatekeeper.ENTRIES());
|
||||
assertEq(gatekeeper.filledEntries(session + 1), 1);
|
||||
|
||||
session += 1;
|
||||
previousHash = bytes32(0);
|
||||
prevLength = gatekeeper.slotLengths(session, 0);
|
||||
} else {
|
||||
assertEq(prevLength + 1, gatekeeper.slotLengths(session, targetSlot));
|
||||
assertEq(prevEntries + 1, gatekeeper.filledEntries(session));
|
||||
}
|
||||
|
||||
{
|
||||
bytes32 preimage1 = gatekeeper.slotValues(session, globalIndex);
|
||||
bytes32 preimage2 = gatekeeper.computePreimage(globalIndex, amount, who);
|
||||
assertEq(preimage1, preimage2);
|
||||
}
|
||||
|
||||
{
|
||||
bytes32 nodeHash1 = gatekeeper.treeNodesLatest(session, globalIndex);
|
||||
bytes32 preimageHash = Hashes.efficientKeccak256(
|
||||
gatekeeper.computePreimage(globalIndex, amount, who)
|
||||
);
|
||||
bytes32 nodeHash2 = Hashes.efficientKeccak256(previousHash, preimageHash);
|
||||
assertEq(nodeHash1, nodeHash2);
|
||||
}
|
||||
}
|
||||
|
||||
function _prepareArrays(uint256 count) private pure returns (bytes32[] memory, uint256[] memory) {
|
||||
bytes32[] memory whos = new bytes32[](count);
|
||||
uint256[] memory amounts = new uint256[](count);
|
||||
|
||||
for (uint256 i = 0; i < count; i++) {
|
||||
whos[i] = keccak256(abi.encodePacked("user", i));
|
||||
amounts[i] = EXISTENTIAL + 1 + i;
|
||||
}
|
||||
|
||||
return (whos, amounts);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user