Skip to content

Commit

Permalink
Merge pull request #2 from binance-chain/incomeMismatch
Browse files Browse the repository at this point in the history
[R4R]fix unbonding all validator and total income mismatch
  • Loading branch information
unclezoro authored May 25, 2020
2 parents 8b8f767 + 9de1f53 commit ad7c557
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 106 deletions.
113 changes: 64 additions & 49 deletions contracts/BSCValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,13 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
uint256 index = currentValidatorSetMap[valAddr];
if (index>0){
Validator storage validator = currentValidatorSet[index-1];
validator.incoming += value;
totalInComing += value;
emit validatorDeposit(valAddr,value);
if(validator.jailed){
emit deprecatedDeposit(valAddr,value);
}else{
validator.incoming += value;
totalInComing += value;
emit validatorDeposit(valAddr,value);
}
}else{
// get incoming from deprecated validator;
// will not add it to the `totalInComing`;
Expand Down Expand Up @@ -192,11 +196,47 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
emit failReasonWithStr(errMsg);
return;
}
// do calculate distribution
(address[] memory crossAddrs, uint256[] memory crossAmounts, address[] memory crossRefundAddrs,
address payable[] memory directAddrs, uint256[] memory directAmounts, uint256 crossTotal) = calDistribute();

// do cross chain transfer
//step 1: do calculate distribution, do not make it as an internal function for saving gas.
uint n = currentValidatorSet.length;
uint crossSize;
uint directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directSize ++;
}
}
//cross transfer
address[] memory crossAddrs = new address[](crossSize);
uint256[] memory crossAmounts = new uint256[](crossSize);
uint256[] memory crossIndexes = new uint256[](crossSize);
address[] memory crossRefundAddrs = new address[](crossSize);
uint256 crossTotal;
// direct transfer
address payable[] memory directAddrs = new address payable[](directSize);
uint256[] memory directAmounts = new uint256[](directSize);
delete crossSize;
delete directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
uint256 value = currentValidatorSet[i].incoming - currentValidatorSet[i].incoming % PRECISION;
crossAmounts[crossSize] = value-extraFee;
crossRefundAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
crossIndexes[crossSize] = i;
crossTotal += value;
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directAddrs[directSize] = currentValidatorSet[i].feeAddress;
directAmounts[directSize] = currentValidatorSet[i].incoming;
directSize ++;
}
}

//step 2: do cross chain transfer
bool failCross = false;
if(crossTotal > 0){
uint256 relayFee = crossAddrs.length*extraFee;
try ITokenHub(TOKEN_HUB_ADDR).batchTransferOut{value:crossTotal}(crossAddrs, crossAmounts, crossRefundAddrs, address(0x0), block.timestamp + expireTimeSecondGap, relayFee) returns (bool success) {
Expand All @@ -206,12 +246,27 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
emit batchTransferFailed(crossTotal, "batch transfer return false");
}
}catch Error(string memory reason) {
failCross = true;
emit batchTransferFailed(crossTotal, reason);
} catch (bytes memory lowLevelData) {
}catch (bytes memory lowLevelData) {
failCross = true;
emit batchTransferLowerFailed(crossTotal, lowLevelData);
}
}

if(failCross){
for(uint i = 0; i< crossIndexes.length;i++){
uint idx = crossIndexes[i];
bool success = currentValidatorSet[idx].feeAddress.send(currentValidatorSet[idx].incoming);
if (success){
emit directTransfer(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming);
}else{
emit directTransferFail(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming);
}
}
}


if(directAddrs.length>0){
for(uint i = 0;i<directAddrs.length;i++){
bool success = directAddrs[i].send(directAmounts[i]);
Expand All @@ -229,7 +284,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
address payable systemPayable = address(uint160(SYSTEM_REWARD_ADDR));
systemPayable.transfer(address(this).balance);
}

totalInComing = 0;
// do update state
if(validatorSet.length>0){
doUpdateState(validatorSet);
Expand Down Expand Up @@ -375,47 +430,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
return (validatorSet,true,"");
}

function calDistribute() private view enoughInComing returns (address[] memory, uint256[] memory,
address[] memory, address payable[]memory, uint256[] memory, uint256){
uint n = currentValidatorSet.length;
uint crossSize;
uint directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directSize ++;
}
}
//cross transfer
address[] memory crossAddrs = new address[](crossSize);
uint256[] memory crossAmounts = new uint256[](crossSize);
address[] memory crossRefundAddrs = new address[](crossSize);
uint256 crossTotal;
// direct transfer
address payable[] memory directAddrs = new address payable[](directSize);
uint256[] memory directAmounts = new uint256[](directSize);
delete crossSize;
delete directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
uint256 value = currentValidatorSet[i].incoming - currentValidatorSet[i].incoming % PRECISION;
crossAmounts[crossSize] = value-extraFee;
crossRefundAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
crossTotal += value;
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directAddrs[directSize] = currentValidatorSet[i].feeAddress;
directAmounts[directSize] = currentValidatorSet[i].incoming;
directSize ++;
}
}
return (crossAddrs, crossAmounts, crossRefundAddrs, directAddrs, directAmounts, crossTotal);
}

