OSDN Git Service

send standby node reward
[bytom/vapor.git] / toolbar / consensusreward / consensusreward.go
1 package consensusreward
2
3 import (
4         "math/big"
5
6         "github.com/vapor/consensus"
7         "github.com/vapor/errors"
8         apinode "github.com/vapor/toolbar/apinode"
9         "github.com/vapor/toolbar/common"
10         "github.com/vapor/toolbar/consensusreward/config"
11 )
12
13 var (
14         errNotStandbyNode = errors.New("No Standby Node")
15         errNotRewardTx    = errors.New("No reward transaction")
16 )
17
18 const standbyNodesRewardForConsensusCycle = 7610350076 // 400000000000000 / (365 * 24 * 60 / (500 * 1200 / 1000 / 60))
19
20 type StandbyNodeReward struct {
21         cfg         *config.Config
22         node        *apinode.Node
23         rewards     map[string]uint64
24         xpubAddress map[string]string
25         startHeight uint64
26         endHeight   uint64
27 }
28
29 func NewStandbyNodeReward(cfg *config.Config, startHeight, endHeight uint64) *StandbyNodeReward {
30         s := &StandbyNodeReward{
31                 cfg:         cfg,
32                 node:        apinode.NewNode(cfg.NodeIP),
33                 rewards:     make(map[string]uint64),
34                 xpubAddress: make(map[string]string),
35                 startHeight: startHeight,
36                 endHeight:   endHeight,
37         }
38         for _, item := range cfg.RewardConf.Node {
39                 s.xpubAddress[item.XPub] = item.Address
40         }
41         return s
42 }
43
44 func (s *StandbyNodeReward) getStandbyNodeReward(height uint64) (map[string]uint64, error) {
45         voteInfos, err := s.node.GetVoteByHeight(height)
46         if err != nil {
47                 return nil, errors.Wrapf(err, "get alternative node reward")
48         }
49         voteInfos = common.CalcStandByNodes(voteInfos)
50         if len(voteInfos) == 0 {
51                 return nil, errNotStandbyNode
52         }
53         totalVoteNum := uint64(0)
54         for _, voteInfo := range voteInfos {
55                 totalVoteNum += voteInfo.VoteNum
56         }
57         total := big.NewInt(0).SetUint64(totalVoteNum)
58         xpubReward := make(map[string]uint64)
59         for _, voteInfo := range voteInfos {
60                 amount := big.NewInt(0).SetUint64(standbyNodesRewardForConsensusCycle)
61                 voteNum := big.NewInt(0).SetUint64(voteInfo.VoteNum)
62                 xpubReward[voteInfo.Vote] = amount.Mul(amount, voteNum).Div(amount, total).Uint64()
63         }
64         return xpubReward, nil
65 }
66
67 func (s *StandbyNodeReward) Settlement() error {
68         if err := s.calcAllReward(); err != nil {
69                 return err
70         }
71         return s.node.BatchSendBTM(s.cfg.RewardConf.AccountID, s.cfg.RewardConf.Password, s.rewards)
72 }
73
74 func (s *StandbyNodeReward) calcAllReward() error {
75         for height := s.startHeight; height <= s.endHeight; height += consensus.ActiveNetParams.RoundVoteBlockNums {
76                 xpubReward, err := s.getStandbyNodeReward(height - consensus.ActiveNetParams.RoundVoteBlockNums)
77                 if err == errNotStandbyNode {
78                         continue
79                 }
80                 if err != nil {
81                         return err
82                 }
83                 for xpub, amount := range xpubReward {
84                         if address, ok := s.xpubAddress[xpub]; ok {
85                                 s.rewards[address] += amount
86                         }
87                 }
88         }
89         if len(s.rewards) == 0 {
90                 return errNotRewardTx
91         }
92         return nil
93 }