Skip to content

Commit

Permalink
feat: define turnLength and systemRewardAntiMEVRatio for BEP-341
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanBSC committed Jun 28, 2024
1 parent adc614d commit f9d1a0c
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 24 deletions.
43 changes: 41 additions & 2 deletions abi/bscvalidatorset.abi
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,19 @@
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getTurnLength",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getValidators",
Expand Down Expand Up @@ -1239,7 +1252,20 @@
},
{
"type": "function",
"name": "systemRewardRatio",
"name": "systemRewardAntiMEVRatio",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "systemRewardBaseRatio",
"inputs": [],
"outputs": [
{
Expand All @@ -1263,6 +1289,19 @@
],
"stateMutability": "view"
},
{
"type": "function",
"name": "turnLength",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "updateParam",
Expand Down Expand Up @@ -1684,4 +1723,4 @@
"inputs": [],
"anonymous": false
}
]
]
52 changes: 42 additions & 10 deletions contracts/BSCValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
uint256 public constant INIT_SYSTEM_REWARD_RATIO = 625; // 625/10000 is 1/16
uint256 public constant MAX_SYSTEM_REWARD_BALANCE = 100 ether;

uint256 public systemRewardRatio;
uint256 public systemRewardBaseRatio;
uint256 public previousHeight;
uint256 public previousBalanceOfSystemReward; // deprecated
bytes[] public previousVoteAddrFullSet;
Expand All @@ -95,6 +95,10 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
Validator[] private _tmpMigratedValidatorSet;
bytes[] private _tmpMigratedVoteAddrs;

// BEP-341 Validators can produce consecutive blocks
uint256 public turnLength; // Consecutive number of blocks a validator receives priority for block production
uint256 public systemRewardAntiMEVRatio;

struct Validator {
address consensusAddress;
address payable feeAddress;
Expand Down Expand Up @@ -331,11 +335,16 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
uint256 index = currentValidatorSetMap[valAddr];

if (isSystemRewardIncluded == false) {
systemRewardRatio = INIT_SYSTEM_REWARD_RATIO;
systemRewardBaseRatio = INIT_SYSTEM_REWARD_RATIO;
burnRatio = INIT_BURN_RATIO;
isSystemRewardIncluded = true;
}

uint256 systemRewardRatio = systemRewardBaseRatio;
if (turnLength > 1 && systemRewardAntiMEVRatio > 0) {
systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1);
}

if (value > 0 && systemRewardRatio > 0) {
uint256 toSystemReward = msg.value.mul(systemRewardRatio).div(BLOCK_FEES_RATIO_SCALE);
if (toSystemReward > 0) {
Expand Down Expand Up @@ -697,8 +706,8 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
require(value.length == 32, "length of burnRatio mismatch");
uint256 newBurnRatio = BytesToTypes.bytesToUint256(32, value);
require(
newBurnRatio.add(systemRewardRatio) <= BLOCK_FEES_RATIO_SCALE,
"the burnRatio plus systemRewardRatio must be no greater than 10000"
newBurnRatio.add(systemRewardBaseRatio).add(systemRewardAntiMEVRatio) <= BLOCK_FEES_RATIO_SCALE,
"the burnRatio plus systemRewardBaseRatio and systemRewardAntiMEVRatio must be no greater than 10000"
);
burnRatio = newBurnRatio;
} else if (Memory.compareStrings(key, "maxNumOfMaintaining")) {
Expand Down Expand Up @@ -741,14 +750,30 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
newNumOfCabinets <= MAX_NUM_OF_VALIDATORS, "the numOfCabinets must be less than MAX_NUM_OF_VALIDATORS"
);
numOfCabinets = newNumOfCabinets;
} else if (Memory.compareStrings(key, "systemRewardRatio")) {
require(value.length == 32, "length of systemRewardRatio mismatch");
uint256 newSystemRewardRatio = BytesToTypes.bytesToUint256(32, value);
} else if (Memory.compareStrings(key, "systemRewardBaseRatio")) {
require(value.length == 32, "length of systemRewardBaseRatio mismatch");
uint256 newSystemRewardBaseRatio = BytesToTypes.bytesToUint256(32, value);
require(
newSystemRewardBaseRatio.add(burnRatio).add(systemRewardAntiMEVRatio) <= BLOCK_FEES_RATIO_SCALE,
"the systemRewardBaseRatio plus burnRatio and systemRewardAntiMEVRatio must be no greater than 10000"
);
systemRewardBaseRatio = newSystemRewardBaseRatio;
} else if (Memory.compareStrings(key, "systemRewardAntiMEVRatio")) {
require(value.length == 32, "length of systemRewardAntiMEVRatio mismatch");
uint256 newSystemRewardAntiMEVRatio = BytesToTypes.bytesToUint256(32, value);
require(
newSystemRewardRatio.add(burnRatio) <= BLOCK_FEES_RATIO_SCALE,
"the systemRewardRatio plus burnRatio must be no greater than 10000"
newSystemRewardAntiMEVRatio.add(burnRatio).add(systemRewardBaseRatio) <= BLOCK_FEES_RATIO_SCALE,
"the systemRewardAntiMEVRatio plus burnRatio and systemRewardBaseRatio must be no greater than 10000"
);
systemRewardRatio = newSystemRewardRatio;
systemRewardAntiMEVRatio = newSystemRewardAntiMEVRatio;
} else if (Memory.compareStrings(key, "turnLength")) {
require(value.length == 32, "length of turnLength mismatch");
uint256 newTurnLength = BytesToTypes.bytesToUint256(32, value);
require(
newTurnLength >= 3 && newTurnLength <= 9 || newTurnLength == 1,
"the turnLength should be in [3,9] or equal to 1"
);
turnLength = newTurnLength;
} else {
require(false, "unknown param");
}
Expand Down Expand Up @@ -1047,6 +1072,13 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
return voteAddrs;
}