function doUpdateState(Validator[] memory validatorSet) private{
totalInComing = 0;
uint n = currentValidatorSet.length;
uint m = validatorSet.length;

Expand Down
113 changes: 64 additions & 49 deletions contracts/BSCValidatorSet.template
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,13 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
uint256 index = currentValidatorSetMap[valAddr];
if (index>0){
Validator storage validator = currentValidatorSet[index-1];
validator.incoming += value;
totalInComing += value;
emit validatorDeposit(valAddr,value);
if(validator.jailed){
emit deprecatedDeposit(valAddr,value);
}else{
validator.incoming += value;
totalInComing += value;
emit validatorDeposit(valAddr,value);
}
}else{
// get incoming from deprecated validator;
// will not add it to the `totalInComing`;
Expand Down Expand Up @@ -193,11 +197,47 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
emit failReasonWithStr(errMsg);
return;
}
// do calculate distribution
(address[] memory crossAddrs, uint256[] memory crossAmounts, address[] memory crossRefundAddrs,
address payable[] memory directAddrs, uint256[] memory directAmounts, uint256 crossTotal) = calDistribute();

// do cross chain transfer
//step 1: do calculate distribution, do not make it as an internal function for saving gas.
uint n = currentValidatorSet.length;
uint crossSize;
uint directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directSize ++;
}
}
//cross transfer
address[] memory crossAddrs = new address[](crossSize);
uint256[] memory crossAmounts = new uint256[](crossSize);
uint256[] memory crossIndexes = new uint256[](crossSize);
address[] memory crossRefundAddrs = new address[](crossSize);
uint256 crossTotal;
// direct transfer
address payable[] memory directAddrs = new address payable[](directSize);
uint256[] memory directAmounts = new uint256[](directSize);
delete crossSize;
delete directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
uint256 value = currentValidatorSet[i].incoming - currentValidatorSet[i].incoming % PRECISION;
crossAmounts[crossSize] = value-extraFee;
crossRefundAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
crossIndexes[crossSize] = i;
crossTotal += value;
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directAddrs[directSize] = currentValidatorSet[i].feeAddress;
directAmounts[directSize] = currentValidatorSet[i].incoming;
directSize ++;
}
}

//step 2: do cross chain transfer
bool failCross = false;
if(crossTotal > 0){
uint256 relayFee = crossAddrs.length*extraFee;
try ITokenHub(TOKEN_HUB_ADDR).batchTransferOut{value:crossTotal}(crossAddrs, crossAmounts, crossRefundAddrs, address(0x0), block.timestamp + expireTimeSecondGap, relayFee) returns (bool success) {
Expand All @@ -207,12 +247,27 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
emit batchTransferFailed(crossTotal, "batch transfer return false");
}
}catch Error(string memory reason) {
failCross = true;
emit batchTransferFailed(crossTotal, reason);
} catch (bytes memory lowLevelData) {
}catch (bytes memory lowLevelData) {
failCross = true;
emit batchTransferLowerFailed(crossTotal, lowLevelData);
}
}

if(failCross){
for(uint i = 0; i< crossIndexes.length;i++){
uint idx = crossIndexes[i];
bool success = currentValidatorSet[idx].feeAddress.send(currentValidatorSet[idx].incoming);
if (success){
emit directTransfer(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming);
}else{
emit directTransferFail(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming);
}
}
}


