OSDN Git Service

modify
authormars <mars@bytom.io>
Thu, 18 Jul 2019 08:59:05 +0000 (16:59 +0800)
committermars <mars@bytom.io>
Thu, 18 Jul 2019 08:59:05 +0000 (16:59 +0800)
toolbar/reward/config/config.go
toolbar/reward/database/dump_reward.sql
toolbar/reward/database/orm/block_state.go
toolbar/reward/reward.go
toolbar/reward/reward/transaction.go
toolbar/reward/reward/vote_reward.go
toolbar/reward/synchron/block_keeper.go

index 23e71ef..fa098a5 100644 (file)
@@ -55,6 +55,7 @@ func DefaultConfig(isVoterReward bool) *Config {
 }
 
 type Chain struct {
+       ChainID     string `json:"chain_id"`
        Name        string `json:"name"`
        Upstream    string `json:"upstream"`
        SyncSeconds uint64 `json:"sync_seconds"`
index 5993867..cba62e8 100644 (file)
@@ -5,7 +5,7 @@ SET FOREIGN_KEY_CHECKS = 0;
 -- Table structure for block_state
 -- ----------------------------
 DROP TABLE IF EXISTS `block_state`;
-CREATE TABLE `block_state`  (
+CREATE TABLE `block_states`  (
   `height` int(11) NOT NULL,
   `block_hash` varchar(64) NOT NULL
 ) ENGINE = InnoDB DEFAULT CHARSET=utf8;
@@ -14,12 +14,12 @@ CREATE TABLE `block_state`  (
 -- Table structure for vote
 -- ----------------------------
 DROP TABLE IF EXISTS `vote`;
-CREATE TABLE `vote`  (
+CREATE TABLE `utxos`  (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `xpub` varchar(128) NOT NULL,
   `voter_address` varchar(62) NOT NULL,
   `vote_height` int(11) NOT NULL,
-  `vote_num` int(11) NOT NULL,
+  `vote_num` bigint(21) NOT NULL,
   `veto_height` int(11) NOT NULL,
   `output_id` varchar(64) NOT NULL,
   PRIMARY KEY (`id`) USING BTREE,
index 6fdd155..d0eecc9 100644 (file)
@@ -1,6 +1,6 @@
 package orm
 
 type BlockState struct {
-       Height    uint64
-       BlockHash string
+       Height    uint64 `json:"height"`
+       BlockHash string `json:"block_hash"`
 }
index eb4c88c..5255010 100644 (file)
@@ -1,8 +1,11 @@
 package reward
 
 import (
+       "time"
+
        "github.com/jinzhu/gorm"
 
+       "github.com/vapor/errors"
        "github.com/vapor/toolbar/reward/config"
        "github.com/vapor/toolbar/reward/database/orm"
        instance "github.com/vapor/toolbar/reward/reward"
@@ -21,12 +24,12 @@ type Reward struct {
        period      uint64
 }
 
-func NewReward(db *gorm.DB, cfg *config.Config, period uint64) *Reward {
+func NewReward(db *gorm.DB, cfg *config.Config, period uint64, quit chan struct{}) *Reward {
        voteInfoCh := make(chan instance.VoteInfo)
        overReadCh := make(chan struct{})
        var countReward CountReward
        if len(cfg.VoteConf) != 0 {
-               countReward = instance.NewVote(cfg.VoteConf, voteInfoCh, overReadCh, period)
+               countReward = instance.NewVote(cfg.VoteConf, voteInfoCh, overReadCh, quit, period)
        } else if cfg.OptionalNodeConf != nil {
                // OptionalNode reward instance
        }
@@ -55,7 +58,22 @@ func (r *Reward) readVoteInfo() error {
 
        minHeight := (1 + 1200*(r.period-1))
        maxHeight := 1200 * r.period
-       rows, err := r.db.Model(&orm.Utxo{}).Select("xpub, voter_address, vote_num, vote_height, veto_height").Where("vote_height BETWEEN ? and ? and xpub in (?)", minHeight, maxHeight, xpubs).Rows()
+
+       ticker := time.NewTicker(time.Duration(r.cfg.Chain.SyncSeconds) * time.Second)
+       for ; true; <-ticker.C {
+               blockState := &orm.BlockState{}
+               if err := r.db.First(blockState).Error; err != nil {
+                       return errors.Wrap(err, "query blockState")
+               }
+               if blockState.Height >= maxHeight {
+                       break
+               }
+
+       }
+
+       //rows, err := r.db.Model(&orm.Utxo{}).Select("xpub, voter_address, vote_num, vote_height, veto_height").Where("vote_height BETWEEN ? and ? and xpub in (?)", minHeight, maxHeight, xpubs).Rows()
+       rows, err := r.db.Model(&orm.Utxo{}).Select("xpub, voter_address, vote_num, vote_height, veto_height").Where("veto_height >= ? and vote_height <= ? and xpub in (?)", minHeight, maxHeight, xpubs).Rows()
+
        if err != nil {
                return err
        }
@@ -74,7 +92,7 @@ func (r *Reward) readVoteInfo() error {
                        return err
                }
 
-               if vetoHeight > 0 && vetoHeight < 1200*r.period {
+               if vetoHeight < 1200*r.period {
                        voteBlockNum = vetoHeight - voteHeight
                } else {
                        voteBlockNum = 1200*r.period - voteHeight
@@ -95,5 +113,5 @@ func (r *Reward) readVoteInfo() error {
 
 func (r *Reward) Start() {
        go r.readVoteInfo()
-       go r.countReward.Start()
+       r.countReward.Start()
 }
index da19446..bf219f3 100644 (file)
@@ -140,3 +140,13 @@ func (t *Transaction) GetCoinbaseTx(blockHeight uint64) (*types.Tx, error) {
 
        return nil, errors.New("no coinbase")
 }
+
+type getBlockCountResp struct {
+       BlockCount uint64 `json:"block_count"`
+}
+
+func (t *Transaction) GetCurrentHeight() (uint64, error) {
+       url := "/get-block-count"
+       res := &getBlockCountResp{}
+       return res.BlockCount, t.request(url, nil, res)
+}
index 4f65b81..6b542fd 100644 (file)
@@ -30,17 +30,19 @@ type Vote struct {
        nodes          []config.VoteRewardConfig
        ch             chan VoteInfo
        overReadCH     chan struct{}
+       quit           chan struct{}
        voteResults    map[string]*voteResult
        voterRewards   map[string]*voterReward
        coinBaseReward map[string]*coinBaseReward
        period         uint64
 }
 
-func NewVote(nodes []config.VoteRewardConfig, ch chan VoteInfo, overReadCH chan struct{}, period uint64) *Vote {
+func NewVote(nodes []config.VoteRewardConfig, ch chan VoteInfo, overReadCH, quit chan struct{}, period uint64) *Vote {
        return &Vote{
                nodes:          nodes,
                ch:             ch,
                overReadCH:     overReadCH,
+               quit:           quit,
                voteResults:    make(map[string]*voteResult),
                voterRewards:   make(map[string]*voterReward),
                coinBaseReward: make(map[string]*coinBaseReward),
@@ -58,7 +60,9 @@ func (v *Vote) Start() {
        v.countReward()
 
        // send transactions
-       v.sendRewardTransaction()
+       if err := v.sendRewardTransaction(); err != nil {
+               panic(err)
+       }
 }
 
 func (v *Vote) getCoinbaseReward() error {
@@ -66,24 +70,37 @@ func (v *Vote) getCoinbaseReward() error {
                tx := Transaction{
                        ip: fmt.Sprintf("http://%s:%d", v.nodes[0].Host, v.nodes[0].Port),
                }
+               for {
+                       h, err := tx.GetCurrentHeight()
+                       if err != nil {
+                               close(v.quit)
+                               return errors.Wrap(err, "get block height")
+                       }
+                       if h >= 1200*v.period {
+                               break
+                       }
+               }
+
                coinbaseTx, err := tx.GetCoinbaseTx(1200 * v.period)
                if err != nil {
+                       close(v.quit)
                        return err
                }
                for _, output := range coinbaseTx.Outputs {
-                       voteOutput, ok := output.TypedOutput.(*types.IntraChainOutput)
+                       output, ok := output.TypedOutput.(*types.IntraChainOutput)
                        if !ok {
+                               close(v.quit)
                                return errors.New("Output type error")
                        }
-                       address := common.GetAddressFromControlProgram(voteOutput.ControlProgram)
+                       address := common.GetAddressFromControlProgram(output.ControlProgram)
                        for _, node := range v.nodes {
                                if address == node.MiningAddress {
                                        reward := &coinBaseReward{
-                                               totalReward: voteOutput.Amount,
+                                               totalReward: output.Amount,
                                        }
                                        ratioNumerator := big.NewInt(int64(node.RewardRatio))
                                        ratioDenominator := big.NewInt(100)
-                                       coinBaseReward := big.NewInt(0).SetUint64(voteOutput.Amount)
+                                       coinBaseReward := big.NewInt(0).SetUint64(output.Amount)
                                        reward.voteTotalReward = coinBaseReward.Mul(coinBaseReward, ratioNumerator).Div(coinBaseReward, ratioDenominator)
                                        v.coinBaseReward[node.XPub] = reward
                                }
@@ -100,10 +117,14 @@ out:
                case voteInfo := <-v.ch:
                        bigBlockNum := big.NewInt(0).SetUint64(voteInfo.VoteBlockNum)
                        bigVoteNum := big.NewInt(0).SetUint64(voteInfo.VoteNum)
-                       bigVoteNum = bigBlockNum.Mul(bigBlockNum, bigVoteNum)
+                       bigVoteNum.Mul(bigVoteNum, bigBlockNum)
 
                        if value, ok := v.voteResults[voteInfo.XPub]; ok {
-                               value.Votes[voteInfo.Address] = bigVoteNum.Add(bigVoteNum, value.Votes[voteInfo.Address])
+                               if vote, ok := value.Votes[voteInfo.Address]; ok {
+                                       vote.Add(vote, bigVoteNum)
+                               } else {
+                                       value.Votes[voteInfo.Address] = bigVoteNum
+                               }
                        } else {
                                voteResult := &voteResult{
                                        Votes:     make(map[string]*big.Int),
@@ -113,8 +134,9 @@ out:
                                voteResult.Votes[voteInfo.Address] = bigVoteNum
                                v.voteResults[voteInfo.XPub] = voteResult
                        }
-
-                       v.voteResults[voteInfo.XPub].VoteTotal = bigVoteNum.Add(bigVoteNum, v.voteResults[voteInfo.XPub].VoteTotal)
+                       voteTotal := v.voteResults[voteInfo.XPub].VoteTotal
+                       voteTotal.Add(voteTotal, bigVoteNum)
+                       v.voteResults[voteInfo.XPub].VoteTotal = voteTotal
                case <-v.overReadCH:
                        break out
                }
@@ -131,12 +153,21 @@ func (v *Vote) countReward() {
 
                for address, vote := range votes.Votes {
                        if value, ok := v.voterRewards[xpub]; ok {
-                               value.rewards[address] = vote.Mul(vote, coinBaseReward.voteTotalReward).Div(vote, votes.VoteTotal)
+                               mul := vote.Mul(vote, coinBaseReward.voteTotalReward)
+                               amount := big.NewInt(0)
+                               amount.Div(mul, votes.VoteTotal)
+
+                               value.rewards[address] = amount
                        } else {
                                reward := &voterReward{
                                        rewards: make(map[string]*big.Int),
                                }
-                               reward.rewards[address] = vote.Mul(vote, coinBaseReward.voteTotalReward).Div(vote, votes.VoteTotal)
+
+                               mul := vote.Mul(vote, coinBaseReward.voteTotalReward)
+                               amount := big.NewInt(0)
+                               amount.Div(mul, votes.VoteTotal)
+
+                               reward.rewards[address] = amount
                                v.voterRewards[xpub] = reward
                        }
                }
@@ -160,7 +191,7 @@ func (v *Vote) sendRewardTransaction() error {
                        log.Info("tx_id: ", txID)
                }
        }
-
+       close(v.quit)
        return nil
 }
 
index 7e74754..2c990fe 100644 (file)
@@ -23,11 +23,33 @@ type ChainKeeper struct {
 }
 
 func NewChainKeeper(db *gorm.DB, cfg *config.Config) *ChainKeeper {
-       return &ChainKeeper{
+
+       keeper := &ChainKeeper{
                cfg:  &cfg.Chain,
                db:   db,
                node: service.NewNode(cfg.Chain.Upstream),
        }
+
+       blockState := &orm.BlockState{}
+       if err := db.First(blockState).Error; err != nil {
+               if err == gorm.ErrRecordNotFound {
+                       blockStr, _, err := keeper.node.GetBlockByHeight(0)
+                       if err != nil {
+                               panic(err)
+                       }
+                       block := &types.Block{}
+                       if err := block.UnmarshalText([]byte(blockStr)); err != nil {
+                               panic(err)
+                       }
+                       if err := keeper.insertBlockState(db, block); err != nil {
+                               panic(err)
+                       }
+               } else {
+                       panic(err)
+               }
+       }
+
+       return keeper
 }
 
 func (c *ChainKeeper) Run() {
@@ -120,7 +142,7 @@ func (c *ChainKeeper) AttachBlock(block *types.Block, txStatus *bc.TransactionSt
                                OutputID:     outputID.String(),
                        }
                        // update data
-                       db := ormDB.Where(utxo).Update("veto_height", block.Height)
+                       db := ormDB.Model(&orm.Utxo{}).Where(utxo).Update("veto_height", block.Height)
                        if err := db.Error; err != nil {
                                ormDB.Rollback()
                                return err
@@ -192,6 +214,18 @@ func (c *ChainKeeper) DetachBlock(block *types.Block, txStatus *bc.TransactionSt
        return ormDB.Commit().Error
 }
 
+func (c *ChainKeeper) insertBlockState(db *gorm.DB, block *types.Block) error {
+       blockHash := block.Hash()
+       blockState := &orm.BlockState{
+               Height:    block.Height,
+               BlockHash: blockHash.String(),
+       }
+       if err := db.Save(blockState).Error; err != nil {
+               return err
+       }
+       return nil
+}
+
 func (c *ChainKeeper) updateBlockState(db *gorm.DB, block *types.Block) error {
        // update blockState
        blockHash := block.Hash()
@@ -200,7 +234,7 @@ func (c *ChainKeeper) updateBlockState(db *gorm.DB, block *types.Block) error {
                BlockHash: blockHash.String(),
        }
 
-       u := db.Updates(blockState)
+       u := db.Model(&orm.BlockState{}).Updates(blockState)
 
        if err := u.Error; err != nil {
                db.Rollback()