From 64c57dc710ca589e1b34e4ceaa8c49183d4e46d9 Mon Sep 17 00:00:00 2001 From: Roshan Date: Thu, 28 Dec 2023 15:12:44 +0800 Subject: [PATCH 1/4] fix: resolve review comments --- abi/bscvalidatorset.abi | 26 +++---- abi/slashindicator.abi | 19 ------ abi/stakehub.abi | 2 +- abi/systemreward.abi | 37 ---------- abi/tokenhub.abi | 24 ------- contracts/BC_fusion/StakeHub.sol | 6 +- .../BC_fusion/interface/IBSCValidatorSet.sol | 3 +- contracts/BSCValidatorSet.sol | 68 ++++++++----------- contracts/GovHub.sol | 3 +- contracts/SlashIndicator.sol | 37 ++++------ contracts/SystemReward.sol | 17 +---- contracts/TokenHub.sol | 4 -- contracts/interface/IBSCValidatorSet.sol | 2 +- contracts/interface/ISystemReward.sol | 1 - package.json | 2 +- scripts/generate.py | 26 +++++-- test/SlashIndicator.t.sol | 10 +-- test/ValidatorSet.t.sol | 4 +- test/utils/interface/IBSCValidatorSet.sol | 2 +- test/utils/interface/ISlashIndicator.sol | 1 - test/utils/interface/IStakeHub.sol | 2 +- test/utils/interface/ISystemReward.sol | 2 - test/utils/interface/ITokenHub.sol | 1 - 23 files changed, 91 insertions(+), 208 deletions(-) diff --git a/abi/bscvalidatorset.abi b/abi/bscvalidatorset.abi index 27ee4c99..a957e052 100644 --- a/abi/bscvalidatorset.abi +++ b/abi/bscvalidatorset.abi @@ -1062,19 +1062,6 @@ ], "stateMutability": "view" }, - { - "type": "function", - "name": "jailValidator", - "inputs": [ - { - "name": "consensusAddress", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, { "type": "function", "name": "maintainSlashScale", @@ -1224,6 +1211,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "removeTmpMigratedValidator", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "systemRewardRatio", diff --git a/abi/slashindicator.abi b/abi/slashindicator.abi index 5cde6e51..8805bf5a 100644 --- a/abi/slashindicator.abi +++ b/abi/slashindicator.abi @@ -865,25 +865,6 @@ ], "anonymous": false }, - { - "type": "event", - "name": "failedMaliciousVoteSlash", - "inputs": [ - { - "name": "voteAddrSlice", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "failReason", - "type": "bytes", - "indexed": false, - "internalType": "bytes" - } - ], - "anonymous": false - }, { "type": "event", "name": "indicatorCleaned", diff --git a/abi/stakehub.abi b/abi/stakehub.abi index 2a783eed..8cdd1b74 100644 --- a/abi/stakehub.abi +++ b/abi/stakehub.abi @@ -1009,7 +1009,7 @@ "internalType": "address" }, { - "name": "commissionRate", + "name": "newCommissionRate", "type": "uint64", "indexed": false, "internalType": "uint64" diff --git a/abi/systemreward.abi b/abi/systemreward.abi index 9ea8b5a6..7e7a13fe 100644 --- a/abi/systemreward.abi +++ b/abi/systemreward.abi @@ -159,19 +159,6 @@ ], "stateMutability": "view" }, - { - "type": "function", - "name": "MAX_REWARDS_FOR_FINALITY", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "RELAYERHUB_CONTRACT_ADDR", @@ -417,30 +404,6 @@ ], "stateMutability": "nonpayable" }, - { - "type": "function", - "name": "claimRewardsforFinality", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address payable" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, { "type": "function", "name": "isOperator", diff --git a/abi/tokenhub.abi b/abi/tokenhub.abi index 7eff9d05..05aa560a 100644 --- a/abi/tokenhub.abi +++ b/abi/tokenhub.abi @@ -750,30 +750,6 @@ ], "stateMutability": "nonpayable" }, - { - "type": "function", - "name": "claimRewardsforFinality", - "inputs": [ - { - "name": "", - "type": "address", - "internalType": "address payable" - }, - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, { "type": "function", "name": "getBep2SymbolByContractAddr", diff --git a/contracts/BC_fusion/StakeHub.sol b/contracts/BC_fusion/StakeHub.sol index 66114cbe..65a93558 100644 --- a/contracts/BC_fusion/StakeHub.sol +++ b/contracts/BC_fusion/StakeHub.sol @@ -176,7 +176,7 @@ contract StakeHub is System, Initializable { bytes voteAddress ); event ConsensusAddressEdited(address indexed operatorAddress, address indexed newConsensusAddress); - event CommissionRateEdited(address indexed operatorAddress, uint64 commissionRate); + event CommissionRateEdited(address indexed operatorAddress, uint64 newCommissionRate); event DescriptionEdited(address indexed operatorAddress); event VoteAddressEdited(address indexed operatorAddress, bytes newVoteAddress); event Delegated(address indexed operatorAddress, address indexed delegator, uint256 shares, uint256 bnbAmount); @@ -994,8 +994,8 @@ contract StakeHub is System, Initializable { } if (IStakeCredit(valInfo.creditContract).getPooledBNB(operatorAddress) < minSelfDelegationBNB) { _jailValidator(valInfo, downtimeJailTime); - // need to inform BSCValidatorSet contract to remove the validator - IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).jailValidator(valInfo.consensusAddress); + IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).removeTmpMigratedValidator(valInfo.consensusAddress); + IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).felony(valInfo.consensusAddress); } } diff --git a/contracts/BC_fusion/interface/IBSCValidatorSet.sol b/contracts/BC_fusion/interface/IBSCValidatorSet.sol index bb9a4f94..a66287f0 100644 --- a/contracts/BC_fusion/interface/IBSCValidatorSet.sol +++ b/contracts/BC_fusion/interface/IBSCValidatorSet.sol @@ -2,5 +2,6 @@ pragma solidity 0.8.17; interface IBSCValidatorSet { - function jailValidator(address consensusAddress) external; + function felony(address consensusAddress) external; + function removeTmpMigratedValidator(address consensusAddress) external; } diff --git a/contracts/BSCValidatorSet.sol b/contracts/BSCValidatorSet.sol index 31370fa7..5ecd394e 100644 --- a/contracts/BSCValidatorSet.sol +++ b/contracts/BSCValidatorSet.sol @@ -188,8 +188,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica receive() external payable {} /*********************** Cross Chain App Implement **************************/ - // TODO: add `onlyCrossChainContract` - function handleSynPackage(uint8, bytes calldata msgBytes) onlyInit initValidatorExtraSet external override returns(bytes memory responsePayload) { + function handleSynPackage(uint8, bytes calldata msgBytes) onlyInit onlyCrossChainContract initValidatorExtraSet external override returns(bytes memory responsePayload) { (IbcValidatorSetPackage memory validatorSetPackage, bool ok) = decodeValidatorSetSynPackage(msgBytes); if (!ok) { return CmnPkg.encodeCommonAckPackage(ERROR_FAIL_DECODE); @@ -202,13 +201,18 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica emit failReasonWithStr("length of jail validators must be one"); resCode = ERROR_LEN_OF_VAL_MISMATCH; } else { - uint256 index = currentValidatorSetMap[validatorSetPackage.validatorSet[0].consensusAddress]; - if (index==0 || currentValidatorSet[index-1].jailed) { - emit validatorEmptyJailed(validatorSetPackage.validatorSet[0].consensusAddress); - resCode = CODE_OK; + address validator = validatorSetPackage.validatorSet[0].consensusAddress; + uint256 index = currentValidatorSetMap[validator]; + if (index == 0 || currentValidatorSet[index-1].jailed) { + emit validatorEmptyJailed(validator); } else { - resCode = _jailValidator(index); + // felony will failed if the validator is the only one in the validator set + bool success = _felony(validator, index-1); + if (!success) { + emit validatorEmptyJailed(validator); + } } + resCode = CODE_OK; } } else { resCode = ERROR_UNKNOWN_PACKAGE_TYPE; @@ -357,36 +361,6 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } } - function jailValidator(address consensusAddress) external onlyStakeHub { - for (uint256 i; i < _tmpMigratedValidatorSet.length; ++i) { - if (_tmpMigratedValidatorSet[i].consensusAddress == consensusAddress) { - _tmpMigratedValidatorSet[i].jailed = true; - break; - } - } - - uint256 index = currentValidatorSetMap[consensusAddress]; - if (index==0 || currentValidatorSet[index-1].jailed) { - emit validatorEmptyJailed(consensusAddress); - } else { - _jailValidator(index); - } - } - - function _jailValidator(uint256 index) internal returns (uint32) { - uint n = currentValidatorSet.length; - bool shouldKeep = (numOfJailed >= n-1); - // will not jail if it is the last valid validator - if (shouldKeep) { - emit validatorEmptyJailed(currentValidatorSet[index-1].consensusAddress); - return CODE_OK; - } - ++numOfJailed; - currentValidatorSet[index-1].jailed = true; - emit validatorJailed(currentValidatorSet[index-1].consensusAddress); - return CODE_OK; - } - function updateValidatorSet(Validator[] memory validatorSet, bytes[] memory voteAddrs) internal returns (uint32) { { // do verify. @@ -701,7 +675,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica return; } - totalValue = ISystemReward(SYSTEM_REWARD_ADDR).claimRewardsforFinality(payable(address(this)), totalValue); + totalValue = ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(payable(address(this)), totalValue); if (totalValue == 0) { return; } @@ -758,7 +732,9 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } } - function felony(address validator)external onlySlash initValidatorExtraSet override{ + function felony(address validator) external initValidatorExtraSet override { + require(msg.sender == SLASH_CONTRACT_ADDR || msg.sender == STAKE_HUB_ADDR, "only slash or stakeHub contract"); + uint256 index = currentValidatorSetMap[validator]; if (index <= 0) { return; @@ -772,6 +748,15 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } } + function removeTmpMigratedValidator(address validator) external onlyStakeHub { + for (uint256 i; i < _tmpMigratedValidatorSet.length; ++i) { + if (_tmpMigratedValidatorSet[i].consensusAddress == validator) { + _tmpMigratedValidatorSet[i].jailed = true; + break; + } + } + } + /*********************** For Temporary Maintenance **************************/ function getCurrentValidatorIndex(address _validator) public view returns (uint256) { uint256 index = currentValidatorSetMap[_validator]; @@ -1064,6 +1049,8 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica // should not happen, but still protect return index; } + + // averageDistribute*rest may less than income, but it is ok, the dust income will go to system reward eventually. uint256 averageDistribute = income / rest; if (averageDistribute != 0) { for (uint i; i= block.number, "evidence too old"); - // reward sender and felony validator if validator found - (address[] memory vals, ) = IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).getLivingValidators(); - for (uint i; i < vals.length; ++i) { - if (signer == vals[i]) { - uint256 amount = (address(SYSTEM_REWARD_ADDR).balance * felonySlashRewardRatio) / 100; - ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(msg.sender, amount); - IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).felony(vals[i]); - break; - } - } - + // reward sender and felony validator IStakeHub(STAKE_HUB_ADDR).doubleSignSlash(signer); + IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).felony(signer); + + uint256 amount = (address(SYSTEM_REWARD_ADDR).balance * felonySlashRewardRatio) / 100; + ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(msg.sender, amount); } /** diff --git a/contracts/SystemReward.sol b/contracts/SystemReward.sol index 26f29eca..a9591bfd 100644 --- a/contracts/SystemReward.sol +++ b/contracts/SystemReward.sol @@ -6,8 +6,7 @@ import "./interface/IParamSubscriber.sol"; import "./interface/ISystemReward.sol"; contract SystemReward is System, IParamSubscriber, ISystemReward { - uint256 public constant MAX_REWARDS/*_FOR_RELAYER*/ = 1e18; - uint256 public constant MAX_REWARDS_FOR_FINALITY = 5e18; + uint256 public constant MAX_REWARDS = 5e18; uint public numOperator; mapping(address => bool) operators; @@ -54,20 +53,6 @@ contract SystemReward is System, IParamSubscriber, ISystemReward { return actualAmount; } - function claimRewardsforFinality(address payable to, uint256 amount) external override(ISystemReward) doInit onlyOperator returns (uint256) { - uint256 actualAmount = amount < address(this).balance ? amount : address(this).balance; - if (actualAmount > MAX_REWARDS_FOR_FINALITY) { - actualAmount = MAX_REWARDS_FOR_FINALITY; - } - if (actualAmount != 0) { - to.transfer(actualAmount); - emit rewardTo(to, actualAmount); - } else { - emit rewardEmpty(); - } - return actualAmount; - } - function isOperator(address addr) external view returns (bool) { return operators[addr]; } diff --git a/contracts/TokenHub.sol b/contracts/TokenHub.sol index ef5c10a5..0945b133 100644 --- a/contracts/TokenHub.sol +++ b/contracts/TokenHub.sol @@ -167,10 +167,6 @@ contract TokenHub is ITokenHub, System, IParamSubscriber, IApplication, ISystemR return actualAmount; } - function claimRewardsforFinality(address payable, uint256) onlyInit onlyRelayerIncentivize external override returns(uint256) { - revert("CLAIM_REWARDS_FOR_FINALITY_NOT_ALLOWED"); - } - function getMiniRelayFee() external view override returns(uint256) { return relayFee; } diff --git a/contracts/interface/IBSCValidatorSet.sol b/contracts/interface/IBSCValidatorSet.sol index b9b59552..b3a060b9 100644 --- a/contracts/interface/IBSCValidatorSet.sol +++ b/contracts/interface/IBSCValidatorSet.sol @@ -3,7 +3,7 @@ pragma experimental ABIEncoderV2; interface IBSCValidatorSet { function misdemeanor(address validator) external; - function felony(address validator)external; + function felony(address validator) external; function isCurrentValidator(address validator) external view returns (bool); function getLivingValidators() external view returns(address[] memory, bytes[] memory); function getMiningValidators() external view returns(address[] memory, bytes[] memory); diff --git a/contracts/interface/ISystemReward.sol b/contracts/interface/ISystemReward.sol index 4e127df6..67a71f58 100644 --- a/contracts/interface/ISystemReward.sol +++ b/contracts/interface/ISystemReward.sol @@ -2,5 +2,4 @@ pragma solidity 0.6.4; interface ISystemReward { function claimRewards(address payable to, uint256 amount) external returns(uint256 actualAmount); - function claimRewardsforFinality(address payable to, uint256 amount) external returns(uint256 actualAmount); } \ No newline at end of file diff --git a/package.json b/package.json index 94023fd0..3a43ceb1 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "lint:check": "forge fmt ./contracts/BC_fusion --check", "lint:write": "forge fmt ./contracts/BC_fusion", - "generate:dev": "poetry run python -m scripts.generate dev --init-felony-slash-scope \"60\" --breathe-block-interval \"1 minutes\" --block-interval \"3 seconds\" --init-bc-consensus-addresses 'hex\"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc\"' --init-bc-vote-addresses 'hex\"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000030b86b3146bdd2200b1dbdb1cea5e40d3451c028cbb4fb03b1826f7f2d82bee76bbd5cd68a74a16a7eceea093fd5826b9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003087ce273bb9b51fd69e50de7a8d9a99cfb3b1a5c6a7b85f6673d137a5a2ce7df3d6ee4e6d579a142d58b0606c4a7a1c27000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a33ac14980d85c0d154c5909ebf7a11d455f54beb4d5d0dc1d8b3670b9c4a6b6c450ee3d623ecc48026f09ed1f0b5c1200000000000000000000000000000000\"' --asset-protector \"0xdF87F0e2B8519Ea2DD4aBd8B639cdD628497eD25\" --unbond-period \"2 minutes\" --downtime-jail-time \"2 minutes\" --felony-jail-time \"3 minutes\" --init-voting-delay \"1 minutes / BLOCK_INTERVAL\" --init-voting-period \"2 minutes / BLOCK_INTERVAL\" --init-min-period-after-quorum \"uint64(1 minutes / BLOCK_INTERVAL)\" --governor-protector \"0xdF87F0e2B8519Ea2DD4aBd8B639cdD628497eD25\" --init-minimal-delay \"1 minutes\" --lock-period-for-token-recover \"1 minutes\"" + "generate:dev": "poetry run python -m scripts.generate dev --epoch \"20\" --misdemeanor-threshold \"5\" --felony-threshold \"10\" --init-felony-slash-scope \"60\" --breathe-block-interval \"1 minutes\" --block-interval \"3 seconds\" --init-bc-consensus-addresses 'hex\"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc\"' --init-bc-vote-addresses 'hex\"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000030b86b3146bdd2200b1dbdb1cea5e40d3451c028cbb4fb03b1826f7f2d82bee76bbd5cd68a74a16a7eceea093fd5826b9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003087ce273bb9b51fd69e50de7a8d9a99cfb3b1a5c6a7b85f6673d137a5a2ce7df3d6ee4e6d579a142d58b0606c4a7a1c27000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a33ac14980d85c0d154c5909ebf7a11d455f54beb4d5d0dc1d8b3670b9c4a6b6c450ee3d623ecc48026f09ed1f0b5c1200000000000000000000000000000000\"' --asset-protector \"0xdF87F0e2B8519Ea2DD4aBd8B639cdD628497eD25\" --unbond-period \"2 minutes\" --downtime-jail-time \"2 minutes\" --felony-jail-time \"3 minutes\" --init-voting-delay \"1 minutes / BLOCK_INTERVAL\" --init-voting-period \"2 minutes / BLOCK_INTERVAL\" --init-min-period-after-quorum \"uint64(1 minutes / BLOCK_INTERVAL)\" --governor-protector \"0xdF87F0e2B8519Ea2DD4aBd8B639cdD628497eD25\" --init-minimal-delay \"1 minutes\" --lock-period-for-token-recover \"1 minutes\"" }, "dependencies": { "@openzeppelin/contracts": "^4.9.3", diff --git a/scripts/generate.py b/scripts/generate.py index 43e56b67..e423e86a 100644 --- a/scripts/generate.py +++ b/scripts/generate.py @@ -116,12 +116,14 @@ def generate_relayer_hub(whitelist_1, whitelist_2): insert(contract, "alreadyInit = true;", "\t\twhitelistInit();") -def generate_slash_indicator(init_felony_slash_scope): +def generate_slash_indicator(misdemeanor_threshold, felony_threshold, init_felony_slash_scope): contract = "SlashIndicator.sol" backup_file( os.path.join(work_dir, "contracts", contract), os.path.join(work_dir, "contracts", contract[:-4] + ".bak") ) + replace_parameter(contract, "uint256 public constant MISDEMEANOR_THRESHOLD", f"{misdemeanor_threshold}") + replace_parameter(contract, "uint256 public constant FELONY_THRESHOLD", f"{felony_threshold}") replace_parameter(contract, "uint256 public constant INIT_FELONY_SLASH_SCOPE", f"{init_felony_slash_scope}") if network == "dev": @@ -231,7 +233,7 @@ def generate_token_recover_portal(source_chain_id): replace_parameter(contract, "string public constant SOURCE_CHAIN_ID", f"\"{source_chain_id}\"") -def generate_validator_set(init_burn_ratio, init_validatorset_bytes): +def generate_validator_set(init_validatorset_bytes, init_burn_ratio, epoch): contract = "BSCValidatorSet.sol" backup_file( os.path.join(work_dir, "contracts", contract), os.path.join(work_dir, "contracts", contract[:-4] + ".bak") @@ -239,6 +241,7 @@ def generate_validator_set(init_burn_ratio, init_validatorset_bytes): replace_parameter(contract, "uint256 public constant INIT_BURN_RATIO", f"{init_burn_ratio}") replace_parameter(contract, "bytes public constant INIT_VALIDATORSET_BYTES", f"hex\"{init_validatorset_bytes}\"") + replace_parameter(contract, "uint256 public constant EPOCH", f"{epoch}") if network == "dev": insert( @@ -253,6 +256,17 @@ def generate_validator_set(init_burn_ratio, init_validatorset_bytes): contract, r"currentValidatorSet\.push\(validatorSetPkg.validatorSet\[i\]\);", "\t\t\tvalidatorExtraSet[i].voteAddress=validatorSetPkg.voteAddrs[i];" ) + replace(contract, r"handleSynPackage\(uint8, bytes calldata msgBytes\) onlyInit onlyCrossChainContract initValidatorExtraSet", "handleSynPackage(uint8, bytes calldata msgBytes) onlyInit initValidatorExtraSet") + + +def generate_gov_hub(): + contract = "GovHub.sol" + backup_file( + os.path.join(work_dir, "contracts", contract), os.path.join(work_dir, "contracts", contract[:-4] + ".bak") + ) + + if network == "dev": + replace(contract, r"handleSynPackage\(uint8, bytes calldata msgBytes\) external onlyCrossChainContract override", "handleSynPackage(uint8, bytes calldata msgBytes) external override") def generate_genesis(): @@ -345,12 +359,15 @@ def dev( init_consensus_bytes: str = "42696e616e63652d436861696e2d4e696c650000000000000000000000000000000000000000000229eca254b3859bffefaf85f4c95da9fbd26527766b784272789c30ec56b380b6eb96442aaab207bc59978ba3dd477690f5c5872334fc39e627723daa97e441e88ba4515150ec3182bc82593df36f8abb25a619187fcfab7e552b94e64ed2deed000000e8d4a51000", init_burn_ratio: Annotated[str, typer.Option(help="init burn ratio of BscValidatorSet")] = "1000", + epoch: str = "200", whitelist_1: Annotated[ str, typer.Option(help="whitelist relayer1's address")] = "0xA904540818AC9c47f2321F97F1069B9d8746c6DB", whitelist_2: Annotated[ str, typer.Option(help="whitelist relayer2's address")] = "0x316b2Fa7C8a2ab7E21110a4B3f58771C01A71344", source_chain_id: Annotated[ str, typer.Option(help="source chain id of the token recover portal")] = "Binance-Chain-Ganges", + misdemeanor_threshold: str = "50", + felony_threshold: str = "150", init_felony_slash_scope: str = "86400", breathe_block_interval: Annotated[str, typer.Option(help="breath block interval of Parlia")] = "1 days", block_interval: Annotated[str, typer.Option(help="block interval of Parlia")] = "3 seconds", @@ -399,10 +416,11 @@ def dev( generate_system() generate_cross_chain() generate_system_reward() - generate_slash_indicator(init_felony_slash_scope) + generate_gov_hub() + generate_slash_indicator(misdemeanor_threshold, felony_threshold, init_felony_slash_scope) generate_relayer_hub(whitelist_1, whitelist_2) generate_tendermint_light_client(init_consensus_bytes) - generate_validator_set(init_burn_ratio, init_validatorset_bytes) + generate_validator_set(init_validatorset_bytes, init_burn_ratio, epoch) generate_token_recover_portal(source_chain_id) generate_stake_hub( breathe_block_interval, init_bc_consensus_addresses, init_bc_vote_addresses, unbond_period, downtime_jail_time, diff --git a/test/SlashIndicator.t.sol b/test/SlashIndicator.t.sol index fade3d90..c771af2b 100644 --- a/test/SlashIndicator.t.sol +++ b/test/SlashIndicator.t.sol @@ -296,15 +296,9 @@ contract SlashIndicatorTest is Deployer { uint256 mockEvidenceHeight = block.number - 1; bytes memory mockOutput = bytes.concat(abi.encodePacked(mockValidator), abi.encodePacked(mockEvidenceHeight)); + vm.mockCall(address(0x68), "", mockOutput); vm.mockCall( - address(0x68), - "", - mockOutput - ); - vm.mockCall( - address(stakeHub), - abi.encodeCall(stakeHub.consensusToOperator, (mockValidator)), - abi.encode(mockValidator) + address(stakeHub), abi.encodeCall(stakeHub.consensusToOperator, (mockValidator)), abi.encode(mockValidator) ); vm.prank(relayer); diff --git a/test/ValidatorSet.t.sol b/test/ValidatorSet.t.sol index da828ba6..e4237ab4 100644 --- a/test/ValidatorSet.t.sol +++ b/test/ValidatorSet.t.sol @@ -595,8 +595,8 @@ contract ValidatorSetTest is Deployer { bscValidatorSet.distributeFinalityReward(addrs, weights); assertEq(address(systemReward).balance, ceil); - // cannot exceed MAX_REWARDS_FOR_FINALITY - uint256 cap = systemReward.MAX_REWARDS_FOR_FINALITY(); + // cannot exceed MAX_REWARDS + uint256 cap = systemReward.MAX_REWARDS(); vm.deal(address(systemReward), ceil + cap * 2); vm.roll(block.number + 1); diff --git a/test/utils/interface/IBSCValidatorSet.sol b/test/utils/interface/IBSCValidatorSet.sol index 0f3e2574..bfe13a4c 100644 --- a/test/utils/interface/IBSCValidatorSet.sol +++ b/test/utils/interface/IBSCValidatorSet.sol @@ -110,7 +110,6 @@ interface BSCValidatorSet { function isMonitoredForMaliciousVote(bytes memory voteAddr) external view returns (bool); function isSystemRewardIncluded() external view returns (bool); function isWorkingValidator(uint256 index) external view returns (bool); - function jailValidator(address consensusAddress) external; function maintainSlashScale() external view returns (uint256); function maxNumOfCandidates() external view returns (uint256); function maxNumOfMaintaining() external view returns (uint256); @@ -122,6 +121,7 @@ interface BSCValidatorSet { function previousBalanceOfSystemReward() external view returns (uint256); function previousHeight() external view returns (uint256); function previousVoteAddrFullSet(uint256) external view returns (bytes memory); + function removeTmpMigratedValidator(address validator) external; function systemRewardRatio() external view returns (uint256); function totalInComing() external view returns (uint256); function updateParam(string memory key, bytes memory value) external; diff --git a/test/utils/interface/ISlashIndicator.sol b/test/utils/interface/ISlashIndicator.sol index 5f6f256f..25f25207 100644 --- a/test/utils/interface/ISlashIndicator.sol +++ b/test/utils/interface/ISlashIndicator.sol @@ -18,7 +18,6 @@ interface SlashIndicator { event crashResponse(); event failedFelony(address indexed validator, uint256 slashCount, bytes failReason); - event failedMaliciousVoteSlash(bytes32 indexed voteAddrSlice, bytes failReason); event indicatorCleaned(); event knownResponse(uint32 code); event maliciousVoteSlashed(bytes32 indexed voteAddrSlice); diff --git a/test/utils/interface/IStakeHub.sol b/test/utils/interface/IStakeHub.sol index 61e96e01..c3754485 100644 --- a/test/utils/interface/IStakeHub.sol +++ b/test/utils/interface/IStakeHub.sol @@ -50,7 +50,7 @@ interface StakeHub { error ZeroShares(); event Claimed(address indexed operatorAddress, address indexed delegator, uint256 bnbAmount); - event CommissionRateEdited(address indexed operatorAddress, uint64 commissionRate); + event CommissionRateEdited(address indexed operatorAddress, uint64 newCommissionRate); event ConsensusAddressEdited(address indexed operatorAddress, address indexed newConsensusAddress); event Delegated(address indexed operatorAddress, address indexed delegator, uint256 shares, uint256 bnbAmount); event DescriptionEdited(address indexed operatorAddress); diff --git a/test/utils/interface/ISystemReward.sol b/test/utils/interface/ISystemReward.sol index 2ba40c7c..35094829 100644 --- a/test/utils/interface/ISystemReward.sol +++ b/test/utils/interface/ISystemReward.sol @@ -23,7 +23,6 @@ interface SystemReward { function INCENTIVIZE_ADDR() external view returns (address); function LIGHT_CLIENT_ADDR() external view returns (address); function MAX_REWARDS() external view returns (uint256); - function MAX_REWARDS_FOR_FINALITY() external view returns (uint256); function RELAYERHUB_CONTRACT_ADDR() external view returns (address); function SLASH_CHANNELID() external view returns (uint8); function SLASH_CONTRACT_ADDR() external view returns (address); @@ -42,7 +41,6 @@ interface SystemReward { function alreadyInit() external view returns (bool); function bscChainID() external view returns (uint16); function claimRewards(address payable to, uint256 amount) external returns (uint256); - function claimRewardsforFinality(address payable to, uint256 amount) external returns (uint256); function isOperator(address addr) external view returns (bool); function numOperator() external view returns (uint256); function updateParam(string memory key, bytes memory value) external; diff --git a/test/utils/interface/ITokenHub.sol b/test/utils/interface/ITokenHub.sol index 34d952e7..66755341 100644 --- a/test/utils/interface/ITokenHub.sol +++ b/test/utils/interface/ITokenHub.sol @@ -85,7 +85,6 @@ interface TokenHub { function cancelTokenRecoverLock(bytes32 tokenSymbol, address attacker) external; function cancelTransferIn(address tokenAddress, address attacker) external; function claimRewards(address payable to, uint256 amount) external returns (uint256); - function claimRewardsforFinality(address payable, uint256) external returns (uint256); function getBep2SymbolByContractAddr(address contractAddr) external view returns (bytes32); function getBoundBep2Symbol(address contractAddr) external view returns (string memory); function getBoundContract(string memory bep2Symbol) external view returns (address); From 348af6b79024f03c0993a595facec36d14f1566c Mon Sep 17 00:00:00 2001 From: Roshan Date: Wed, 3 Jan 2024 14:40:59 +0800 Subject: [PATCH 2/4] add check to `_jailValidator` --- contracts/BC_fusion/StakeHub.sol | 7 ++++++- contracts/BC_fusion/interface/ICrossChain.sol | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 contracts/BC_fusion/interface/ICrossChain.sol diff --git a/contracts/BC_fusion/StakeHub.sol b/contracts/BC_fusion/StakeHub.sol index 65a93558..374217e1 100644 --- a/contracts/BC_fusion/StakeHub.sol +++ b/contracts/BC_fusion/StakeHub.sol @@ -8,6 +8,7 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./System.sol"; import "./lib/Utils.sol"; import "./interface/IBSCValidatorSet.sol"; +import "./interface/ICrossChain.sol"; import "./interface/IGovToken.sol"; import "./interface/IStakeCredit.sol"; @@ -1015,7 +1016,11 @@ contract StakeHub is System, Initializable { function _jailValidator(Validator storage valInfo, uint256 jailUntil) internal { // keep the last eligible validator bool isLast = (numOfJailed >= _validatorSet.length() - 1); - if (isLast) { + // 0x08 is the staking channel id. If this channel is closed, then BC-fusion is finished and we should keep the last eligible validator here + if ( + !ICrossChain(CROSS_CHAIN_CONTRACT_ADDR).registeredContractChannelMap(VALIDATOR_CONTRACT_ADDR, 0x08) + && isLast + ) { emit ValidatorEmptyJailed(valInfo.operatorAddress); return; } diff --git a/contracts/BC_fusion/interface/ICrossChain.sol b/contracts/BC_fusion/interface/ICrossChain.sol new file mode 100644 index 00000000..c6cbf1d2 --- /dev/null +++ b/contracts/BC_fusion/interface/ICrossChain.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.17; + +interface ICrossChain { + function registeredContractChannelMap(address, uint8) external view returns (bool); +} From fca3c57af040d94a8f0089d0ccc538348d14aeee Mon Sep 17 00:00:00 2001 From: Roshan Date: Wed, 3 Jan 2024 15:08:42 +0800 Subject: [PATCH 3/4] fix lint issue --- contracts/BC_fusion/interface/ICrossChain.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BC_fusion/interface/ICrossChain.sol b/contracts/BC_fusion/interface/ICrossChain.sol index c6cbf1d2..8b4767e6 100644 --- a/contracts/BC_fusion/interface/ICrossChain.sol +++ b/contracts/BC_fusion/interface/ICrossChain.sol @@ -2,5 +2,5 @@ pragma solidity 0.8.17; interface ICrossChain { - function registeredContractChannelMap(address, uint8) external view returns (bool); + function registeredContractChannelMap(address, uint8) external view returns (bool); } From 7f022fd98de9c1a8573ccf6f00c2905e502b1b22 Mon Sep 17 00:00:00 2001 From: Roshan Date: Wed, 3 Jan 2024 15:11:43 +0800 Subject: [PATCH 4/4] fix review comments --- contracts/BC_fusion/StakeHub.sol | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contracts/BC_fusion/StakeHub.sol b/contracts/BC_fusion/StakeHub.sol index 374217e1..e5a43aa9 100644 --- a/contracts/BC_fusion/StakeHub.sol +++ b/contracts/BC_fusion/StakeHub.sol @@ -1016,13 +1016,12 @@ contract StakeHub is System, Initializable { function _jailValidator(Validator storage valInfo, uint256 jailUntil) internal { // keep the last eligible validator bool isLast = (numOfJailed >= _validatorSet.length() - 1); - // 0x08 is the staking channel id. If this channel is closed, then BC-fusion is finished and we should keep the last eligible validator here - if ( - !ICrossChain(CROSS_CHAIN_CONTRACT_ADDR).registeredContractChannelMap(VALIDATOR_CONTRACT_ADDR, 0x08) - && isLast - ) { - emit ValidatorEmptyJailed(valInfo.operatorAddress); - return; + if (isLast) { + // 0x08 is the staking channel id. If this channel is closed, then BC-fusion is finished and we should keep the last eligible validator here + if (!ICrossChain(CROSS_CHAIN_CONTRACT_ADDR).registeredContractChannelMap(VALIDATOR_CONTRACT_ADDR, 0x08)) { + emit ValidatorEmptyJailed(valInfo.operatorAddress); + return; + } } if (jailUntil > valInfo.jailUntil) {