Skip to content

Commit 1934266

Browse files
authored
Merge pull request #562 from NathanBSC/BEP-341-produce-consecutive-blocks
feat: define turnLength and systemRewardAntiMEVRatio for BEP-341
2 parents 5ce49d3 + d451f6d commit 1934266

File tree

5 files changed

+133
-24
lines changed

5 files changed

+133
-24
lines changed

abi/bscvalidatorset.abi

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,19 @@
912912
],
913913
"stateMutability": "view"
914914
},
915+
{
916+
"type": "function",
917+
"name": "getTurnLength",
918+
"inputs": [],
919+
"outputs": [
920+
{
921+
"name": "",
922+
"type": "uint256",
923+
"internalType": "uint256"
924+
}
925+
],
926+
"stateMutability": "view"
927+
},
915928
{
916929
"type": "function",
917930
"name": "getValidators",
@@ -1239,7 +1252,20 @@
12391252
},
12401253
{
12411254
"type": "function",
1242-
"name": "systemRewardRatio",
1255+
"name": "systemRewardAntiMEVRatio",
1256+
"inputs": [],
1257+
"outputs": [
1258+
{
1259+
"name": "",
1260+
"type": "uint256",
1261+
"internalType": "uint256"
1262+
}
1263+
],
1264+
"stateMutability": "view"
1265+
},
1266+
{
1267+
"type": "function",
1268+
"name": "systemRewardBaseRatio",
12431269
"inputs": [],
12441270
"outputs": [
12451271
{
@@ -1263,6 +1289,19 @@
12631289
],
12641290
"stateMutability": "view"
12651291
},
1292+
{
1293+
"type": "function",
1294+
"name": "turnLength",
1295+
"inputs": [],
1296+
"outputs": [
1297+
{
1298+
"name": "",
1299+
"type": "uint256",
1300+
"internalType": "uint256"
1301+
}
1302+
],
1303+
"stateMutability": "view"
1304+
},
12661305
{
12671306
"type": "function",
12681307
"name": "updateParam",
@@ -1684,4 +1723,4 @@
16841723
"inputs": [],
16851724
"anonymous": false
16861725
}
1687-
]
1726+
]

contracts/BSCValidatorSet.sol

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
8484
uint256 public constant INIT_SYSTEM_REWARD_RATIO = 625; // 625/10000 is 1/16
8585
uint256 public constant MAX_SYSTEM_REWARD_BALANCE = 100 ether;
8686

87-
uint256 public systemRewardRatio;
87+
uint256 public systemRewardBaseRatio;
8888
uint256 public previousHeight;
8989
uint256 public previousBalanceOfSystemReward; // deprecated
9090
bytes[] public previousVoteAddrFullSet;
@@ -95,6 +95,10 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
9595
Validator[] private _tmpMigratedValidatorSet;
9696
bytes[] private _tmpMigratedVoteAddrs;
9797

