emit event during the weaver insertion

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2026-09-14 10:46:40 +03:00
parent 635853f170
commit b1e9be968e
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
8 changed files with 59 additions and 63 deletions

View File

@ -109,14 +109,12 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
return (publicKey, state.parity, state.session);
}
function ghost(bytes32 receiver, uint256 amount) external override returns (uint256) {
function ghost(bytes32 receiver, uint256 amount) external override {
if (msg.sender != staking) revert NotStaking();
if (amount < EXISTENTIAL_DEPOSIT) revert NonExistentAmount();
IStorageHistory(storageHistory).increaseBridgeIn(amount);
emit Ghosted(receiver, amount);
return _insertTreeNode(receiver, amount);
_insertTreeNode(receiver, amount);
}
function verify(

View File

@ -14,7 +14,6 @@ interface IGatekeeper {
error InsufficientValue();
error ExecutionReverted();
event Ghosted(bytes32 indexed receiver, uint256 indexed amount);
event Recalled(address indexed receiver, uint256 indexed amount);
event Rotated(bytes32 indexed aggregatedPublicKey, uint8 indexed parity);
event VoluntaryVerification(address indexed sender, uint256 indexed gasSpent);
@ -29,6 +28,6 @@ interface IGatekeeper {
function govern(uint256 session, uint256 payload, bytes calldata call) external returns (bytes calldata);
function recall(uint256 session, uint256 amount, uint256 payload) external;
function rotate(uint256 session, bytes32 publicKey, uint8 parity) external;
function ghost(bytes32 receiver, uint256 amount) external returns (uint256);
function ghost(bytes32 receiver, uint256 amount) external;
function initialize(address previousAddress) external;
}

View File

@ -2,6 +2,8 @@
pragma solidity ^0.8.20;
interface IWeaver {
event ThreadInserted(uint256 index, uint256 session);
function currentWeavingSession() external view returns (uint256);
function startWeavingSession() external view returns (uint256);
function getSlotValues(uint256 globalIndex, uint256 session, uint256 atBlock) external view returns (bytes32[] memory);

View File

@ -14,8 +14,8 @@ contract WeaverMock is Weaver {
return _previousAddress;
}
function insertTreeNode(bytes32 receiver, uint256 amount) external returns (uint256) {
return _insertTreeNode(receiver, amount);
function insertTreeNode(bytes32 receiver, uint256 amount) external {
_insertTreeNode(receiver, amount);
}
function computeArgumentsHash(

View File

@ -134,9 +134,10 @@ abstract contract Weaver is IWeaver {
return proof;
}
function _insertTreeNode(bytes32 who, uint256 amount) internal returns (uint256 globalIndex) {
function _insertTreeNode(bytes32 who, uint256 amount) internal {
uint256 session = currentWeavingSession;
globalIndex = _filledEntries[session];
uint256 globalIndex = _filledEntries[session];
if (globalIndex >= ENTRIES) {
unchecked { ++session; }
currentWeavingSession = session;
@ -158,6 +159,8 @@ abstract contract Weaver is IWeaver {
_slotValues[session][slotIndex].push(preimage);
unchecked { ++_filledEntries[session]; }
emit ThreadInserted(globalIndex, session);
}
function _computeArgumentsHash(uint256 i, uint256 a, bytes32 r) internal pure returns (bytes32) {

View File

@ -203,7 +203,7 @@ contract GatekeeperTest is Test {
Gatekeeper gatekeeper;
MockStaking staking;
event Ghosted(bytes32 indexed receiver, uint256 indexed amount);
event ThreadInserted(uint256 index, uint256 session);
function setUp() public {
vm.prank(ALICE, ALICE);
@ -247,7 +247,7 @@ contract GatekeeperTest is Test {
bytes32 receiver = bytes32(abi.encodePacked(ALICE));
vm.expectEmit(true, true, true, false, address(gatekeeper));
emit Ghosted(receiver, ghostAmount);
emit ThreadInserted(0, 0);
vm.prank(ALICE);
staking.runGhost(receiver, ghostAmount);
}

View File

@ -1,6 +1,6 @@
pragma solidity 0.8.20;
import {Test} from "forge-std/Test.sol";
import {Test, Vm} from "forge-std/Test.sol";
import {Gatekeeper} from "../../src/Gatekeeper.sol";
import {Hashes} from "../../src/libraries/Hashes.sol";
@ -21,9 +21,9 @@ contract MockStaking {
governor = msg.sender;
}
function ghost(bytes32 receiver, uint256 amount) external returns (uint256) {
function ghost(bytes32 receiver, uint256 amount) external {
require(msg.sender == governor);
return gatekeeper.ghost(receiver, amount);
gatekeeper.ghost(receiver, amount);
}
function createNewGatekeeper() external {
@ -127,25 +127,25 @@ contract GatekeeperWeaverTest is Test {
}
function test_insertationWorksAsExpected() public {
uint256 currentWeavingSession = gatekeeper.currentWeavingSession();
uint256 maxCount = gatekeeper.ENTRIES();
uint256 currentWeavingSession;
uint256 newWeavingSession;
uint256 globalIndex;
(bytes32[] memory whos, uint256[] memory amounts) = _prepareArrays(maxCount);
vm.recordLogs();
for (uint256 i = 0; i < maxCount; i++) {
if (i % 5 == 0) { vm.roll(block.number + 1); }
globalIndex = _insertWithAssert(currentWeavingSession, amounts[i], whos[i]);
(globalIndex, currentWeavingSession) = _insertWithAssert(amounts[i], whos[i]);
assertTrue(_verifyProof(globalIndex, currentWeavingSession, block.number, amounts[i], whos[i]));
}
globalIndex = _insertWithAssert(currentWeavingSession, amounts[69], whos[69]);
uint256 newSession = gatekeeper.currentWeavingSession();
assertEq(currentWeavingSession + 1, newSession);
(globalIndex, newWeavingSession) = _insertWithAssert(amounts[69], whos[69]);
assertEq(currentWeavingSession + 1, newWeavingSession);
vm.roll(block.number + 1337);
assertTrue(_verifyProof(globalIndex, newSession, block.number, amounts[69], whos[69]));
assertTrue(_verifyProof(globalIndex, newWeavingSession, block.number, amounts[69], whos[69]));
assertTrue(_verifyProof(0, currentWeavingSession, block.number, amounts[0], whos[0]));
assertTrue(_verifyProof(69, currentWeavingSession, block.number, amounts[69], whos[69]));
assertTrue(_verifyProof(420, currentWeavingSession, block.number, amounts[420], whos[420]));
@ -156,7 +156,7 @@ contract GatekeeperWeaverTest is Test {
assertTrue(_verifyProof(69, currentWeavingSession, 100, amounts[69], whos[69]));
assertTrue(_verifyProof(420, currentWeavingSession, 100, amounts[420], whos[420]));
assertFalse(_verifyProof(globalIndex, newSession, 100, amounts[69], whos[69]));
assertFalse(_verifyProof(globalIndex, newWeavingSession, 100, amounts[69], whos[69]));
assertFalse(_verifyProof(1337, currentWeavingSession, 100, amounts[1337], whos[1337]));
assertFalse(_verifyProof(2047, currentWeavingSession, 100, amounts[2047], whos[2047]));
@ -174,7 +174,7 @@ contract GatekeeperWeaverTest is Test {
staking.ghost(whos[i], amounts[i]);
}
assertTrue(_verifyProof(globalIndex, newSession, block.number, amounts[69], whos[69]));
assertTrue(_verifyProof(globalIndex, newWeavingSession, block.number, amounts[69], whos[69]));
assertTrue(_verifyProof(0, currentWeavingSession, block.number, amounts[0], whos[0]));
assertTrue(_verifyProof(69, currentWeavingSession, block.number, amounts[69], whos[69]));
assertTrue(_verifyProof(420, currentWeavingSession, block.number, amounts[420], whos[420]));
@ -185,7 +185,7 @@ contract GatekeeperWeaverTest is Test {
assertTrue(_verifyProof(69, currentWeavingSession, 100, amounts[69], whos[69]));
assertTrue(_verifyProof(420, currentWeavingSession, 100, amounts[420], whos[420]));
assertFalse(_verifyProof(globalIndex, newSession, 100, amounts[69], whos[69]));
assertFalse(_verifyProof(globalIndex, newWeavingSession, 100, amounts[69], whos[69]));
assertFalse(_verifyProof(1337, currentWeavingSession, 100, amounts[1337], whos[1337]));
assertFalse(_verifyProof(2047, currentWeavingSession, 100, amounts[2047], whos[2047]));
@ -212,41 +212,43 @@ contract GatekeeperWeaverTest is Test {
}
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);
) private returns (uint256 globalIndex, uint256 emittedSession) {
uint256 preSession = gatekeeper.currentWeavingSession();
uint256 targetSlot = gatekeeper.filledEntries(preSession);
bytes32 previousHash = gatekeeper.treeNodesLatest(preSession, targetSlot);
uint256 prevEntries = gatekeeper.filledEntries(preSession);
uint160 prevLength = gatekeeper.slotLengths(preSession, targetSlot);
vm.prank(ALICE);
globalIndex = staking.ghost(who, amount);
staking.ghost(who, amount);
(globalIndex, emittedSession) = _getInsertedDataFromLogs();
if (preSession != emittedSession) {
assertEq(preSession + 1, emittedSession);
assertEq(emittedSession, gatekeeper.currentWeavingSession());
if (session + 1 == gatekeeper.currentWeavingSession()) {
assertEq(prevLength, gatekeeper.DEPTH());
assertEq(gatekeeper.slotLengths(session + 1, 0), 1);
assertEq(gatekeeper.slotLengths(emittedSession, 0), 1);
assertEq(prevEntries, gatekeeper.ENTRIES());
assertEq(gatekeeper.filledEntries(session + 1), 1);
assertEq(session + 1, gatekeeper.currentWeavingSession());
assertEq(gatekeeper.filledEntries(emittedSession), 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));
assertEq(prevLength + 1, gatekeeper.slotLengths(emittedSession, targetSlot));
assertEq(prevEntries + 1, gatekeeper.filledEntries(emittedSession));
}
{
bytes32 preimage1 = gatekeeper.slotValues(session, globalIndex);
bytes32 preimage1 = gatekeeper.slotValues(emittedSession, globalIndex);
bytes32 preimage2 = gatekeeper.computePreimage(globalIndex, amount, who);
assertEq(preimage1, preimage2);
}
{
bytes32 nodeHash1 = gatekeeper.treeNodesLatest(session, globalIndex);
bytes32 nodeHash1 = gatekeeper.treeNodesLatest(emittedSession, globalIndex);
bytes32 preimageHash = Hashes.efficientKeccak256(
gatekeeper.computePreimage(globalIndex, amount, who)
);
@ -268,4 +270,17 @@ contract GatekeeperWeaverTest is Test {
return (whos, amounts);
}
function _getInsertedDataFromLogs() private returns (uint256 index, uint256 session) {
Vm.Log[] memory entries = vm.getRecordedLogs();
bytes32 targetTopic = keccak256("ThreadInserted(uint256,uint256)");
for (uint256 i = entries.length; i > 0; i--) {
if (entries[i - 1].topics.length > 0 && entries[i - 1].topics[0] == targetTopic) {
(index, session) = abi.decode(entries[i - 1].data, (uint256, uint256));
return (index, session);
}
}
revert("Target event not found in logs");
}
}

View File

@ -86,7 +86,6 @@ contract StakingTest is Test {
event DistributorSet(address distributor);
event WarmupSet(uint256 warmup);
event Ghosted(bytes32 indexed receiver, uint256 indexed amount);
function setUp() public {
vm.startPrank(INITIALIZER);
@ -640,23 +639,6 @@ contract StakingTest is Test {
assertEq(ghst.totalSupply(), 0);
}
function test_ghostTokensEmitsEvent() public {
_prepareAndRoll(ALICE, BIG_AMOUNT, true, true);
uint256 aliceBalance = stnk.balanceOf(ALICE);
vm.startPrank(ALICE);
stnk.approve(address(staking), aliceBalance);
uint256 ghstBalance = staking.wrap(ALICE, aliceBalance);
vm.stopPrank();
bytes32 receiver = bytes32(abi.encodePacked(ALICE));
vm.expectEmit(true, true, true, false, staking.gatekeeper());
emit Ghosted(receiver, ghstBalance);
vm.prank(ALICE);
staking.ghost(receiver, ghstBalance);
}
function test_breakoutLogicWorks() public {
uint256 initialIndex = staking.index();
bytes32 receiver = bytes32(abi.encodePacked(ALICE));
@ -678,9 +660,6 @@ contract StakingTest is Test {
uint256 range = (payout * 3) / 100;
requestedPayout = (pseudoRandom % range) + 1;
vm.expectEmit(true, true, true, false, staking.gatekeeper());
emit Ghosted(receiver, requestedPayout);
vm.prank(ALICE);
staking.breakout(receiver, requestedPayout);
expectedPayout += requestedPayout;