The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/internal/chain/reward.go

271 lines
7.7 KiB

package chain
import (
"math/big"
"sort"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/reward"
"github.com/harmony-one/harmony/consensus/votepower"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
[availability] Implement inactive toggle for validators that miss threshold of signing required; (66%) of epoch (#2077) * [availability] Add function setting Validator as Inactive=true if meets threshold * [availability] Set Validators that did not meet signing threshold to inactive * [availability] Wrap Setting invalid validator only if new epoch forthcoming * [availability] Return right error value * [staking] Add Active field to EditValidator staking txn * [availability] Add validator snapshot type, thread throughout codebase * [availability] Adjust check availability on a per epoch basis * [availability] Address PR comments, simplify collection of validators * [availability] Fold ValidatorSnapshot into ValidatorWrapper * [blockchain] Move update of validator list to after availability removal of validator * [availability] Move availability signing counts to Wrapper, out of Stats * [availability] Record epoch on each validator update as well * [availability] Remove update validator stats in writeblockwithstate, update validator signing in proposal of new block to get correct state written * [availability] Mutate state for validators signing in finalize * [availability] Set unavailable validators in finalize * [consensus] Remove error level for non-error log * [node] No point to broadcast crosslink if we are not in cross link time yet * [availability] Remove moved blocksigners function * [core] Give more context in failure * [availability] Provide set as filter for which validators to track on signing increase and set inactivity * [blockchain] Write snapshot of validator as is * Fix format in staking transaction (#2127) * [availability] Move increment of validator signing counter to before shard state proposal * [availability] Kick out inactive validators right before new shard state proposal * [availability] Keep logic of getting shard members as was * [state-transition] Attach Epoch number to create validator txn Co-authored-by: flicker-harmony <52401354+flicker-harmony@users.noreply.github.com>
5 years ago
"github.com/harmony-one/harmony/staking/availability"
"github.com/harmony-one/harmony/staking/network"
"github.com/pkg/errors"
)
func ballotResultBeaconchain(
bc engine.ChainReader, header *block.Header,
) (shard.SlotList, shard.SlotList, shard.SlotList, error) {
[availability] Implement inactive toggle for validators that miss threshold of signing required; (66%) of epoch (#2077) * [availability] Add function setting Validator as Inactive=true if meets threshold * [availability] Set Validators that did not meet signing threshold to inactive * [availability] Wrap Setting invalid validator only if new epoch forthcoming * [availability] Return right error value * [staking] Add Active field to EditValidator staking txn * [availability] Add validator snapshot type, thread throughout codebase * [availability] Adjust check availability on a per epoch basis * [availability] Address PR comments, simplify collection of validators * [availability] Fold ValidatorSnapshot into ValidatorWrapper * [blockchain] Move update of validator list to after availability removal of validator * [availability] Move availability signing counts to Wrapper, out of Stats * [availability] Record epoch on each validator update as well * [availability] Remove update validator stats in writeblockwithstate, update validator signing in proposal of new block to get correct state written * [availability] Mutate state for validators signing in finalize * [availability] Set unavailable validators in finalize * [consensus] Remove error level for non-error log * [node] No point to broadcast crosslink if we are not in cross link time yet * [availability] Remove moved blocksigners function * [core] Give more context in failure * [availability] Provide set as filter for which validators to track on signing increase and set inactivity * [blockchain] Write snapshot of validator as is * Fix format in staking transaction (#2127) * [availability] Move increment of validator signing counter to before shard state proposal * [availability] Kick out inactive validators right before new shard state proposal * [availability] Keep logic of getting shard members as was * [state-transition] Attach Epoch number to create validator txn Co-authored-by: flicker-harmony <52401354+flicker-harmony@users.noreply.github.com>
5 years ago
return availability.BallotResult(bc, header, shard.BeaconChainShardID)
}
// AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward
func AccumulateRewards(
bc engine.ChainReader, state *state.DB, header *block.Header,
[slash][consensus] Notice double sign & broadcast, factor out tech debt of consensus (#2152) * [slash] Remove dead interface, associated piping * [slash] Expand out structs * [consensus] Write to a chan when find a case of double-signing, remove dead code * [slash] Broadcast the noticing of a double signing * [rawdb] CRUD for slashing candidates * [slashing][node][proto] Broadcast the slash record after receive from consensus, handle received proto message, persist in off-chain db while pending * [slash][node][propose-block] Add verified slashes proposed into the header in block proposal * [slash][shard] Factor out external validator as method on shard state, add double-signature field * [slash][engine] Apply slash, name boolean expression for sorts, use stable sort * [slash] Abstract Ballot results so keep track of both pre and post double sign event * [slash] Fix type errors on test code * [slash] Read from correct rawdb * [slash] Add epoch based guards in CRUD of slashing * [slash] Write to correct cache for slashing candidates * [shard] Use explicit named type of BLS Signature, use convention * [slash] Fix mistake done in refactor, improper header used. Factor out fromSlice to set * [slash][node] Restore newblock to master, try again minimial change * [cx-receipts] Break up one-liner, use SliceStable, not Slice * [network] Finish refactor that makes network message headers once * [network] Simplify creation further of headers write * [slash] Adjust data structure of slash after offline discussion with RJ, Chao * [slash] Still did need signature of the double signature * [consensus] Prepare message does not have block header * [consensus] Soft reset three files to 968517d~1 * [consensus] Begin factor consensus network intended message out with prepare first * [consensus] Factor out Prepared message * [consensus] Factor out announce message creation * [consensus] Committed Message, branch on verify sender key for clearer log * [consensus] Committed Message Factor out * [consensus] Do jenkins MVP of signatures adjustment * [main][slash] Provide YAML config as webhook config for double sign event * [consensus] Adjust signatures, whitespace, lessen GC pressure * [consensus] Remove dead code * [consensus] Factor out commit overloaded message, give commit payload override in construct * [consensus] Fix travis tests * [consensus] Provide block bytes in SubmitVote(quorum.Commit) * [consensus] Factor out noisy sanity checks in BFT, move existing commit check earlier as was before * [quorum] Adjust signatures in quorum * [staking] Adjust after merge from master * [consensus] Finish refactor of consensus * [node] Fix import * [consensus] Fix travis * [consensus] Use origin/master copy of block, fix mistake of pointer to empty byte * [consensus] Less verbose bools * [consensus] Remove unused trailing mutation hook in message construct * [consensus] Address some TODOs on err, comment out double sign
5 years ago
rewarder reward.Distributor, beaconChain engine.ChainReader,
) (*big.Int, error) {
blockNum := header.Number().Uint64()
if blockNum == 0 {
// genesis block has no parent to reward.
return network.NoReward, nil
}
if bc.Config().IsStaking(header.Epoch()) &&
bc.CurrentHeader().ShardID() != shard.BeaconChainShardID {
return network.NoReward, nil
}
// After staking
if bc.Config().IsStaking(header.Epoch()) &&
bc.CurrentHeader().ShardID() == shard.BeaconChainShardID {
defaultReward := network.BaseStakedReward
// TODO Use cached result in off-chain db instead of full computation
_, percentageStaked, err := network.WhatPercentStakedNow(
beaconChain, header.Time().Int64(),
)
if err != nil {
return network.NoReward, err
}
howMuchOff, adjustBy := network.Adjustment(*percentageStaked)
defaultReward = defaultReward.Add(adjustBy)
utils.Logger().Info().
Str("percentage-token-staked", percentageStaked.String()).
Str("how-much-off", howMuchOff.String()).
Str("adjusting-by", adjustBy.String()).
Str("block-reward", defaultReward.String()).
Msg("dynamic adjustment of block-reward ")
// If too much is staked, then possible to have negative reward,
// not an error, just a possible economic situation, hence we return
if defaultReward.IsNegative() {
return network.NoReward, nil
}
newRewards := big.NewInt(0)
// Take care of my own beacon chain committee, _ is missing, for slashing
members, payable, missing, err := ballotResultBeaconchain(beaconChain, header)
if err != nil {
return network.NoReward, err
}
if err := availability.IncrementValidatorSigningCounts(
beaconChain,
shard.Committee{shard.BeaconChainShardID, members}.StakedValidators(),
state,
payable,
missing,
); err != nil {
return network.NoReward, err
}
votingPower, err := votepower.Compute(members)
if err != nil {
return network.NoReward, err
}
for beaconMember := range payable {
// TODO Give out whatever leftover to the last voter/handle
// what to do about share of those that didn't sign
voter := votingPower.Voters[payable[beaconMember].BlsPublicKey]
if !voter.IsHarmonyNode {
snapshot, err := bc.ReadValidatorSnapshot(voter.EarningAccount)
if err != nil {
return network.NoReward, err
}
due := defaultReward.Mul(
voter.EffectivePercent.Quo(votepower.StakersShare),
).RoundInt()
newRewards = new(big.Int).Add(newRewards, due)
if err := state.AddReward(snapshot, due); err != nil {
return network.NoReward, err
}
}
}
// Handle rewards for shardchain
if cxLinks := header.CrossLinks(); len(cxLinks) > 0 {
crossLinks := types.CrossLinks{}
if err := rlp.DecodeBytes(cxLinks, &crossLinks); err != nil {
return network.NoReward, err
}
type slotPayable struct {
payout numeric.Dec
payee common.Address
bucket int
index int
}
allPayables := []slotPayable{}
for i := range crossLinks {
cxLink := crossLinks[i]
if !bc.Config().IsStaking(cxLink.Epoch()) {
continue
}
shardState, err := bc.ReadShardState(cxLink.Epoch())
if err != nil {
return network.NoReward, err
}
subComm := shardState.FindCommitteeByID(cxLink.ShardID())
payableSigners, missing, err := availability.BlockSigners(
cxLink.Bitmap(), subComm,
)
if err != nil {
return network.NoReward, err
}
staked := subComm.StakedValidators()
if err := availability.IncrementValidatorSigningCounts(
beaconChain, staked, state, payableSigners, missing,
); err != nil {
return network.NoReward, err
}
votingPower, err := votepower.Compute(payableSigners)
if err != nil {
return network.NoReward, err
}
for j := range payableSigners {
voter := votingPower.Voters[payableSigners[j].BlsPublicKey]
if !voter.IsHarmonyNode && !voter.EffectivePercent.IsZero() {
due := defaultReward.Mul(
voter.EffectivePercent.Quo(votepower.StakersShare),
)
to := voter.EarningAccount
allPayables = append(allPayables, slotPayable{
payout: due,
payee: to,
bucket: i,
index: j,
})
}
}
}
resultsHandle := make([][]slotPayable, len(crossLinks))
for i := range resultsHandle {
resultsHandle[i] = []slotPayable{}
}
for _, payThem := range allPayables {
bucket := payThem.bucket
resultsHandle[bucket] = append(resultsHandle[bucket], payThem)
}
// Check if any errors and sort each bucket to enforce order
for bucket := range resultsHandle {
sort.SliceStable(resultsHandle[bucket],
func(i, j int) bool {
return resultsHandle[bucket][i].index < resultsHandle[bucket][j].index
},
)
}
// Finally do the pay
for bucket := range resultsHandle {
for payThem := range resultsHandle[bucket] {
snapshot, err := bc.ReadValidatorSnapshot(resultsHandle[bucket][payThem].payee)
if err != nil {
return network.NoReward, err
}
due := resultsHandle[bucket][payThem].payout.TruncateInt()
newRewards = new(big.Int).Add(newRewards, due)
if err := state.AddReward(snapshot, due); err != nil {
return network.NoReward, err
}
}
}
return newRewards, nil
}
return network.NoReward, nil
}
// Before staking
payable := []struct {
string
common.Address
*big.Int
}{}
parentHeader := bc.GetHeaderByHash(header.ParentHash())
if parentHeader.Number().Cmp(common.Big0) == 0 {
// Parent is an epoch block,
// which is not signed in the usual manner therefore rewards nothing.
return network.NoReward, nil
}
[availability] Implement inactive toggle for validators that miss threshold of signing required; (66%) of epoch (#2077) * [availability] Add function setting Validator as Inactive=true if meets threshold * [availability] Set Validators that did not meet signing threshold to inactive * [availability] Wrap Setting invalid validator only if new epoch forthcoming * [availability] Return right error value * [staking] Add Active field to EditValidator staking txn * [availability] Add validator snapshot type, thread throughout codebase * [availability] Adjust check availability on a per epoch basis * [availability] Address PR comments, simplify collection of validators * [availability] Fold ValidatorSnapshot into ValidatorWrapper * [blockchain] Move update of validator list to after availability removal of validator * [availability] Move availability signing counts to Wrapper, out of Stats * [availability] Record epoch on each validator update as well * [availability] Remove update validator stats in writeblockwithstate, update validator signing in proposal of new block to get correct state written * [availability] Mutate state for validators signing in finalize * [availability] Set unavailable validators in finalize * [consensus] Remove error level for non-error log * [node] No point to broadcast crosslink if we are not in cross link time yet * [availability] Remove moved blocksigners function * [core] Give more context in failure * [availability] Provide set as filter for which validators to track on signing increase and set inactivity * [blockchain] Write snapshot of validator as is * Fix format in staking transaction (#2127) * [availability] Move increment of validator signing counter to before shard state proposal * [availability] Kick out inactive validators right before new shard state proposal * [availability] Keep logic of getting shard members as was * [state-transition] Attach Epoch number to create validator txn Co-authored-by: flicker-harmony <52401354+flicker-harmony@users.noreply.github.com>
5 years ago
_, signers, _, err := availability.BallotResult(bc, header, header.ShardID())
if err != nil {
return network.NoReward, err
}
totalAmount := rewarder.Award(
network.BlockReward, signers, func(receipient common.Address, amount *big.Int) {
payable = append(payable, struct {
string
common.Address
*big.Int
}{common2.MustAddressToBech32(receipient), receipient, amount},
)
},
)
if totalAmount.Cmp(network.BlockReward) != 0 {
utils.Logger().Error().
Int64("block-reward", network.BlockReward.Int64()).
Int64("total-amount-paid-out", totalAmount.Int64()).
Msg("Total paid out was not equal to block-reward")
return nil, errors.Wrapf(
network.ErrPayoutNotEqualBlockReward, "payout "+totalAmount.String(),
)
}
for i := range payable {
state.AddBalance(payable[i].Address, payable[i].Int)
}
header.Logger(utils.Logger()).Debug().
Int("NumAccounts", len(payable)).
Str("TotalAmount", totalAmount.String()).
Msg("[Block Reward] Successfully paid out block reward")
return totalAmount, nil
}