98+
// BEP-341 Validators can produce consecutive blocks
99+
uint256 public turnLength; // Consecutive number of blocks a validator receives priority for block production
100+
uint256 public systemRewardAntiMEVRatio;
101+
98102
struct Validator {
99103
address consensusAddress;
100104
address payable feeAddress;
@@ -331,11 +335,16 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
331335
uint256 index = currentValidatorSetMap[valAddr];
332336

333337
if (isSystemRewardIncluded == false) {
334-
systemRewardRatio = INIT_SYSTEM_REWARD_RATIO;
338+
systemRewardBaseRatio = INIT_SYSTEM_REWARD_RATIO;
335339
burnRatio = INIT_BURN_RATIO;
336340
isSystemRewardIncluded = true;
337341
}
338342

343+
uint256 systemRewardRatio = systemRewardBaseRatio;
344+
if (turnLength > 1 && systemRewardAntiMEVRatio > 0) {
345+
systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1);
346+
}
347+
339348
if (value > 0 && systemRewardRatio > 0) {
340349
uint256 toSystemReward = msg.value.mul(systemRewardRatio).div(BLOCK_FEES_RATIO_SCALE);
341350
if (toSystemReward > 0) {
@@ -697,8 +706,8 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
697706
require(value.length == 32, "length of burnRatio mismatch");
698707
uint256 newBurnRatio = BytesToTypes.bytesToUint256(32, value);
699708
require(
700-
newBurnRatio.add(systemRewardRatio) <= BLOCK_FEES_RATIO_SCALE,
701-
"the burnRatio plus systemRewardRatio must be no greater than 10000"
709+
newBurnRatio.add(systemRewardBaseRatio).add(systemRewardAntiMEVRatio) <= BLOCK_FEES_RATIO_SCALE,
710+
"the burnRatio plus systemRewardBaseRatio and systemRewardAntiMEVRatio must be no greater than 10000"
702711
);
703712
burnRatio = newBurnRatio;
704713
} else if (Memory.compareStrings(key, "maxNumOfMaintaining")) {
@@ -741,14 +750,30 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
741750
newNumOfCabinets <= MAX_NUM_OF_VALIDATORS, "the numOfCabinets must be less than MAX_NUM_OF_VALIDATORS"
742751
);
743752
numOfCabinets = newNumOfCabinets;
744-
} else if (Memory.compareStrings(key, "systemRewardRatio")) {
745-
require(value.length == 32, "length of systemRewardRatio mismatch");
746-
uint256 newSystemRewardRatio = BytesToTypes.bytesToUint256(32, value);
753+
} else if (Memory.compareStrings(key, "systemRewardBaseRatio")) {
754+
require(value.length == 32, "length of systemRewardBaseRatio mismatch");
755+
uint256 newSystemRewardBaseRatio = BytesToTypes.bytesToUint256(32, value);
756+
require(
757+
newSystemRewardBaseRatio.add(burnRatio).add(systemRewardAntiMEVRatio) <= BLOCK_FEES_RATIO_SCALE,
758+
"the systemRewardBaseRatio plus burnRatio and systemRewardAntiMEVRatio must be no greater than 10000"
759+
);
760+
systemRewardBaseRatio = newSystemRewardBaseRatio;
761+
} else if (Memory.compareStrings(key, "systemRewardAntiMEVRatio")) {
762+
require(value.length == 32, "length of systemRewardAntiMEVRatio mismatch");
763+
uint256 newSystemRewardAntiMEVRatio = BytesToTypes.bytesToUint256(32, value);
747764
require(
748-
newSystemRewardRatio.add(burnRatio) <= BLOCK_FEES_RATIO_SCALE,
749-
"the systemRewardRatio plus burnRatio must be no greater than 10000"
765+
newSystemRewardAntiMEVRatio.add(burnRatio).add(systemRewardBaseRatio) <= BLOCK_FEES_RATIO_SCALE,
766+
"the systemRewardAntiMEVRatio plus burnRatio and systemRewardBaseRatio must be no greater than 10000"
750767
);
751-
systemRewardRatio = newSystemRewardRatio;
768+
systemRewardAntiMEVRatio = newSystemRewardAntiMEVRatio;
769+
} else if (Memory.compareStrings(key, "turnLength")) {
770+
require(value.length == 32, "length of turnLength mismatch");
771+
uint256 newTurnLength = BytesToTypes.bytesToUint256(32, value);
772+
require(
773+
newTurnLength >= 3 && newTurnLength <= 9 || newTurnLength == 1,
774+
"the turnLength should be in [3,9] or equal to 1"
775+
);
776+
turnLength = newTurnLength;
752777
} else {
753778
require(false, "unknown param");
754779
}
@@ -1047,6 +1072,13 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
10471072
return voteAddrs;
10481073
}
10491074

