github.com/amazechain/amc@v0.1.3/internal/consensus/apos/reward.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package apos 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "github.com/amazechain/amc/common/block" 24 "github.com/amazechain/amc/common/math" 25 "github.com/holiman/uint256" 26 "sort" 27 "strings" 28 29 "github.com/amazechain/amc/common/hexutil" 30 "github.com/amazechain/amc/contracts/deposit" 31 "github.com/amazechain/amc/params" 32 33 "github.com/amazechain/amc/common/types" 34 "github.com/amazechain/amc/log" 35 "github.com/amazechain/amc/modules/rawdb" 36 "github.com/ledgerwatch/erigon-lib/kv" 37 ) 38 39 type RewardResponse struct { 40 Address types.Address `json:"address" yaml:"address"` 41 Data RewardResponseValues `json:"data" yaml:"data"` 42 Total *uint256.Int `json:"total" yaml:"total"` 43 } 44 type RewardResponseValue struct { 45 Value uint256.Int `json:"value" yaml:"value"` 46 Timestamp hexutil.Uint64 `json:"timestamp" yaml:"timestamp"` 47 BlockNumber string `json:"blockNumber" yaml:"blockNumber"` 48 } 49 type RewardResponseValues []*RewardResponseValue 50 51 func (r RewardResponseValues) Len() int { 52 return len(r) 53 } 54 55 func (r RewardResponseValues) Less(i, j int) bool { 56 return r[i].Timestamp < r[j].Timestamp 57 } 58 59 func (r RewardResponseValues) Swap(i, j int) { 60 r[i], r[j] = r[j], r[i] 61 } 62 63 type Reward struct { 64 chainConfig *params.ChainConfig 65 66 ctx context.Context 67 rewardLimit *uint256.Int 68 rewardEpoch *uint256.Int 69 } 70 71 type AccountReward struct { 72 Account types.Address 73 Number *uint256.Int 74 Value *uint256.Int 75 } 76 type AccountRewards []*AccountReward 77 78 func (r AccountRewards) Len() int { 79 return len(r) 80 } 81 82 func (r AccountRewards) Less(i, j int) bool { 83 return strings.Compare(r[i].Account.String(), r[j].Account.String()) > 0 84 } 85 86 func (r AccountRewards) Swap(i, j int) { 87 r[i], r[j] = r[j], r[i] 88 } 89 90 func newReward(chainConfig *params.ChainConfig) *Reward { 91 rewardLimitBig, _ := uint256.FromBig(chainConfig.Apos.RewardLimit) 92 return &Reward{ 93 ctx: context.TODO(), chainConfig: chainConfig, 94 rewardLimit: rewardLimitBig, 95 rewardEpoch: uint256.NewInt(chainConfig.Apos.RewardEpoch), 96 } 97 } 98 99 func (r *Reward) GetRewards(addr types.Address, from *uint256.Int, to *uint256.Int, getBlockByNumber func(*uint256.Int) (block.IBlock, error)) (*RewardResponse, error) { 100 resp := new(RewardResponse) 101 resp.Address = addr 102 resp.Data = make([]*RewardResponseValue, 0) 103 104 if from.Uint64() > to.Uint64() { 105 return nil, errors.New("from > to number") 106 } 107 endEpoch := r.number2epoch(to) 108 startEpoch := r.number2epoch(from) 109 110 resp.Total = uint256.NewInt(0) 111 112 for i := endEpoch; i.Cmp(startEpoch) > 0; i = i.SubUint64(i, 1) { 113 114 blockNr := r.epoch2number(i) 115 blk, err := getBlockByNumber(blockNr) 116 if err != nil { 117 return nil, err 118 } 119 120 for _, reward := range blk.Body().Reward() { 121 if bytes.Compare(reward.Address[:], addr[:]) == 0 { 122 resp.Data = append(resp.Data, &RewardResponseValue{ 123 Value: *reward.Amount, 124 Timestamp: hexutil.Uint64(blk.Header().(*block.Header).Time), 125 BlockNumber: blockNr.String(), 126 }) 127 resp.Total = resp.Total.Add(resp.Total, reward.Amount) 128 } 129 } 130 } 131 sort.Sort(resp.Data) 132 133 return resp, nil 134 } 135 136 func (r *Reward) SetRewards(tx kv.RwTx, number *uint256.Int, setRewards bool) (AccountRewards, error) { 137 currentRewardMap, err := r.buildRewards(tx, number, setRewards) 138 if err != nil { 139 return nil, err 140 } 141 resp := make(AccountRewards, 0, len(currentRewardMap)) 142 for k, v := range currentRewardMap { 143 resp = append(resp, &AccountReward{ 144 Account: k, 145 Value: v, 146 }) 147 } 148 sort.Sort(resp) 149 return resp, nil 150 } 151 152 func (r *Reward) buildRewards(tx kv.RwTx, number *uint256.Int, setRewards bool) (map[types.Address]*uint256.Int, error) { 153 154 endNumber := new(uint256.Int).Sub(number, r.rewardEpoch) 155 156 //calculate last batch but this one 157 currentNr := number.Clone() 158 currentNr.SubUint64(currentNr, 1) 159 rewardMap := make(map[types.Address]*uint256.Int, 0) 160 depositeMap := map[types.Address]*deposit.Info{} 161 162 for currentNr.Cmp(endNumber) >= 0 { 163 // Todo use cache instead ? 164 hash, err := rawdb.ReadCanonicalHash(tx, currentNr.Uint64()) 165 if nil != err { 166 log.Error("cannot open chain db", "err", err) 167 return nil, err 168 } 169 if hash == (types.Hash{}) { 170 return nil, err 171 } 172 header := rawdb.ReadHeader(tx, hash, currentNr.Uint64()) 173 if header == nil { 174 return nil, errors.New("buildreward header type assert error") 175 } 176 177 block := rawdb.ReadBlock(tx, header.Hash(), header.Number.Uint64()) 178 if block == nil { 179 return nil, errors.New("buildreward block type assert error") 180 } 181 182 verifiers := block.Body().Verifier() 183 for _, verifier := range verifiers { 184 depositInfo, ok := depositeMap[verifier.Address] 185 if !ok { 186 depositInfo = deposit.GetDepositInfo(tx, verifier.Address) 187 if depositInfo == nil { 188 continue 189 } 190 depositeMap[verifier.Address] = depositInfo 191 log.Debug("account deposite infos", "addr", verifier.Address, "perblock", depositInfo.RewardPerBlock, "perepoch", depositInfo.MaxRewardPerEpoch) 192 } 193 194 addrReward, ok := rewardMap[verifier.Address] 195 if !ok { 196 addrReward = uint256.NewInt(0) 197 } 198 199 rewardMap[verifier.Address] = math.Min256(addrReward.Add(addrReward, depositInfo.RewardPerBlock), depositInfo.MaxRewardPerEpoch.Clone()) 200 } 201 202 currentNr.SubUint64(currentNr, 1) 203 } 204 205 for addr, amount := range rewardMap { 206 var payAmount, unpayAmount *uint256.Int 207 208 lastSedi, err := r.getAccountRewardUnpaid(tx, addr) 209 if err != nil { 210 log.Debug("build reward Big map get account reward error,err=", err) 211 return nil, err 212 } 213 if lastSedi != nil { 214 amount.Add(amount, lastSedi) 215 } 216 217 if amount.Cmp(r.rewardLimit) >= 0 { 218 payAmount = amount.Clone() 219 unpayAmount = uint256.NewInt(0) 220 } else { 221 payAmount = uint256.NewInt(0) 222 unpayAmount = amount.Clone() 223 } 224 225 rewardMap[addr] = payAmount 226 227 if setRewards { 228 log.Debug("🔨 set account reward unpaid", "addr", addr, "non-pay amount", unpayAmount.Uint64(), "pay amount", payAmount.Uint64(), "number", currentNr.String()) 229 if err := r.setAccountRewardUnpaid(tx, addr, unpayAmount); err != nil { 230 return nil, err 231 } 232 } 233 } 234 235 log.Debug("buildrewards maps", "rewardMap", rewardMap, "rewardmap len", len(rewardMap), "issetreward", setRewards) 236 237 return rewardMap, nil 238 } 239 240 //func (r *Reward) setRewardByEpochPaid(tx kv.RwTx, epoch *uint256.Int, rewardMap map[types.Address]*uint256.Int) error { 241 // if tx == nil { 242 // return errors.New("setrewardepoch tx nil") 243 // } 244 // if len(rewardMap) == 0 { 245 // return nil 246 // } 247 // key := fmt.Sprintf("epoch:%s", epoch.String()) 248 // err := rawdb.PutEpochReward(tx, key, rewardMap) 249 // if err != nil { 250 // return err 251 // } 252 // 253 // return nil 254 //} 255 256 func (r *Reward) getAccountRewardUnpaid(tx kv.Getter, account types.Address) (*uint256.Int, error) { 257 value, err := rawdb.GetAccountReward(tx, account) 258 if err != nil { 259 return uint256.NewInt(0), err 260 } 261 return value, nil 262 } 263 264 func (r *Reward) setAccountRewardUnpaid(tx kv.Putter, account types.Address, val *uint256.Int) error { 265 return rawdb.PutAccountReward(tx, account, val) 266 } 267 268 func (r *Reward) number2epoch(number *uint256.Int) *uint256.Int { 269 beijingBlock, _ := uint256.FromBig(r.chainConfig.BeijingBlock) 270 if beijingBlock.Cmp(number) == 1 { 271 return uint256.NewInt(0) 272 } 273 return new(uint256.Int).Div(new(uint256.Int).Sub(number, beijingBlock), r.rewardEpoch) 274 } 275 276 func (r *Reward) epoch2number(epoch *uint256.Int) *uint256.Int { 277 beijingBlock, _ := uint256.FromBig(r.chainConfig.BeijingBlock) 278 return new(uint256.Int).Add(new(uint256.Int).Mul(epoch, r.rewardEpoch), beijingBlock) 279 }