diff --git a/src/ronin/gateway/BridgeTracking.sol b/src/ronin/gateway/BridgeTracking.sol index c55ffa1b7..e663f0edf 100644 --- a/src/ronin/gateway/BridgeTracking.sol +++ b/src/ronin/gateway/BridgeTracking.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.9; +import { console2 as console } from "forge-std/console2.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "../../extensions/collections/HasContracts.sol"; import "../../interfaces/bridge/IBridgeTracking.sol"; @@ -86,12 +87,10 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr delete ______deprecatedValidator; } - function initializeV3( - address bridgeManager, - address bridgeSlash, - address bridgeReward, - address dposGA - ) external reinitializer(3) { + function initializeV3(address bridgeManager, address bridgeSlash, address bridgeReward, address dposGA) + external + reinitializer(3) + { _setContract(ContractType.BRIDGE_MANAGER, bridgeManager); _setContract(ContractType.BRIDGE_SLASH, bridgeSlash); _setContract(ContractType.BRIDGE_REWARD, bridgeReward); @@ -143,21 +142,24 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr /** * @inheritdoc IBridgeTracking */ - function getManyTotalBallots( - uint256 period, - address[] calldata operators - ) external view override returns (uint256[] memory _res) { + function getManyTotalBallots(uint256 period, address[] calldata operators) + external + view + override + returns (uint256[] memory _res) + { _res = _getManyTotalBallots(period, operators); } - function _getManyTotalBallots( - uint256 period, - address[] memory operators - ) internal view returns (uint256[] memory res) { + function _getManyTotalBallots(uint256 period, address[] memory operators) + internal + view + returns (uint256[] memory res) + { uint256 length = operators.length; res = new uint256[](length); bool isBufferCounted = _isBufferCountedForPeriod(period); - for (uint i = 0; i < length; ) { + for (uint256 i = 0; i < length;) { res[i] = _totalBallotOf(period, operators[i], isBufferCounted); unchecked { @@ -176,10 +178,12 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr /** * @inheritdoc IBridgeTracking */ - function handleVoteApproved( - VoteKind kind, - uint256 requestId - ) external override onlyContract(ContractType.BRIDGE) skipOnNotStarted { + function handleVoteApproved(VoteKind kind, uint256 requestId) + external + override + onlyContract(ContractType.BRIDGE) + skipOnNotStarted + { ReceiptTrackingInfo storage _receiptInfo = _receiptTrackingInfo[kind][requestId]; // Only records for the receipt which not approved @@ -193,7 +197,7 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr _bufferRequest.id = requestId; address[] storage _voters = _receiptInfo.voters; - for (uint i = 0; i < _voters.length; ) { + for (uint256 i = 0; i < _voters.length;) { _increaseBallot(kind, requestId, _voters[i], currentPeriod); unchecked { @@ -208,11 +212,12 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr /** * @inheritdoc IBridgeTracking */ - function recordVote( - VoteKind kind, - uint256 requestId, - address operator - ) external override onlyContract(ContractType.BRIDGE) skipOnNotStarted { + function recordVote(VoteKind kind, uint256 requestId, address operator) + external + override + onlyContract(ContractType.BRIDGE) + skipOnNotStarted + { uint256 period = IRoninValidatorSet(getContract(ContractType.VALIDATOR)).currentPeriod(); _trySyncBuffer(); ReceiptTrackingInfo storage _receiptInfo = _receiptTrackingInfo[kind][requestId]; @@ -240,16 +245,11 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr address bridgeSlashContract = getContract(ContractType.BRIDGE_SLASH); (bool success, bytes memory returnOrRevertData) = bridgeSlashContract.call( abi.encodeCall( - IBridgeSlash.execSlashBridgeOperators, - (allOperators, ballots, totalBallot_, totalVote_, lastSyncPeriod) + IBridgeSlash.execSlashBridgeOperators, (allOperators, ballots, totalBallot_, totalVote_, lastSyncPeriod) ) ); if (!success) { - emit ExternalCallFailed( - bridgeSlashContract, - IBridgeSlash.execSlashBridgeOperators.selector, - returnOrRevertData - ); + emit ExternalCallFailed(bridgeSlashContract, IBridgeSlash.execSlashBridgeOperators.selector, returnOrRevertData); } address bridgeRewardContract = getContract(ContractType.BRIDGE_REWARD); @@ -297,11 +297,11 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr /** * @dev See `totalBallotOf`. */ - function _totalBallotOf( - uint256 period, - address operator, - bool mustCountLastStats - ) internal view returns (uint256 _totalBallot) { + function _totalBallotOf(uint256 period, address operator, bool mustCountLastStats) + internal + view + returns (uint256 _totalBallot) + { _totalBallot = _periodMetric[period].totalBallotOf[operator]; if (mustCountLastStats) { _totalBallot += _bufferMetric.data.totalBallotOf[operator]; @@ -317,6 +317,8 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr function _trySyncBuffer() internal { IRoninValidatorSet validatorContract = IRoninValidatorSet(getContract(ContractType.VALIDATOR)); uint256 currentEpoch = validatorContract.epochOf(block.number); + console.log("isSyncBuffer: ", _bufferMetric.lastEpoch < currentEpoch); + console.log("LastEpoch in buffer, currentEpoch ", _bufferMetric.lastEpoch, currentEpoch); if (_bufferMetric.lastEpoch < currentEpoch) { (, uint256 trackedPeriod) = validatorContract.tryGetPeriodOfEpoch(_bufferMetric.lastEpoch + 1); _bufferMetric.lastEpoch = currentEpoch; @@ -327,7 +329,7 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr _metric.totalBallot += _bufferMetric.data.totalBallot; // Copy voters info and voters' ballot - for (uint i = 0; i < _bufferMetric.data.voters.length; ) { + for (uint256 i = 0; i < _bufferMetric.data.voters.length;) { address voter = _bufferMetric.data.voters[i]; _metric.totalBallotOf[voter] += _bufferMetric.data.totalBallotOf[voter]; delete _bufferMetric.data.totalBallotOf[voter]; // need to manually delete each element, due to mapping @@ -338,7 +340,7 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr } // Mark all receipts in the buffer as tracked. Keep total number of receipts and delete receipt details. - for (uint i = 0; i < _bufferMetric.requests.length; ) { + for (uint256 i = 0; i < _bufferMetric.requests.length;) { Request storage _bufferRequest = _bufferMetric.requests[i]; ReceiptTrackingInfo storage _receiptInfo = _receiptTrackingInfo[_bufferRequest.kind][_bufferRequest.id]; _receiptInfo.trackedPeriod = trackedPeriod; @@ -356,12 +358,18 @@ contract BridgeTracking is HasBridgeDeprecated, HasValidatorDeprecated, HasContr /** * @dev Returns whether the buffer stats must be counted or not. */ - function _isBufferCountedForPeriod(uint256 queriedPeriod) internal view returns (bool) { + function _isBufferCountedForPeriod(uint256 queriedPeriod) internal view returns (bool res) { IRoninValidatorSet validatorContract = IRoninValidatorSet(getContract(ContractType.VALIDATOR)); uint256 currentEpoch = validatorContract.epochOf(block.number); - (bool filled, uint256 periodOfNextTemporaryEpoch) = validatorContract.tryGetPeriodOfEpoch( - _bufferMetric.lastEpoch + 1 + (bool filled, uint256 periodOfNextTemporaryEpoch) = + validatorContract.tryGetPeriodOfEpoch(_bufferMetric.lastEpoch + 1); + res = filled && queriedPeriod == periodOfNextTemporaryEpoch && _bufferMetric.lastEpoch < currentEpoch; + console.log("_isBufferCountedForPeriod", res); + console.log( + "- queriedPeriod, periodOfNextTemporaryEpoch, _bufferMetric.lastEpoch", + queriedPeriod, + periodOfNextTemporaryEpoch, + _bufferMetric.lastEpoch ); - return filled && queriedPeriod == periodOfNextTemporaryEpoch && _bufferMetric.lastEpoch < currentEpoch; } } diff --git a/test/bridge/integration/ronin-gateway/updateOperator.t.sol b/test/bridge/integration/ronin-gateway/updateOperator.t.sol new file mode 100644 index 000000000..deb9b947a --- /dev/null +++ b/test/bridge/integration/ronin-gateway/updateOperator.t.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console2 as console } from "forge-std/console2.sol"; +import { Transfer } from "@ronin/contracts/libraries/Transfer.sol"; +import { Token } from "@ronin/contracts/libraries/Token.sol"; +import { ContractType } from "@ronin/contracts/utils/ContractType.sol"; +import { IsolatedGovernance } from "@ronin/contracts/libraries/IsolatedGovernance.sol"; +import { VoteStatusConsumer } from "@ronin/contracts/interfaces/consumers/VoteStatusConsumer.sol"; +import { MockRoninGatewayV3Extended } from "@ronin/contracts/mocks/ronin/MockRoninGatewayV3Extended.sol"; +import "../BaseIntegration.t.sol"; + +contract UpdateOperator_RoninGatewayV3_Test is BaseIntegration_Test { + using Transfer for Transfer.Receipt; + + address _newBridgeOperator; + uint256 _numOperatorsForVoteExecuted; + Transfer.Receipt[] first50Receipts; + Transfer.Receipt[] second50Receipts; + + function setUp() public virtual override { + super.setUp(); + _config.switchTo(Network.RoninLocal.key()); + + vm.deal(address(_bridgeReward), 10 ether); + _newBridgeOperator = makeAddr("new-bridge-operator"); + Transfer.Receipt memory sampleReceipt = Transfer.Receipt({ + id: 0, + kind: Transfer.Kind.Deposit, + ronin: Token.Owner({ addr: makeAddr("recipient"), tokenAddr: address(_roninWeth), chainId: _param.test.roninChainId }), + mainchain: Token.Owner({ + addr: makeAddr("requester"), + tokenAddr: address(_mainchainWeth), + chainId: _param.test.mainchainChainId + }), + info: Token.Info({ erc: Token.Standard.ERC20, id: 0, quantity: 100 }) + }); + + uint256 id = 1; + for (uint256 i; i < 50; i++) { + first50Receipts.push(sampleReceipt); + second50Receipts.push(sampleReceipt); + first50Receipts[i].id = id; + second50Receipts[i].id = id + 50; + + id++; + } + + _numOperatorsForVoteExecuted = + _param.roninBridgeManager.bridgeOperators.length * _param.roninBridgeManager.num / _param.roninBridgeManager.denom; + } + + function test_bulkDeposit_100Txs() public { + _setTimestampToPeriodEnding(); + _wrapUpEpochAndMine(); + uint256 periodAfter = _validatorSet.currentPeriod(); + + for (uint256 i; i < _numOperatorsForVoteExecuted; i++) { + vm.prank(_param.roninBridgeManager.bridgeOperators[i]); + _roninGatewayV3.tryBulkDepositFor(first50Receipts); + } + + vm.prank(_param.roninBridgeManager.governors[0]); + _roninBridgeManager.updateBridgeOperator(_newBridgeOperator); + + _param.roninBridgeManager.bridgeOperators[0] = _newBridgeOperator; + + for (uint256 i; i < _numOperatorsForVoteExecuted; i++) { + vm.prank(_param.roninBridgeManager.bridgeOperators[i]); + _roninGatewayV3.tryBulkDepositFor(second50Receipts); + } + + uint256[] memory totalBallots2 = + _bridgeTracking.getManyTotalBallots(periodAfter, _param.roninBridgeManager.bridgeOperators); + + _setTimestampToPeriodEnding(); + _wrapUpEpochAndMine(); + _wrapUpEpochAndMine(); + + Transfer.Receipt memory sampleReceipt = first50Receipts[0]; + sampleReceipt.id = 101; + + for (uint256 i; i < _numOperatorsForVoteExecuted; i++) { + vm.prank(_param.roninBridgeManager.bridgeOperators[i]); + _roninGatewayV3.depositFor(sampleReceipt); + } + } +}