Skip to content

Commit

Permalink
test: hardhat test of bridge tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
huyhuynh3103 committed Jan 25, 2024
1 parent c7170b2 commit 7e8dbae
Show file tree
Hide file tree
Showing 4 changed files with 355 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { IBridgeTracking } from "@ronin/contracts/interfaces/bridge/IBridgeTracking.sol";
import { MockGatewayForTracking } from "@ronin/contracts/mocks/MockGatewayForTracking.sol";
import "../BaseIntegration.t.sol";

// Epoch e-1 test: Vote is approved in the last epoch of period
contract EpochE1_VoteIsApprovedInLastEpoch_BridgeTracking_Test is BaseIntegration_Test {
MockGatewayForTracking _mockRoninGatewayV3;

uint256 _period;
uint256 _receiptId;
IBridgeTracking.VoteKind _receiptKind;
address[] _operators;

function setUp() public virtual override {
super.setUp();
_config.switchTo(Network.RoninLocal.key());
vm.coinbase(makeAddr("coin-base-addr"));

// upgrade ronin gateway v3
_mockRoninGatewayV3 = new MockGatewayForTracking(address(_bridgeTracking));

bytes memory calldata_ =
abi.encodeCall(IHasContracts.setContract, (ContractType.BRIDGE, address(_mockRoninGatewayV3)));
_roninProposalUtils.functionDelegateCall(address(_bridgeTracking), calldata_);

vm.deal(address(_bridgeReward), 10 ether);

_setTimestampToPeriodEnding();
_wrapUpEpochAndMine();

_period = _validatorSet.currentPeriod();
_receiptId = 1;
_receiptKind = IBridgeTracking.VoteKind.Withdrawal;

_operators.push(_param.roninBridgeManager.bridgeOperators[0]);
_operators.push(_param.roninBridgeManager.bridgeOperators[1]);
}

// Epoch e-1: Vote & Approve & Vote > Should not record when not approved yet. Vote in last epoch (e-1).
function test_epochE1_notRecordVoteAndBallot_receiptWithoutApproval() public {
_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, _operators);

assertEq(_bridgeTracking.totalVote(_period), 0);
assertEq(_bridgeTracking.totalBallot(_period), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), 0);
}

// Epoch e-1: Vote & Approve & Vote > Should not record when approve. Approve in last epoch (e-1).
function test_epochE2_notRecordVoteAndBallot_approveInLastEpoch() public {
test_epochE1_notRecordVoteAndBallot_receiptWithoutApproval();

_mockRoninGatewayV3.sendApprovedVote(_receiptKind, _receiptId);

assertEq(_bridgeTracking.totalVote(_period), 0);
assertEq(_bridgeTracking.totalBallot(_period), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), 0);
}

// Epoch e-1: Vote & Approve & Vote > Should not record even after approved. Vote in last epoch (e-1).
function test_epochE1_notRecordVoteAndBallot_voteInLastEpoch() public {
test_epochE2_notRecordVoteAndBallot_approveInLastEpoch();

_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, wrapAddress(_param.roninBridgeManager.bridgeOperators[2]));

assertEq(_bridgeTracking.totalVote(_period), 0);
assertEq(_bridgeTracking.totalBallot(_period), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), 0);
}

// Epoch e: vote > Should not record for current period metric when wrapping up period. Query in next epoch (e), for current period (p-1): return 0.
function test_epochE_notRecordForCurrentPeriod_WhenWrappingUpPeriod() public {
test_epochE1_notRecordVoteAndBallot_voteInLastEpoch();

_setTimestampToPeriodEnding();
_wrapUpEpochAndMine();

uint256 lastPeriod = _period;
uint256 newPeriod = _validatorSet.currentPeriod();
_period = newPeriod;
assertTrue(newPeriod != lastPeriod);

assertEq(_bridgeTracking.totalVote(lastPeriod), 0);
assertEq(_bridgeTracking.totalBallot(lastPeriod), 0);
assertEq(_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[1]), 0);
assertEq(_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[2]), 0);
}

// Epoch e: vote > Should record for the buffer metric when wrapping up period. Query in next epoch (e), for next period (p): return >0 (buffer).
function test_epochE_recordBufferMetricForNewPeriod_WhenWrappingUpPeriod() public {
test_epochE_notRecordForCurrentPeriod_WhenWrappingUpPeriod();

uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 3);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
}

