OSDN Git Service

Alternate nodes assign rewards (#356)
authorwz <mars@bytom.io>
Thu, 25 Jul 2019 09:40:23 +0000 (17:40 +0800)
committerPaladz <yzhu101@uottawa.ca>
Thu, 25 Jul 2019 09:40:23 +0000 (17:40 +0800)
* 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

toolbar/apinode/node_test.go
toolbar/vote_reward/settlementvotereward/settlementreward.go

index 681bf02..4bbae41 100644 (file)
@@ -39,22 +39,22 @@ type args struct {
 
 func TestBuildTxRequest(t *testing.T) {
        cases := []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},
                        },
        }{
                {
                        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},
                        },
                },
                {
                        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 err != nil {
                        t.Fatal(err)
                }
-               if string(tx) != string(c.want) {
+               if _, ok := c.optionWant[string(tx)]; !ok {
                        t.Fatal(i, string(tx))
                }
        }
                        t.Fatal(i, string(tx))
                }
        }
index c367dae..92d37ee 100644 (file)
@@ -14,6 +14,14 @@ import (
        "github.com/vapor/toolbar/vote_reward/config"
 )
 
        "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
 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 {
 
 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 {
                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)
                }
 
                voteResults, err := s.getVoteResultFromDB(height)
@@ -66,10 +81,42 @@ func (s *SettlementReward) Settlement() error {
                s.calcVoterRewards(voteResults, totalReward)
        }
 
                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)
 }
 
        // 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 {
 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 amount.Uint64(), nil
                }
        }
-       return 0, errors.New("No reward found")
+       return 0, errNotFoundReward
 }
 
 func (s *SettlementReward) calcVoterRewards(voteResults []*voteResult, totalReward uint64) {
 }
 
 func (s *SettlementReward) calcVoterRewards(voteResults []*voteResult, totalReward uint64) {