diff --git a/contracts/interfaces/ISFC.sol b/contracts/interfaces/ISFC.sol index c940a52..9a3f45a 100644 --- a/contracts/interfaces/ISFC.sol +++ b/contracts/interfaces/ISFC.sol @@ -121,6 +121,8 @@ interface ISFC { function getEpochEndBlock(uint256 epoch) external view returns (uint256); + function epochEndTime(uint256 epoch) external view returns (uint256); + function rewardsStash(address delegator, uint256 validatorID) external view returns (uint256); function createValidator(bytes calldata pubkey) external payable; diff --git a/contracts/sfc/SFC.sol b/contracts/sfc/SFC.sol index 5b97ec3..f27501a 100644 --- a/contracts/sfc/SFC.sol +++ b/contracts/sfc/SFC.sol @@ -209,7 +209,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { event AnnouncedRedirection(address indexed from, address indexed to); modifier onlyDriver() { - if (!isNode(msg.sender)) { + if (!_isNode(msg.sender)) { revert NotDriverAuth(); } _; @@ -552,6 +552,11 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { return getEpochSnapshot[epoch].endBlock; } + /// Get epoch end time. + function epochEndTime(uint256 epoch) public view returns (uint256) { + return getEpochSnapshot[epoch].endTime; + } + /// Check whether the given validator is slashed - the stake (or its part) cannot /// be withdrawn because of misbehavior (double-sign) of the validator. function isSlashed(uint256 validatorID) public view returns (bool) { @@ -572,7 +577,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { } /// Check if an address is the NodeDriverAuth contract. - function isNode(address addr) internal view virtual returns (bool) { + function _isNode(address addr) internal view virtual returns (bool) { return addr == address(node); } @@ -649,7 +654,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { } /// Get slashing penalty for a stake. - function getSlashingPenalty( + function _getSlashingPenalty( uint256 amount, bool isCheater, uint256 refundRatio @@ -693,7 +698,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { uint256 amount = getWithdrawalRequest[delegator][toValidatorID][wrID].amount; bool isCheater = isSlashed(toValidatorID); - uint256 penalty = getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]); + uint256 penalty = _getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]); delete getWithdrawalRequest[delegator][toValidatorID][wrID]; if (amount <= penalty) { @@ -777,11 +782,6 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { } } - /// Get epoch end time. - function epochEndTime(uint256 epoch) internal view returns (uint256) { - return getEpochSnapshot[epoch].endTime; - } - /// Check if an address is redirected. function _redirected(address addr) internal view returns (bool) { return getRedirection[addr] != address(0); @@ -1045,6 +1045,22 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { totalSupply = totalSupply + amount; } + /// Sync validator with node. + function _syncValidator(uint256 validatorID, bool syncPubkey) internal { + if (!_validatorExists(validatorID)) { + revert ValidatorNotExists(); + } + // emit special log for node + uint256 weight = getValidator[validatorID].receivedStake; + if (getValidator[validatorID].status != OK_STATUS) { + weight = 0; + } + node.updateValidatorWeight(validatorID, weight); + if (syncPubkey && weight != 0) { + node.updateValidatorPubkey(validatorID, getValidatorPubkey[validatorID]); + } + } + /// Notify stake subscriber about staking changes. /// Used to recount votes from delegators in the governance contract. function _notifyStakeSubscriber(address delegator, address validatorAuth, bool strict) internal { @@ -1082,22 +1098,6 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { } } - /// Sync validator with node. - function _syncValidator(uint256 validatorID, bool syncPubkey) public { - if (!_validatorExists(validatorID)) { - revert ValidatorNotExists(); - } - // emit special log for node - uint256 weight = getValidator[validatorID].receivedStake; - if (getValidator[validatorID].status != OK_STATUS) { - weight = 0; - } - node.updateValidatorWeight(validatorID, weight); - if (syncPubkey && weight != 0) { - node.updateValidatorPubkey(validatorID, getValidatorPubkey[validatorID]); - } - } - /// Check if a validator exists. function _validatorExists(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].createdTime != 0; diff --git a/contracts/test/UnitTestSFC.sol b/contracts/test/UnitTestSFC.sol index e45a54d..5c40c05 100644 --- a/contracts/test/UnitTestSFC.sol +++ b/contracts/test/UnitTestSFC.sol @@ -40,11 +40,15 @@ contract UnitTestSFC is SFC { return time; } - function isNode(address addr) internal view override returns (bool) { + function _isNode(address addr) internal view override returns (bool) { if (allowedNonNodeCalls) { return true; } - return SFC.isNode(addr); + return SFC._isNode(addr); + } + + function syncValidator(uint256 validatorID, bool syncPubkey) public { + _syncValidator(validatorID, syncPubkey); } } diff --git a/test/SFC.ts b/test/SFC.ts index c3351c3..e8e537d 100644 --- a/test/SFC.ts +++ b/test/SFC.ts @@ -65,7 +65,7 @@ describe('SFC', () => { }); it('Should succeed and set genesis validator with bad status', async function () { - await this.sfc._syncValidator(1, false); + await this.sfc.syncValidator(1, false); }); it('Should revert when sealEpoch not called by node', async function () { @@ -946,7 +946,7 @@ describe('SFC', () => { }); it('Should revert when syncing if validator does not exist', async function () { - await expect(this.sfc._syncValidator(33, false)).to.be.revertedWithCustomError(this.sfc, 'ValidatorNotExists'); + await expect(this.sfc.syncValidator(33, false)).to.be.revertedWithCustomError(this.sfc, 'ValidatorNotExists'); }); });