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  }