if(directAddrs.length>0){
for(uint i = 0;i<directAddrs.length;i++){
bool success = directAddrs[i].send(directAmounts[i]);
Expand All @@ -230,7 +285,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
address payable systemPayable = address(uint160(SYSTEM_REWARD_ADDR));
systemPayable.transfer(address(this).balance);
}

totalInComing = 0;
// do update state
if(validatorSet.length>0){
doUpdateState(validatorSet);
Expand Down Expand Up @@ -385,47 +440,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber {
return (validatorSet,true,"");
}

function calDistribute() private view enoughInComing returns (address[] memory, uint256[] memory,
address[] memory, address payable[]memory, uint256[] memory, uint256){
uint n = currentValidatorSet.length;
uint crossSize;
uint directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directSize ++;
}
}
//cross transfer
address[] memory crossAddrs = new address[](crossSize);
uint256[] memory crossAmounts = new uint256[](crossSize);
address[] memory crossRefundAddrs = new address[](crossSize);
uint256 crossTotal;
// direct transfer
address payable[] memory directAddrs = new address payable[](directSize);
uint256[] memory directAmounts = new uint256[](directSize);
delete crossSize;
delete directSize;
for(uint i = 0;i<n;i++){
if(currentValidatorSet[i].incoming >= DUSTY_INCOMING){
crossAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
uint256 value = currentValidatorSet[i].incoming - currentValidatorSet[i].incoming % PRECISION;
crossAmounts[crossSize] = value-extraFee;
crossRefundAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
crossTotal += value;
crossSize ++;
}else if (currentValidatorSet[i].incoming > 0){
directAddrs[directSize] = currentValidatorSet[i].feeAddress;
directAmounts[directSize] = currentValidatorSet[i].incoming;
directSize ++;
}
}
return (crossAddrs, crossAmounts, crossRefundAddrs, directAddrs, directAmounts, crossTotal);
}

function doUpdateState(Validator[] memory validatorSet) private{
totalInComing = 0;
uint n = currentValidatorSet.length;
uint m = validatorSet.length;

Expand Down
5 changes: 5 additions & 0 deletions generate-genesis.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ Promise.all([
"relayerIncentivize",
"contracts/RelayerIncentivize.sol",
"RelayerIncentivize"
),
compileContract(
"govHub",
"contracts/GovHub.sol",
"GovHub"
)
]).then(result => {

Expand Down
4 changes: 4 additions & 0 deletions genesis-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
"0x0000000000000000000000000000000000001006": {
"balance": "0x0",
"code": "0x{{relayerHub}}"
},
"0x0000000000000000000000000000000000001007": {
"balance": "0x0",
"code": "0x{{govHub}}"
}{% for v in initHolders %},
"{{ v.address.replace('0x', '') }}": {
"balance": "0x{{ v.balance }}"
Expand Down
6 changes: 5 additions & 1 deletion genesis.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions test/BSCValidatorSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,12 @@ contract('BSCValidatorSet', (accounts) => {
let validatorEBalance = await web3.eth.getBalance(validatorE);
let deprecatedBalance = await web3.eth.getBalance(deprecated);

assert.equal(validatorABalance,0);
assert.equal(validatorBBalance,web3.utils.toBN(1e16));
assert.equal(validatorCBalance,0);
assert.equal(validatorDBalance,0);
assert.equal(validatorEBalance,0);
assert.equal(deprecatedBalance,0);
assert.equal(validatorABalance, 0);
assert.equal(validatorBBalance, web3.utils.toBN(1e16));
assert.equal(validatorCBalance, web3.utils.toBN(1e17));
assert.equal(validatorDBalance, web3.utils.toBN(1e18));
assert.equal(validatorEBalance, web3.utils.toBN(1e18).add(web3.utils.toBN(1e5)));
assert.equal(deprecatedBalance, 0);

truffleAssert.eventEmitted(tx, "validatorSetUpdated");
truffleAssert.eventEmitted(tx, "batchTransferFailed",(ev) => {
Expand All @@ -444,7 +444,7 @@ contract('BSCValidatorSet', (accounts) => {
return ev.amount.toString() === web3.utils.toBN(1e16).toString();
});
truffleAssert.eventEmitted(tx, "systemTransfer",(ev) => {
return ev.amount.toString() === web3.utils.toBN(31e17).add(web3.utils.toBN(1e5)).add(web3.utils.toBN(1e16)).toString();
return ev.amount.toString() === web3.utils.toBN(1e18).add(web3.utils.toBN(1e16)).toString();
});
});
});
Expand Down

0 comments on commit ad7c557

Please sign in to comment.