// Epoch e: vote > Should record new ballot for the buffer metric
function test_epochE_recordNewBallotForBufferMetric() public {
test_epochE_recordBufferMetricForNewPeriod_WhenWrappingUpPeriod();

_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, wrapAddress(_param.roninBridgeManager.bridgeOperators[3]));

uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 4);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[3]), expectedTotalVotes);

_wrapUpEpochAndMine();

assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 4);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[3]), expectedTotalVotes);
}

// Epoch 2e-1: vote > Should record new ballot for the buffer metric
function test_epoch2E_1_recordNewBallotForBufferMetric() public {
test_epochE_recordNewBallotForBufferMetric();

_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, wrapAddress(_param.roninBridgeManager.bridgeOperators[4]));

uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 5);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[3]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[4]), expectedTotalVotes);

_setTimestampToPeriodEnding();
_wrapUpEpochAndMine();

assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 5);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[3]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[4]), expectedTotalVotes);
}

// Epoch 3e: vote > Should not record new ballot. And the period metric is finalized as in epoch 2e-1.
function test_epoch3E_notRecordNewBallot_periodMetricIsFinalizedAsInEpoch2E_1() public {
test_epoch2E_1_recordNewBallotForBufferMetric();

_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, wrapAddress(_param.roninBridgeManager.bridgeOperators[5]));

uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 5);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[3]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[4]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[5]), 0);
}

// Epoch 3e: vote > Should the metric of the new period get reset.
function test_epoch3E_metricOfNewPeriodGetReset() public {
test_epoch3E_notRecordNewBallot_periodMetricIsFinalizedAsInEpoch2E_1();

_setTimestampToPeriodEnding();
_wrapUpEpochAndMine();

uint256 lastPeriod = _period;
uint256 newPeriod = _validatorSet.currentPeriod();
_period = newPeriod;
assertTrue(newPeriod != lastPeriod);

assertEq(_bridgeTracking.totalVote(newPeriod), 0);
assertEq(_bridgeTracking.totalBallot(newPeriod), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[1]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[2]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[3]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[4]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[5]), 0);
}

function _wrapUpEpochAndMine() internal {
_validatorSet.endEpoch();
vm.prank(block.coinbase);
_validatorSet.wrapUpEpoch();
// mine a dummy block
vm.roll(block.number + 1);
}

function _setTimestampToPeriodEnding() internal {
vm.warp(((block.timestamp / 86400) + 1) * 86400);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { IBridgeTracking } from "@ronin/contracts/interfaces/bridge/IBridgeTracking.sol";
import { MockGatewayForTracking } from "@ronin/contracts/mocks/MockGatewayForTracking.sol";
import "../BaseIntegration.t.sol";

// Epoch e-2 test: Vote is approved NOT in the last epoch
contract EpochE2_VoteIsNotApprovedInLastEpoch_BridgeTracking_Test is BaseIntegration_Test {
MockGatewayForTracking _mockRoninGatewayV3;

uint256 _period;
uint256 _receiptId;
IBridgeTracking.VoteKind _receiptKind;
address[] _operators;

function setUp() public virtual override {
super.setUp();
_config.switchTo(Network.RoninLocal.key());
vm.coinbase(makeAddr("coin-base-addr"));

// upgrade ronin gateway v3
_mockRoninGatewayV3 = new MockGatewayForTracking(address(_bridgeTracking));

bytes memory calldata_ =
abi.encodeCall(IHasContracts.setContract, (ContractType.BRIDGE, address(_mockRoninGatewayV3)));
_roninProposalUtils.functionDelegateCall(address(_bridgeTracking), calldata_);

vm.deal(address(_bridgeReward), 10 ether);

_setTimestampToPeriodEnding();
_wrapUpEpochAndMine();

_period = _validatorSet.currentPeriod();
_receiptId = 0;
_receiptKind = IBridgeTracking.VoteKind.Deposit;

_operators.push(_param.roninBridgeManager.bridgeOperators[0]);
_operators.push(_param.roninBridgeManager.bridgeOperators[1]);
}

// Epoch e-2: Vote & Approve & Vote. > Should not record the receipts which is not approved yet
function test_epochE2_notRecordVoteAndBallot_receiptWithoutApproval() public {
_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, _operators);

assertEq(_bridgeTracking.totalVote(_period), 0);
assertEq(_bridgeTracking.totalBallot(_period), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), 0);
}

