From: wz Date: Thu, 25 Jul 2019 09:40:23 +0000 (+0800) Subject: Alternate nodes assign rewards (#356) X-Git-Tag: v1.0.5~74 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=12923c3da59850d60960cda65f14fc8886edcea9;hp=ff266975e6aba0c5a5e1b7f9d56cc322108bab57 Alternate nodes assign rewards (#356) * Alternate nodes assign rewards * modify logic * add pick alternative nodes * remove config * fix * fix * modify test * restore code * fix review * fix review * fix review * fix review * fix unit * fix review --- diff --git a/toolbar/apinode/node_test.go b/toolbar/apinode/node_test.go index 681bf029..4bbae41a 100644 --- a/toolbar/apinode/node_test.go +++ b/toolbar/apinode/node_test.go @@ -39,22 +39,22 @@ type args struct { func TestBuildTxRequest(t *testing.T) { cases := []struct { - args args - want string + args args + optionWant map[string]bool }{ { args: args{ accountID: "9bb77612-350e-4d53-81e2-525b28247ba5", outputs: map[string]uint64{"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf": 100}, }, - want: `{"actions":[{"type":"control_address","address":"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":100},{"type":"spend_account","account_id":"9bb77612-350e-4d53-81e2-525b28247ba5","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":10000100}]}`, + optionWant: map[string]bool{`{"actions":[{"type":"control_address","address":"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":100},{"type":"spend_account","account_id":"9bb77612-350e-4d53-81e2-525b28247ba5","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":10000100}]}`: true}, }, { args: args{ accountID: "9bb77612-350e-4d53-81e2-525b28247ba5", outputs: map[string]uint64{"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf": 100, "sp1qcgtxkhfzytul4lfttwex3skfqhm0tg6ms9da28": 200}, }, - want: `{"actions":[{"type":"control_address","address":"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":100},{"type":"control_address","address":"sp1qcgtxkhfzytul4lfttwex3skfqhm0tg6ms9da28","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":200},{"type":"spend_account","account_id":"9bb77612-350e-4d53-81e2-525b28247ba5","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":10000300}]}`, + optionWant: map[string]bool{`{"actions":[{"type":"control_address","address":"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":100},{"type":"control_address","address":"sp1qcgtxkhfzytul4lfttwex3skfqhm0tg6ms9da28","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":200},{"type":"spend_account","account_id":"9bb77612-350e-4d53-81e2-525b28247ba5","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":10000300}]}`: true, `{"actions":[{"type":"control_address","address":"sp1qcgtxkhfzytul4lfttwex3skfqhm0tg6ms9da28","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":200},{"type":"control_address","address":"sp1qlryy65a5apylphqp6axvhx7nd6y2zlexuvn7gf","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":100},{"type":"spend_account","account_id":"9bb77612-350e-4d53-81e2-525b28247ba5","asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","amount":10000300}]}`: true}, }, } @@ -63,7 +63,7 @@ func TestBuildTxRequest(t *testing.T) { if err != nil { t.Fatal(err) } - if string(tx) != string(c.want) { + if _, ok := c.optionWant[string(tx)]; !ok { t.Fatal(i, string(tx)) } } diff --git a/toolbar/vote_reward/settlementvotereward/settlementreward.go b/toolbar/vote_reward/settlementvotereward/settlementreward.go index c367daeb..92d37eef 100644 --- a/toolbar/vote_reward/settlementvotereward/settlementreward.go +++ b/toolbar/vote_reward/settlementvotereward/settlementreward.go @@ -14,6 +14,14 @@ import ( "github.com/vapor/toolbar/vote_reward/config" ) +var ( + errNotFoundReward = errors.New("No reward found") + errNotStandbyNode = errors.New("No Standby Node") + errNotRewardTx = errors.New("No reward transaction") +) + +const standbyNodesRewardForConsensusCycle = 7610350076 // 400000000000000 / (365 * 24 * 60 / (500 * 1200 / 1000 / 60)) + type voteResult struct { VoteAddress string VoteNum uint64 @@ -52,10 +60,17 @@ func (s *SettlementReward) getVoteResultFromDB(height uint64) (voteResults []*vo func (s *SettlementReward) Settlement() error { for height := s.startHeight + consensus.ActiveNetParams.RoundVoteBlockNums; height <= s.endHeight; height += consensus.ActiveNetParams.RoundVoteBlockNums { - coinbaseHeight := height + 1 - totalReward, err := s.getCoinbaseReward(coinbaseHeight) + totalReward, err := s.getCoinbaseReward(height + 1) + if err == errNotFoundReward { + totalReward, err = s.getStandbyNodeReward(height - consensus.ActiveNetParams.RoundVoteBlockNums) + } + + if err == errNotStandbyNode { + continue + } + if err != nil { - return errors.Wrapf(err, "get total reward at coinbase_height: %d", coinbaseHeight) + return errors.Wrapf(err, "get total reward at height: %d", height) } voteResults, err := s.getVoteResultFromDB(height) @@ -66,10 +81,42 @@ func (s *SettlementReward) Settlement() error { s.calcVoterRewards(voteResults, totalReward) } + if len(s.rewards) == 0 { + return errNotRewardTx + } + // send transactions return s.node.BatchSendBTM(s.rewardCfg.AccountID, s.rewardCfg.Password, s.rewards) } +func (s *SettlementReward) getStandbyNodeReward(height uint64) (uint64, error) { + voteInfos, err := s.node.GetVoteByHeight(height) + if err != nil { + return 0, errors.Wrapf(err, "get alternative node reward") + } + + voteInfos = common.CalcStandByNodes(voteInfos) + + totalVoteNum, xpubVoteNum := uint64(0), uint64(0) + for _, voteInfo := range voteInfos { + totalVoteNum += voteInfo.VoteNum + if s.rewardCfg.XPub == voteInfo.Vote { + xpubVoteNum = voteInfo.VoteNum + } + } + + if xpubVoteNum == 0 { + return 0, errNotStandbyNode + } + + amount := big.NewInt(0).SetUint64(standbyNodesRewardForConsensusCycle) + rewardRatio := big.NewInt(0).SetUint64(s.rewardCfg.RewardRatio) + amount.Mul(amount, rewardRatio).Div(amount, big.NewInt(100)) + total := big.NewInt(0).SetUint64(totalVoteNum) + voteNum := big.NewInt(0).SetUint64(xpubVoteNum) + return amount.Mul(amount, voteNum).Div(amount, total).Uint64(), nil +} + func (s *SettlementReward) getCoinbaseReward(height uint64) (uint64, error) { block, err := s.node.GetBlockByHeight(height) if err != nil { @@ -99,7 +146,7 @@ func (s *SettlementReward) getCoinbaseReward(height uint64) (uint64, error) { return amount.Uint64(), nil } } - return 0, errors.New("No reward found") + return 0, errNotFoundReward } func (s *SettlementReward) calcVoterRewards(voteResults []*voteResult, totalReward uint64) {