github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/core/vm/election/reward.go (about)

     1  // Copyright 2019 The go-vnt Authors
     2  // This file is part of the go-vnt library.
     3  //
     4  // The go-vnt library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-vnt library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package election
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/vntchain/go-vnt/common"
    24  	inter "github.com/vntchain/go-vnt/core/vm/interface"
    25  	"github.com/vntchain/go-vnt/log"
    26  )
    27  
    28  type AllLock struct {
    29  	Amount *big.Int // 锁仓和抵押总额
    30  }
    31  
    32  type Reward struct {
    33  	Rest *big.Int // 剩余总激励
    34  }
    35  
    36  func (ec electionContext) depositReward(address common.Address, value *big.Int) error {
    37  	if value.Cmp(common.Big0) <= 0 {
    38  		log.Error("depositReward less than 0 VNT", "address", address.Hex(), "VNT", value.String())
    39  		return fmt.Errorf("deposit reward less than 0 VNT")
    40  	}
    41  
    42  	db := ec.context.GetStateDb()
    43  	// 查询当前剩余Reward
    44  	reward := getReward(db)
    45  
    46  	// 增加当前Reward
    47  	reward.Rest = big.NewInt(0).Add(reward.Rest, value)
    48  
    49  	// 保存当前Reward
    50  	return setReward(db, reward)
    51  }
    52  
    53  // GrantReward 发放激励给该候选节点的受益人,返回错误。
    54  // 发放激励的接口不区分是产块激励还是投票激励,超级节点必须是Active,否则无收益。
    55  // 激励金额不足发放时为正常情况不返回error,返回nil。
    56  // 返回错误时,数据状态恢复到原始情况,即所有激励都不发放。
    57  func GrantReward(stateDB inter.StateDB, rewards map[common.Address]*big.Int, blockNum *big.Int) (err error) {
    58  	// 无激励即可返回
    59  	rest := QueryRestReward(stateDB, blockNum)
    60  	if rest.Cmp(common.Big0) <= 0 {
    61  		return nil
    62  	}
    63  
    64  	// 退出时,如果存在错误,恢复原始状态
    65  	snap := stateDB.Snapshot()
    66  	defer func() {
    67  		if err != nil {
    68  			stateDB.RevertToSnapshot(snap)
    69  		}
    70  	}()
    71  
    72  	for addr, amount := range rewards {
    73  		// 激励不能超过剩余金额
    74  		if rest.Cmp(amount) < 0 {
    75  			amount = rest
    76  		}
    77  		can := GetCandidate(stateDB, addr)
    78  		// 再检查:跳过不存在或未激活的候选人
    79  		if can == nil || !can.Active() {
    80  			log.Warn("Not find candidate or inactive when granting reward", "addr", addr.String())
    81  			continue
    82  		}
    83  		// 发送错误退出
    84  		if err = transfer(stateDB, contractAddr, can.Beneficiary, amount); err != nil {
    85  			return err
    86  		}
    87  		rest = rest.Sub(rest, amount)
    88  		// 发放到无剩余激励
    89  		if rest.Cmp(common.Big0) <= 0 {
    90  			break
    91  		}
    92  	}
    93  
    94  	if  blockNum.Cmp(big.NewInt(ElectionStart)) > 0  {
    95  		return nil
    96  	} else {
    97  		// 激励正常发放完毕,更新剩余激励
    98  		return setReward(stateDB, Reward{Rest: big.NewInt(0).Set(rest)})
    99  	}
   100  }
   101  
   102  // QueryRestReward returns the value of left reward for candidates.
   103  func QueryRestReward(stateDB inter.StateDB, blockNum *big.Int) *big.Int {
   104  	if  blockNum.Cmp(big.NewInt(ElectionStart)) > 0 {
   105  		totalLock, err := getLock(stateDB)
   106  		if err != nil && err != KeyNotExistErr {
   107  			log.Error("QueryRestReward failed", "err", err)
   108  			return common.Big0;
   109  		}
   110  		totalBalance := stateDB.GetBalance(contractAddr)
   111  		if rest := big.NewInt(0).Sub(totalBalance, totalLock.Amount); rest.Cmp(common.Big0) > 0 {
   112  			return rest;
   113  		} else {
   114  			return common.Big0;
   115  		}
   116  	} else {
   117  		reward := getReward(stateDB)
   118  		return reward.Rest
   119  	}
   120  }