// Epoch e-2: Vote & Approve & Vote. > Should be able to approve the receipts and not record the approved receipts once the epoch is not yet wrapped up
function test_epochE2_recordVoteAndBallot_receiptIsApproved() public {
test_epochE2_notRecordVoteAndBallot_receiptWithoutApproval();

_mockRoninGatewayV3.sendApprovedVote(_receiptKind, _receiptId);
assertEq(_bridgeTracking.totalVote(_period), 0);
assertEq(_bridgeTracking.totalBallot(_period), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), 0);
}

// Epoch e-1: Continue voting for the vote of e-2 > Should be able to record the approved votes/ballots when the epoch is wrapped up
function test_epochE1_continueVotingForVoteOfE2() public {
test_epochE2_recordVoteAndBallot_receiptIsApproved();

_wrapUpEpochAndMine();

uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 2);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
}

// Epoch e-1: Continue voting for the vote of e-2 > Should be able to record the approved votes/ballots when the epoch is wrapped up
function test_epochE1_recordForWhoVoteLately_onceRequestIsApproved() public {
test_epochE1_continueVotingForVoteOfE2();

_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, wrapAddress(_param.roninBridgeManager.bridgeOperators[2]));

_wrapUpEpochAndMine();
uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(_period), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(_period), expectedTotalVotes * 3);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallotOf(_period, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes);
}

// Epoch e (first epoch of new period): Continue voting for vote in e-2 > Should not record in the next period
function test_epochE_continueVotingForVoteInE2_notRecordInNextPeriod() public {
test_epochE1_recordForWhoVoteLately_onceRequestIsApproved();

_setTimestampToPeriodEnding();
_wrapUpEpochAndMine();

uint256 lastPeriod = _period;
uint256 newPeriod = _validatorSet.currentPeriod();
assertTrue(newPeriod != lastPeriod);

_mockRoninGatewayV3.sendBallot(_receiptKind, _receiptId, wrapAddress(_param.roninBridgeManager.bridgeOperators[3]));

uint256 expectedTotalVotes = 1;
assertEq(_bridgeTracking.totalVote(lastPeriod), expectedTotalVotes);
assertEq(_bridgeTracking.totalBallot(lastPeriod), expectedTotalVotes * 3);
assertEq(
_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[0]), expectedTotalVotes
);
assertEq(
_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[1]), expectedTotalVotes
);
assertEq(
_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[2]), expectedTotalVotes
);
assertEq(_bridgeTracking.totalBallotOf(lastPeriod, _param.roninBridgeManager.bridgeOperators[3]), 0);

_period = newPeriod;

assertEq(_bridgeTracking.totalVote(newPeriod), 0);
assertEq(_bridgeTracking.totalBallot(newPeriod), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[0]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[1]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[2]), 0);
assertEq(_bridgeTracking.totalBallotOf(newPeriod, _param.roninBridgeManager.bridgeOperators[3]), 0);
}

function _wrapUpEpochAndMine() internal {
_validatorSet.endEpoch();
vm.prank(block.coinbase);
_validatorSet.wrapUpEpoch();
// mine a dummy block
vm.roll(block.number + 1);
}

function _setTimestampToPeriodEnding() internal {
vm.warp(((block.timestamp / 86400) + 1) * 86400);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ contract DepositVote_RoninGatewayV3_Test is BaseIntegration_Test {

bytes memory calldata_ =
abi.encodeCall(IHasContracts.setContract, (ContractType.BRIDGE_TRACKING, address(_bridgeTracking)));
_roninProposalUtils.functionDelegateCallGlobal(
GlobalProposal.TargetOption.GatewayContract, _roninNonce++, calldata_
);
_roninProposalUtils.functionDelegateCallGlobal(GlobalProposal.TargetOption.GatewayContract, calldata_);

vm.etch(address(_roninGatewayV3), address(new MockRoninGatewayV3Extended()).code);

Expand Down
Loading

0 comments on commit 7e8dbae

Please sign in to comment.