1075+
function getTurnLength() external view returns (uint256) {
1076+
if (turnLength == 0) {
1077+
return 1;
1078+
}
1079+
return turnLength;
1080+
}
1081+
10501082
function setPreviousVoteAddrFullSet() private {
10511083
uint256 n = previousVoteAddrFullSet.length;
10521084
uint256 m = currentVoteAddrFullSet.length;

test/SlashIndicator.t.sol

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ contract SlashIndicatorTest is Deployer {
88

99
uint256 public burnRatio;
1010
uint256 public burnRatioScale;
11-
uint256 public systemRewardRatio;
11+
uint256 public systemRewardBaseRatio;
1212
uint256 public systemRewardRatioScale;
1313

1414
address public coinbase;
@@ -20,8 +20,8 @@ contract SlashIndicatorTest is Deployer {
2020
bscValidatorSet.isSystemRewardIncluded() ? bscValidatorSet.burnRatio() : bscValidatorSet.INIT_BURN_RATIO();
2121
burnRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();
2222

23-
systemRewardRatio = bscValidatorSet.isSystemRewardIncluded()
24-
? bscValidatorSet.systemRewardRatio()
23+
systemRewardBaseRatio = bscValidatorSet.isSystemRewardIncluded()
24+
? bscValidatorSet.systemRewardBaseRatio()
2525
: bscValidatorSet.INIT_SYSTEM_REWARD_RATIO();
2626
systemRewardRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();
2727

@@ -434,7 +434,13 @@ contract SlashIndicatorTest is Deployer {
434434
}
435435

436436
function _calcIncoming(uint256 value) internal view returns (uint256 incoming) {
437-
uint256 toSystemReward = (value * systemRewardRatio) / systemRewardRatioScale;
437+
uint256 turnLength = bscValidatorSet.getTurnLength();
438+
uint256 systemRewardAntiMEVRatio = bscValidatorSet.systemRewardAntiMEVRatio();
439+
uint256 systemRewardRatio = systemRewardBaseRatio;
440+
if (turnLength > 1 && systemRewardAntiMEVRatio > 0) {
441+
systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1);
442+
}
443+
uint256 toSystemReward = (value * systemRewardBaseRatio) / systemRewardRatioScale;
438444
uint256 toBurn = (value * burnRatio) / burnRatioScale;
439445
incoming = value - toSystemReward - toBurn;
440446
}

test/ValidatorSet.t.sol

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ contract ValidatorSetTest is Deployer {
2020
uint256 public burnRatioScale;
2121
uint256 public maxNumOfWorkingCandidates;
2222
uint256 public numOfCabinets;
23-
uint256 public systemRewardRatio;
23+
uint256 public systemRewardBaseRatio;
2424
uint256 public systemRewardRatioScale;
2525

2626
address public coinbase;
@@ -39,8 +39,8 @@ contract ValidatorSetTest is Deployer {
3939
burnRatio =
4040
bscValidatorSet.isSystemRewardIncluded() ? bscValidatorSet.burnRatio() : bscValidatorSet.INIT_BURN_RATIO();
4141
burnRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();
42-
systemRewardRatio = bscValidatorSet.isSystemRewardIncluded()
43-
? bscValidatorSet.systemRewardRatio()
42+
systemRewardBaseRatio = bscValidatorSet.isSystemRewardIncluded()
43+
? bscValidatorSet.systemRewardBaseRatio()
4444
: bscValidatorSet.INIT_SYSTEM_REWARD_RATIO();
4545
systemRewardRatioScale = bscValidatorSet.BLOCK_FEES_RATIO_SCALE();
4646
totalInComing = bscValidatorSet.totalInComing();
@@ -78,17 +78,35 @@ contract ValidatorSetTest is Deployer {
7878
vm.expectRevert("deposit value is zero");
7979
bscValidatorSet.deposit(validator0);
8080

81-
uint256 realAmount = _calcIncoming(amount);
81+
uint256 realAmount0 = _calcIncoming(amount);
8282
vm.expectEmit(true, false, false, true, address(bscValidatorSet));
83-
emit validatorDeposit(validator0, realAmount);
83+
emit validatorDeposit(validator0, realAmount0);
84+
bscValidatorSet.deposit{ value: amount }(validator0);
85+
86+
vm.stopPrank();
87+
assertEq(bscValidatorSet.getTurnLength(), 1);
88+
bytes memory key = "turnLength";
89+
bytes memory value = bytes(hex"0000000000000000000000000000000000000000000000000000000000000005"); // 5
90+
_updateParamByGovHub(key, value, address(bscValidatorSet));
91+
assertEq(bscValidatorSet.getTurnLength(), 5);
92+
93+
key = "systemRewardAntiMEVRatio";
94+
value = bytes(hex"0000000000000000000000000000000000000000000000000000000000000200"); // 512
95+
_updateParamByGovHub(key, value, address(bscValidatorSet));
96+
assertEq(bscValidatorSet.systemRewardAntiMEVRatio(), 512);
97+
vm.startPrank(coinbase);
98+
99+
uint256 realAmount1 = _calcIncoming(amount);
100+
vm.expectEmit(true, false, false, true, address(bscValidatorSet));
101+
emit validatorDeposit(validator0, realAmount1);
84102
bscValidatorSet.deposit{ value: amount }(validator0);
85103

86104
address newAccount = _getNextUserAddress();
87105
vm.expectEmit(true, false, false, true, address(bscValidatorSet));
88-
emit deprecatedDeposit(newAccount, realAmount);
106+
emit deprecatedDeposit(newAccount, realAmount1);
89107
bscValidatorSet.deposit{ value: amount }(newAccount);
90108

91-
assertEq(bscValidatorSet.totalInComing(), totalInComing + realAmount);
109+
assertEq(bscValidatorSet.totalInComing(), totalInComing + realAmount0 + realAmount1);
92110
vm.stopPrank();
93111
}
94112

@@ -109,6 +127,11 @@ contract ValidatorSetTest is Deployer {
109127
_updateParamByGovHub(key, value, address(bscValidatorSet));
110128
assertEq(bscValidatorSet.maxNumOfCandidates(), 5);
111129
assertEq(bscValidatorSet.maxNumOfWorkingCandidates(), 5);
130+
131+
key = "systemRewardBaseRatio";
132+
value = bytes(hex"0000000000000000000000000000000000000000000000000000000000000400"); // 1024
133+
_updateParamByGovHub(key, value, address(bscValidatorSet));
134+
assertEq(bscValidatorSet.systemRewardBaseRatio(), 1024);
112135
}
113136

114137
function testValidateSetChange() public {
@@ -284,6 +307,12 @@ contract ValidatorSetTest is Deployer {
284307
}
285308

286309
function _calcIncoming(uint256 value) internal view returns (uint256 incoming) {
310+
uint256 turnLength = bscValidatorSet.getTurnLength();
311+
uint256 systemRewardAntiMEVRatio = bscValidatorSet.systemRewardAntiMEVRatio();
312+
uint256 systemRewardRatio = systemRewardBaseRatio;
313+
if (turnLength > 1 && systemRewardAntiMEVRatio > 0) {
314+
systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1);
315+
}
287316
uint256 toSystemReward = (value * systemRewardRatio) / systemRewardRatioScale;
288317
uint256 toBurn = (value * burnRatio) / burnRatioScale;
289318
incoming = value - toSystemReward - toBurn;

test/utils/interface/IBSCValidatorSet.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ interface BSCValidatorSet {
7575
function VALIDATORS_UPDATE_MESSAGE_TYPE() external view returns (uint8);
7676
function VALIDATOR_CONTRACT_ADDR() external view returns (address);
7777
function alreadyInit() external view returns (bool);
78+
function systemRewardAntiMEVRatio() external view returns (uint256);
7879
function bscChainID() external view returns (uint16);
7980
function burnRatio() external view returns (uint256);
8081
function burnRatioInitialized() external view returns (bool);
@@ -102,12 +103,14 @@ interface BSCValidatorSet {
102103
function getIncoming(address validator) external view returns (uint256);
103104
function getLivingValidators() external view returns (address[] memory, bytes[] memory);
104105
function getMiningValidators() external view returns (address[] memory, bytes[] memory);
106+
function getTurnLength() external view returns (uint256);
105107
function getValidators() external view returns (address[] memory);
106108
function getWorkingValidatorCount() external view returns (uint256 workingValidatorCount);
107109
function handleAckPackage(uint8 channelId, bytes memory msgBytes) external;
108110
function handleFailAckPackage(uint8 channelId, bytes memory msgBytes) external;
109111
function handleSynPackage(uint8, bytes memory msgBytes) external returns (bytes memory responsePayload);
110112
function init() external;
113+
function systemRewardBaseRatio() external view returns (uint256);
111114
function isCurrentValidator(address validator) external view returns (bool);
112115
function isMonitoredForMaliciousVote(bytes memory voteAddr) external view returns (bool);
113116
function isSystemRewardIncluded() external view returns (bool);
@@ -124,8 +127,8 @@ interface BSCValidatorSet {
124127
function previousHeight() external view returns (uint256);
125128
function previousVoteAddrFullSet(uint256) external view returns (bytes memory);
126129
function removeTmpMigratedValidator(address validator) external;
127-
function systemRewardRatio() external view returns (uint256);
128130
function totalInComing() external view returns (uint256);
131+
function turnLength() external view returns (uint256);
129132
function updateParam(string memory key, bytes memory value) external;
130133
function updateValidatorSetV2(
131134
address[] memory _consensusAddrs,

0 commit comments

Comments
 (0)