Skip to content

Commit

Permalink
Merge pull request poanetwork#48 from SurfingNerd/reward
Browse files Browse the repository at this point in the history
Integrated pool based reward logic
  • Loading branch information
SurfingNerd authored Nov 13, 2020
2 parents 292da04 + 5c91810 commit 6b21638
Show file tree
Hide file tree
Showing 17 changed files with 573 additions and 620 deletions.
5 changes: 4 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
"${workspaceFolder}/node_modules/**/*.js",
"${workspaceFolder}/lib/**/*.js",
"<node_internals>/**/*.js"
]
],
"env": {
"CONTRACTS_NO_UPGRADE_PROXY": "true"
}
},
{
"name": "run stakingTest",
Expand Down
3 changes: 2 additions & 1 deletion contracts/CertifierHbbft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ contract CertifierHbbft is UpgradeableOwned, ICertifier {
address[] calldata _certifiedAddresses,
address _validatorSet
) external {
require(msg.sender == _admin() || tx.origin == _admin() || block.number == 0, "Sender must be admin");
require(msg.sender == _admin() || tx.origin == _admin() || address(0) == _admin() || block.number == 0,
"Sender must be admin");
require(!isInitialized(), "Contract is already initialized");
require(_validatorSet != address(0), "Validatorset must not be 0");
for (uint256 i = 0; i < _certifiedAddresses.length; i++) {
Expand Down
6 changes: 2 additions & 4 deletions contracts/InitializerHbbft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ contract InitializerHbbft {
/// @param _internetAddresses bytes16[] memory
/// @param _parts bytes[] memory
/// @param _acks bytes[][] memory
/// @param _blockReward uint256
constructor(
address[] memory _contracts,
address _owner,
Expand All @@ -52,8 +51,7 @@ contract InitializerHbbft {
bytes32[] memory _publicKeys,
bytes16[] memory _internetAddresses,
bytes[] memory _parts,
bytes[][] memory _acks,
uint256 _blockReward
bytes[][] memory _acks
) public {
IValidatorSetHbbft(_contracts[0]).initialize(
_contracts[1], // _blockRewardContract
Expand All @@ -80,7 +78,7 @@ contract InitializerHbbft {
_parts,
_acks
);
IBlockRewardHbbft(_contracts[1]).initialize(_contracts[0], _blockReward);
IBlockRewardHbbft(_contracts[1]).initialize(_contracts[0]);
address[] memory permittedAddresses = new address[](1);
permittedAddresses[0] = _owner;

Expand Down
2 changes: 1 addition & 1 deletion contracts/KeyGenHistory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ contract KeyGenHistory is UpgradeabilityAdmin, IKeyGenHistory {
bytes[][] memory _acks
) public {
// Unit Tests may deploy at block numbers other than 0.
require(msg.sender == _admin() || tx.origin == _admin() || block.number == 0, "Sender must be admin");
require(msg.sender == _admin() || tx.origin == _admin() || address(0) == _admin() || block.number == 0, "Sender must be admin");
require(!isInitialized(), "initialization can only be done once"); // initialization can only be done once
require(_validators.length != 0, "Validators must be more than 0.");
require(_validators.length == _parts.length, "Wrong number of Parts!");
Expand Down
2 changes: 1 addition & 1 deletion contracts/TxPermissionHbbft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ contract TxPermissionHbbft is UpgradeableOwned, ITxPermission {
address _validatorSet,
address _keyGenHistoryContract
) external {
require(msg.sender == _admin() || tx.origin == _admin() || block.number == 0);
require(msg.sender == _admin() || tx.origin == _admin() || address(0) == _admin() || block.number == 0);
require(!isInitialized(), "initialization can only be done once");
require(_certifier != address(0));
require(_validatorSet != address(0), "ValidatorSet must not be 0");
Expand Down
6 changes: 3 additions & 3 deletions contracts/ValidatorSetHbbft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ contract ValidatorSetHbbft is UpgradeabilityAdmin, IValidatorSetHbbft {
// ============================================== Constants =======================================================

/// @dev The max number of validators.
uint256 public constant MAX_VALIDATORS = 19;
uint256 public constant MAX_VALIDATORS = 25;

// ================================================ Events ========================================================

Expand Down Expand Up @@ -160,8 +160,8 @@ contract ValidatorSetHbbft is UpgradeabilityAdmin, IValidatorSetHbbft {
address[] calldata _initialMiningAddresses,
address[] calldata _initialStakingAddresses
) external {
require(msg.sender == _admin() || tx.origin == _admin() || block.number == 0,
"Initialization only on genesis block or by admin");
require(msg.sender == _admin() || tx.origin == _admin() || address(0) == _admin() || block.number == 0,
"ValidatorSet: Initialization only on genesis block or by admin");
require(!isInitialized(), "ValidatorSet contract is already initialized");
require(_blockRewardContract != address(0), "BlockReward contract address can't be 0x0");
require(_randomContract != address(0), "Random contract address can't be 0x0");
Expand Down
95 changes: 82 additions & 13 deletions contracts/base/BlockRewardHbbftBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {

mapping(address => uint256[]) internal _epochsPoolGotRewardFor;

/// @dev The maximum per-block reward distributed among the validators.
uint256 public maxEpochReward;

/// @dev The reward amount to be distributed in native coins among participants (the validator and their
/// delegators) of the specified pool (mining address) for the specified staking epoch.
mapping(uint256 => mapping(address => uint256)) public epochPoolNativeReward;
Expand All @@ -51,9 +48,37 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {
/// constant by upgrading the contract.
mapping(uint256 => uint256) public validatorMinRewardPercent;

/// @dev the Delta Pool holds all coins that never got emitted, since the maximum supply is 4,380,000
uint256 public deltaPot;

/// @dev each epoch reward, one Fraction of the delta pool gets payed out.
/// the number is the divisor of the fraction. 60 means 1/60 of the delta pool gets payed out.
uint256 public deltaPotPayoutFraction = 60;


/// @dev the reinsertPot holds all coins that are designed for getting reinserted into the coin circulation.
/// sources are:
///
uint256 public reinsertPot;

/// @dev each epoch reward, one Fraction of the reinsert pool gets payed out.
/// the number is the divisor of the fraction. 60 means 1/60 of the reinsert pool gets payed out.
uint256 public reinsertPotPayoutFraction;

/// @dev The address of the `ValidatorSet` contract.
IValidatorSetHbbft public validatorSetContract;

/// @dev parts of the epoch reward get forwarded to a governance fund
/// just a dummy function for now.
address payable public governancePotAddress;

uint256 public governancePotShareNominator;
uint256 public governancePotShareDenominator;

uint256 public constant VALIDATOR_MIN_REWARD_PERCENT = 30; // 30%
uint256 public constant REWARD_PERCENT_MULTIPLIER = 1000000;


// ================================================ Events ========================================================

/// @dev Emitted by the `reward` function.
Expand Down Expand Up @@ -96,14 +121,45 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {
/// @dev Initializes the contract at network startup.
/// Can only be called by the constructor of the `InitializerHbbft` contract or owner.
/// @param _validatorSet The address of the `ValidatorSetHbbft` contract.
function initialize(address _validatorSet, uint256 _maxEpochReward) external {
require(msg.sender == _admin() || tx.origin == _admin() || block.number == 0,
function initialize(address _validatorSet) external {
require(msg.sender == _admin() || tx.origin == _admin() || address(0) == _admin() || block.number == 0,
"Initialization only on genesis block or by admin");
require(!isInitialized(), "initialization can only be done once");
require(_validatorSet != address(0), "ValidatorSet must not be 0");
validatorSetContract = IValidatorSetHbbft(_validatorSet);
maxEpochReward = _maxEpochReward;
validatorMinRewardPercent[0] = VALIDATOR_MIN_REWARD_PERCENT;

deltaPotPayoutFraction = 6000;
reinsertPotPayoutFraction = 6000;
governancePotAddress = 0xDA0da0da0Da0Da0Da0DA00DA0da0da0DA0DA0dA0;
governancePotShareNominator = 1;
governancePotShareDenominator = 10;
}

function addToDeltaPot()
external
payable {
deltaPot += msg.value;
}

function addToReinsertPot()
external
payable {
reinsertPot += msg.value;
}

function setdeltaPotPayoutFraction(uint256 _value)
external
onlyOwner {
require(_value != 0, "Payout fraction must not be 0");
deltaPotPayoutFraction = _value;
}

function setReinsertPotPayoutFraction(uint256 _value)
external
onlyOwner {
require(_value != 0, "Payout fraction must not be 0");
reinsertPotPayoutFraction = _value;
}

/// @dev Called by the engine when producing and closing a block,
Expand Down Expand Up @@ -366,9 +422,6 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {

// ============================================== Internal ========================================================

uint256 internal constant VALIDATOR_MIN_REWARD_PERCENT = 30; // 30%
uint256 internal constant REWARD_PERCENT_MULTIPLIER = 1000000;


/// @dev Distributes rewards among pools at the latest block of a staking epoch.
/// This function is called by the `reward` function.
Expand All @@ -384,11 +437,28 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {
uint256 numValidators = validators.length;
require(numValidators != 0, "Empty Validator list");

uint256 totalReward = maxEpochReward + nativeRewardUndistributed;
uint256 deltaPotShare = deltaPot / deltaPotPayoutFraction;
deltaPot -= deltaPotShare;

// we could reuse the deltaPotShare variable here, to combat the "stack to deep" problem.
uint256 reinsertPotShare = reinsertPot / reinsertPotPayoutFraction;
reinsertPot -= reinsertPotShare;

uint256 totalReward = deltaPotShare + reinsertPotShare + nativeRewardUndistributed;

if (totalReward == 0) {
return 0;
}

// we calculate the governance share here, and store it in the distributeAmount variable.
// the distributedAmount variable is later resused to track all distributed shares
// in order to handle division results in a correct way.
// we can not write clean code here, because of EVMs restriction to use only 16 local variables.
uint256 distributedAmount = totalReward * governancePotShareNominator / governancePotShareDenominator;

governancePotAddress.transfer(distributedAmount);

uint256 rewardToDistribute = totalReward - distributedAmount;

// Indicates whether the validator is entitled to share the rewartds or not.
bool[] memory isRewardedValidator = new bool[](numValidators);
Expand All @@ -402,7 +472,7 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {
) {
isRewardedValidator[i] = true;
numRewardedValidators++;
}
}
}

// No rewards distributed in this epoch
Expand All @@ -411,8 +481,7 @@ contract BlockRewardHbbftBase is UpgradeableOwned, IBlockRewardHbbft {
}

// Share the reward equally among the validators.
uint256 poolReward = totalReward / numRewardedValidators;
uint256 distributedAmount;
uint256 poolReward = rewardToDistribute / numRewardedValidators;

if (poolReward != 0) {
for (uint256 i = 0; i < numValidators; i++) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/base/StakingHbbftBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ contract StakingHbbftBase is UpgradeableOwned, IStakingHbbft {
bytes16[] memory _internetAddresses
)
internal {
require(msg.sender == _admin() || tx.origin == _admin() || block.number == 0,
require(msg.sender == _admin() || tx.origin == _admin() || address(0) == _admin() || block.number == 0,
"Initialization only on genesis block or by admin");
require(!isInitialized(), "Already initialized"); // initialization can only be done once
require(_validatorSetContract != address(0),"ValidatorSet can't be 0");
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IBlockRewardHbbft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ pragma solidity ^0.5.16;


interface IBlockRewardHbbft {
function initialize(address, uint256) external;
function initialize(address) external;
function epochsPoolGotRewardFor(address) external view returns(uint256[] memory);
}
2 changes: 1 addition & 1 deletion contracts/upgradeability/UpgradeabilityAdmin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract UpgradeabilityAdmin {
}
}

// function adminAddress()
// function getAdminAddress()
// public
// view
// returns (address adm) {
Expand Down
Loading

0 comments on commit 6b21638

Please sign in to comment.