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 }