Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[reward] Abstract out block-reward, use rewarder, check result correct #1820

Merged
merged 4 commits into from
Nov 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion consensus/consensus_leader_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestConstructAnnounceMessage(test *testing.T) {
func TestConstructPreparedMessage(test *testing.T) {
leaderPriKey := bls.RandPrivateKey()
leaderPubKey := leaderPriKey.GetPublicKey()
leader := p2p.Peer{IP: "127.0.0.1", Port: "6000", ConsensusPubKey: leaderPubKey}
leader := p2p.Peer{IP: "127.0.0.1", Port: "19999", ConsensusPubKey: leaderPubKey}

validatorPriKey := bls.RandPrivateKey()
validatorPubKey := leaderPriKey.GetPublicKey()
Expand Down
7 changes: 7 additions & 0 deletions consensus/engine/consensus_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/reward"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/params"
Expand Down Expand Up @@ -73,6 +74,12 @@ type Engine interface {
// rules of a particular engine. The changes are executed inline.
Prepare(chain ChainReader, header *block.Header) error

// Rewarder handles the distribution of block rewards
Rewarder() reward.Distributor

// SetRewarder assigns the Distributor used in block reward
SetRewarder(reward.Distributor)

// Finalize runs any post-transaction state modifications (e.g. block rewards)
// and assembles the final block.
// Note: The block header and state database might be updated to reflect any
Expand Down
7 changes: 1 addition & 6 deletions consensus/quorum/one-node-one-vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils"
// "github.com/harmony-one/harmony/staking/effective"
)
Expand All @@ -20,10 +19,6 @@ func (v *uniformVoteWeight) Policy() Policy {
return SuperMajorityVote
}

// func (v *uniformVoteWeight) SetShardIDProvider(p func() (uint32, error)) {
// v.p = p
// }

// IsQuorumAchieved ..
func (v *uniformVoteWeight) IsQuorumAchieved(p Phase) bool {
r := v.SignersCount(p) >= v.QuorumThreshold().Int64()
Expand Down Expand Up @@ -59,7 +54,7 @@ func (v *uniformVoteWeight) ToggleActive(*bls.PublicKey) bool {
func (v *uniformVoteWeight) Award(
// Here hook is the callback which gets the amount the earner is due in just reward
// up to the hook to do side-effects like write the statedb
Pie *big.Int, earners []common2.Address, hook func(earner common.Address, due *big.Int),
Pie *big.Int, earners []common.Address, hook func(earner common.Address, due *big.Int),
) *big.Int {
payout := big.NewInt(0)
last := big.NewInt(0)
Expand Down
2 changes: 1 addition & 1 deletion consensus/quorum/one-node-staked-vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package quorum
import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
)
Expand Down
16 changes: 16 additions & 0 deletions consensus/reward/rewarder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package reward

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
)

// Distributor ..
type Distributor interface {
Award(
Pie *big.Int,
earners []common.Address,
hook func(earner common.Address, due *big.Int),
) (payout *big.Int)
}
19 changes: 16 additions & 3 deletions internal/chain/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/harmony-one/bls/ffi/go/bls"
"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/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/ctxerror"
Expand All @@ -19,10 +20,22 @@ import (
"golang.org/x/crypto/sha3"
)

type engineImpl struct{}
type engineImpl struct {
d reward.Distributor
}

// Engine is an algorithm-agnostic consensus engine.
var Engine = &engineImpl{}
var Engine = &engineImpl{nil}

// Rewarder handles the distribution of block rewards
func (e *engineImpl) Rewarder() reward.Distributor {
return e.d
}

// SetRewarder ..
func (e *engineImpl) SetRewarder(d reward.Distributor) {
e.d = d
}

// SealHash returns the hash of a block prior to it being sealed.
func (e *engineImpl) SealHash(header *block.Header) (hash common.Hash) {
Expand Down Expand Up @@ -156,7 +169,7 @@ func (e *engineImpl) Finalize(
incxs []*types.CXReceiptsProof, stks []*staking.StakingTransaction) (*types.Block, error) {
// Accumulate any block and uncle rewards and commit the final state root
// Header seems complete, assemble into a block and return
if err := AccumulateRewards(chain, state, header); err != nil {
if err := AccumulateRewards(chain, state, header, e.Rewarder()); err != nil {
return nil, ctxerror.New("cannot pay block reward").WithCause(err)
}
header.SetRoot(state.IntermediateRoot(chain.Config().IsS3(header.Epoch())))
Expand Down
53 changes: 36 additions & 17 deletions internal/chain/reward.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@ import (
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/reward"
"github.com/harmony-one/harmony/core/state"
bls2 "github.com/harmony-one/harmony/crypto/bls"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils"
"github.com/pkg/errors"
)

// BlockReward is the block reward, to be split evenly among block signers.
var BlockReward = new(big.Int).Mul(big.NewInt(24), big.NewInt(denominations.One))
var (
// BlockReward is the block reward, to be split evenly among block signers.
BlockReward = new(big.Int).Mul(big.NewInt(24), big.NewInt(denominations.One))
errPayoutNotEqualBlockReward = errors.New("total payout not equal to blockreward")
)

// AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
func AccumulateRewards(
bc engine.ChainReader, state *state.DB, header *block.Header,
bc engine.ChainReader, state *state.DB, header *block.Header, rewarder reward.Distributor,
) error {
blockNum := header.Number().Uint64()
if blockNum == 0 {
Expand Down Expand Up @@ -72,9 +77,9 @@ func AccumulateRewards(
if err := mask.SetMask(header.LastCommitBitmap()); err != nil {
return ctxerror.New("cannot set group sig mask bits").WithCause(err)
}
totalAmount := big.NewInt(0)
var accounts []common.Address
signers := []string{}

accounts := []common.Address{}

for idx, member := range parentCommittee.NodeList {
if signed, err := mask.IndexEnabled(idx); err != nil {
return ctxerror.New("cannot check for committer bit",
Expand All @@ -85,19 +90,33 @@ func AccumulateRewards(
}
}

numAccounts := big.NewInt(int64(len(accounts)))
last := new(big.Int)
for i, account := range accounts {
cur := new(big.Int)
cur.Mul(BlockReward, big.NewInt(int64(i+1))).Div(cur, numAccounts)
diff := new(big.Int).Sub(cur, last)
signers = append(signers, common2.MustAddressToBech32(account))
state.AddBalance(account, diff)
totalAmount = new(big.Int).Add(totalAmount, diff)
last = cur
type t struct {
common.Address
*big.Int
}
signers := []string{}
payable := []t{}

totalAmount := rewarder.Award(
BlockReward, accounts, func(receipient common.Address, amount *big.Int) {
signers = append(signers, common2.MustAddressToBech32(receipient))
payable = append(payable, t{receipient, amount})
})

if totalAmount.Cmp(BlockReward) != 0 {
utils.Logger().Error().
Int64("block-reward", BlockReward.Int64()).
Int64("total-amount-paid-out", totalAmount.Int64()).
Msg("Total paid out was not equal to block-reward")
return errors.Wrapf(errPayoutNotEqualBlockReward, "payout "+totalAmount.String())
}

for i := range payable {
state.AddBalance(payable[i].Address, payable[i].Int)
}

header.Logger(utils.Logger()).Debug().
Str("NumAccounts", numAccounts.String()).
Int("NumAccounts", len(accounts)).
Str("TotalAmount", totalAmount.String()).
Strs("Signers", signers).
Msg("[Block Reward] Successfully paid out block reward")
Expand Down
2 changes: 2 additions & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/harmony-one/harmony/api/service/syncing/downloader"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/consensus/reward"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
Expand Down Expand Up @@ -514,6 +515,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
node.pendingTransactions = make(map[common.Hash]*types.Transaction)
node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
node.Consensus.VerifiedNewBlock = make(chan *types.Block)
chain.Engine.SetRewarder(node.Consensus.Decider.(reward.Distributor))
// the sequence number is the next block number to be added in consensus protocol, which is always one more than current chain header block
node.Consensus.SetBlockNum(blockchain.CurrentBlock().NumberU64() + 1)

Expand Down