function getTurnLength() external view returns (uint256) {
if (turnLength == 0) {
return 1;
}
return turnLength;
}

function setPreviousVoteAddrFullSet() private {
uint256 n = previousVoteAddrFullSet.length;
uint256 m = currentVoteAddrFullSet.length;
Expand Down
14 changes: 10 additions & 4 deletions test/SlashIndicator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ contract SlashIndicatorTest is Deployer {

uint256 public burnRatio;
uint256 public burnRatioScale;
uint256 public systemRewardRatio;
uint256 public systemRewardBaseRatio;
uint256 public systemRewardRatioScale;

address public coinbase;
Expand All @@ -19,8 +19,8 @@ contract SlashIndicatorTest is Deployer {
bscValidatorSet.isSystemRewardIncluded() ? bscValidatorSet.burnRatio() : bscValidatorSet.INIT_BURN_RATIO();
burnRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();

systemRewardRatio = bscValidatorSet.isSystemRewardIncluded()
? bscValidatorSet.systemRewardRatio()
systemRewardBaseRatio = bscValidatorSet.isSystemRewardIncluded()
? bscValidatorSet.systemRewardBaseRatio()
: bscValidatorSet.INIT_SYSTEM_REWARD_RATIO();
systemRewardRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();

Expand Down Expand Up @@ -350,7 +350,13 @@ contract SlashIndicatorTest is Deployer {
}

function _calcIncoming(uint256 value) internal view returns (uint256 incoming) {
uint256 toSystemReward = (value * systemRewardRatio) / systemRewardRatioScale;
uint256 turnLength = bscValidatorSet.getTurnLength();
uint256 systemRewardAntiMEVRatio = bscValidatorSet.systemRewardAntiMEVRatio();
uint256 systemRewardRatio = systemRewardBaseRatio;
if (turnLength > 1 && systemRewardAntiMEVRatio > 0) {
systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1);
}
uint256 toSystemReward = (value * systemRewardBaseRatio) / systemRewardRatioScale;
uint256 toBurn = (value * burnRatio) / burnRatioScale;
incoming = value - toSystemReward - toBurn;
}
Expand Down
43 changes: 36 additions & 7 deletions test/ValidatorSet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract ValidatorSetTest is Deployer {
uint256 public burnRatioScale;
uint256 public maxNumOfWorkingCandidates;
uint256 public numOfCabinets;
uint256 public systemRewardRatio;
uint256 public systemRewardBaseRatio;
uint256 public systemRewardRatioScale;

address public coinbase;
Expand All @@ -39,8 +39,8 @@ contract ValidatorSetTest is Deployer {
burnRatio =
bscValidatorSet.isSystemRewardIncluded() ? bscValidatorSet.burnRatio() : bscValidatorSet.INIT_BURN_RATIO();
burnRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();
systemRewardRatio = bscValidatorSet.isSystemRewardIncluded()
? bscValidatorSet.systemRewardRatio()
systemRewardBaseRatio = bscValidatorSet.isSystemRewardIncluded()
? bscValidatorSet.systemRewardBaseRatio()
: bscValidatorSet.INIT_SYSTEM_REWARD_RATIO();
systemRewardRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();
totalInComing = bscValidatorSet.totalInComing();
Expand Down Expand Up @@ -78,17 +78,35 @@ contract ValidatorSetTest is Deployer {
vm.expectRevert("deposit value is zero");
bscValidatorSet.deposit(validator0);

uint256 realAmount = _calcIncoming(amount);
uint256 realAmount0 = _calcIncoming(amount);
vm.expectEmit(true, false, false, true, address(bscValidatorSet));
emit validatorDeposit(validator0, realAmount);
emit validatorDeposit(validator0, realAmount0);
bscValidatorSet.deposit{ value: amount }(validator0);

vm.stopPrank();
assertEq(bscValidatorSet.getTurnLength(), 1);
bytes memory key = "turnLength";
bytes memory value = bytes(hex"0000000000000000000000000000000000000000000000000000000000000005"); // 5
_updateParamByGovHub(key, value, address(bscValidatorSet));
assertEq(bscValidatorSet.getTurnLength(), 5);

key = "systemRewardAntiMEVRatio";
value = bytes(hex"0000000000000000000000000000000000000000000000000000000000000200"); // 512
_updateParamByGovHub(key, value, address(bscValidatorSet));
assertEq(bscValidatorSet.systemRewardAntiMEVRatio(), 512);
vm.startPrank(coinbase);

uint256 realAmount1 = _calcIncoming(amount);
vm.expectEmit(true, false, false, true, address(bscValidatorSet));
emit validatorDeposit(validator0, realAmount1);
bscValidatorSet.deposit{ value: amount }(validator0);

address newAccount = _getNextUserAddress();
vm.expectEmit(true, false, false, true, address(bscValidatorSet));
emit deprecatedDeposit(newAccount, realAmount);
emit deprecatedDeposit(newAccount, realAmount1);
bscValidatorSet.deposit{ value: amount }(newAccount);

assertEq(bscValidatorSet.totalInComing(), totalInComing + realAmount);
assertEq(bscValidatorSet.totalInComing(), totalInComing + realAmount0 + realAmount1);
vm.stopPrank();
}

Expand All @@ -109,6 +127,11 @@ contract ValidatorSetTest is Deployer {
_updateParamByGovHub(key, value, address(bscValidatorSet));
assertEq(bscValidatorSet.maxNumOfCandidates(), 5);
assertEq(bscValidatorSet.maxNumOfWorkingCandidates(), 5);

key = "systemRewardBaseRatio";
value = bytes(hex"0000000000000000000000000000000000000000000000000000000000000400"); // 1024
_updateParamByGovHub(key, value, address(bscValidatorSet));
assertEq(bscValidatorSet.systemRewardBaseRatio(), 1024);
}

function testValidateSetChange() public {
Expand Down Expand Up @@ -284,6 +307,12 @@ contract ValidatorSetTest is Deployer {
}

function _calcIncoming(uint256 value) internal view returns (uint256 incoming) {
uint256 turnLength = bscValidatorSet.getTurnLength();
uint256 systemRewardAntiMEVRatio = bscValidatorSet.systemRewardAntiMEVRatio();
uint256 systemRewardRatio = systemRewardBaseRatio;
if (turnLength > 1 && systemRewardAntiMEVRatio > 0) {
systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1);
}
uint256 toSystemReward = (value * systemRewardRatio) / systemRewardRatioScale;
uint256 toBurn = (value * burnRatio) / burnRatioScale;
incoming = value - toSystemReward - toBurn;
Expand Down
5 changes: 4 additions & 1 deletion test/utils/interface/IBSCValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ interface BSCValidatorSet {
function VALIDATORS_UPDATE_MESSAGE_TYPE() external view returns (uint8);
function VALIDATOR_CONTRACT_ADDR() external view returns (address);
function alreadyInit() external view returns (bool);
function systemRewardAntiMEVRatio() external view returns (uint256);
function bscChainID() external view returns (uint16);
function burnRatio() external view returns (uint256);
function burnRatioInitialized() external view returns (bool);
Expand Down Expand Up @@ -102,12 +103,14 @@ interface BSCValidatorSet {
function getIncoming(address validator) external view returns (uint256);
function getLivingValidators() external view returns (address[] memory, bytes[] memory);
function getMiningValidators() external view returns (address[] memory, bytes[] memory);
function getTurnLength() external view returns (uint256);
function getValidators() external view returns (address[] memory);
function getWorkingValidatorCount() external view returns (uint256 workingValidatorCount);
function handleAckPackage(uint8 channelId, bytes memory msgBytes) external;
function handleFailAckPackage(uint8 channelId, bytes memory msgBytes) external;
function handleSynPackage(uint8, bytes memory msgBytes) external returns (bytes memory responsePayload);
function init() external;
function systemRewardBaseRatio() external view returns (uint256);
function isCurrentValidator(address validator) external view returns (bool);
function isMonitoredForMaliciousVote(bytes memory voteAddr) external view returns (bool);
function isSystemRewardIncluded() external view returns (bool);
Expand All @@ -124,8 +127,8 @@ interface BSCValidatorSet {
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 turnLength() external view returns (uint256);
function updateParam(string memory key, bytes memory value) external;
function updateValidatorSetV2(
address[] memory _consensusAddrs,
Expand Down

0 comments on commit f9d1a0c

Please sign in to comment.