github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/orgchain/validation/state_validate_bonus.go (about)

     1  package validation
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/sixexorg/magnetic-ring/common"
     7  	"github.com/sixexorg/magnetic-ring/core/orgchain/types"
     8  	"github.com/sixexorg/magnetic-ring/errors"
     9  	"github.com/sixexorg/magnetic-ring/store/orgchain/storages"
    10  	"github.com/sixexorg/magnetic-ring/store/storelaw"
    11  )
    12  
    13  //just sub balance
    14  func (s *StateValidate) verifyBonus(oplog *OpLog) (extra []*OpLog, err error) {
    15  	if oplog.method == Account_bonus_fee {
    16  		aa := oplog.data.(*OPAddressBigInt)
    17  		s.getAccountState(aa.Address)
    18  		amount, bonusHeight, err := calculateReward(s.ledgeror, aa.Address, s.leagueId, s.MemoAccountState[aa.Address].BonusHeight(), s.currentBlockHeight)
    19  		//s.calculateReward(aa.Address, s.MemoAccountState[aa.Address].BonusHeight())
    20  		if err != nil {
    21  			return nil, err
    22  		}
    23  		if amount.Cmp(aa.Num) == -1 {
    24  			return nil, errors.ERR_STATE_BONUS_NOT_ENOUGH
    25  		}
    26  		amount.Sub(amount, aa.Num)
    27  		ops := analysisBonusAfter(aa.Address, bonusHeight, amount)
    28  		return ops, nil
    29  
    30  	}
    31  	return nil, nil
    32  }
    33  
    34  func (s *StateValidate) calculateReward(account common.Address, bonusLeft uint64) (amount *big.Int, bonusHeight uint64, err error) {
    35  	bonusLeft = bonusLeft + types.HWidth
    36  	// get account state between bonusHeight+1 and s.targetHeight
    37  	// get headlvs
    38  	// get height level of account
    39  	ass, err := s.ledgeror.GetAccountRange(bonusLeft, s.currentBlockHeight, account, s.leagueId)
    40  	if err != nil {
    41  		return nil, 0, err
    42  	}
    43  	as, _ := s.ledgeror.GetPrevAccount4V(bonusLeft, account, s.leagueId)
    44  	if ass.Len() > 0 {
    45  		if as.GetHeight() < ass[0].GetHeight() {
    46  			ass = append(storelaw.AccountStaters{as}, ass...)
    47  		}
    48  	} else {
    49  		ass = storelaw.AccountStaters{as}
    50  	}
    51  	assFTree := make([]common.FTreer, 0, len(ass))
    52  	for _, v := range ass {
    53  		assFTree = append(assFTree, v)
    54  	}
    55  	hbonus := s.ledgeror.GetBonus(s.leagueId)
    56  	amount, bonusHeight = aggregateBonus(assFTree, hbonus, bonusLeft, s.currentBlockHeight, types.HWidth)
    57  	return
    58  }
    59  
    60  func aggregateBonus(assFTree []common.FTreer, hbonus map[uint64]uint64, start, end, lapWidth uint64) (amount *big.Int, bonusLeft uint64) {
    61  	if start == 0 {
    62  		start += lapWidth
    63  	}
    64  	l := (end-start)/lapWidth + 1
    65  	balances := make([]*big.Int, 0, l)
    66  	aft := common.NewForwardTree(lapWidth, start, end, assFTree)
    67  	for !aft.Next() {
    68  		balances = append(balances, aft.Val().(*big.Int))
    69  	}
    70  	sum := big.NewInt(0)
    71  	sp := big.NewInt(0)
    72  	for _, v := range balances {
    73  		sp.Mul(v, new(big.Int).SetUint64(hbonus[start]))
    74  		sum.Add(sum, sp)
    75  		bonusLeft = start
    76  		start += lapWidth
    77  		sp.SetUint64(0)
    78  	}
    79  	sum.Div(sum, bigU)
    80  	return sum, bonusLeft
    81  }
    82  func CalculateBonus(ledger *storages.LedgerStoreImp, account, leagueId common.Address) (amount *big.Int, bonusHeight uint64, err error) {
    83  	curHeight := ledger.GetCurrentBlockHeight()
    84  	as, err := ledger.GetPrevAccount4V(curHeight, account, leagueId)
    85  	if err != nil {
    86  		return nil, 0, err
    87  	}
    88  	return calculateReward(ledger, account, leagueId, as.BonusHeight(), curHeight)
    89  }
    90  func calculateReward(ledger storelaw.Ledger4Validation, account, leagueId common.Address, bonusLeft, curHeight uint64) (amount *big.Int, bonusHeight uint64, err error) {
    91  	bonusLeft = bonusLeft + types.HWidth
    92  	// get account state between bonusHeight+1 and s.targetHeight
    93  	// get headlvs
    94  	// get height level of account
    95  	ass, err := ledger.GetAccountRange(bonusLeft, curHeight, account, leagueId)
    96  	if err != nil {
    97  		return nil, 0, err
    98  	}
    99  	as, _ := ledger.GetPrevAccount4V(bonusLeft, account, leagueId)
   100  	if ass.Len() > 0 {
   101  		if as.GetHeight() < ass[0].GetHeight() {
   102  			ass = append(storelaw.AccountStaters{as}, ass...)
   103  		}
   104  	} else {
   105  		ass = storelaw.AccountStaters{as}
   106  	}
   107  	assFTree := make([]common.FTreer, 0, len(ass))
   108  	for _, v := range ass {
   109  		assFTree = append(assFTree, v)
   110  	}
   111  	hbonus := ledger.GetBonus(leagueId)
   112  	amount, bonusHeight = aggregateBonus(assFTree, hbonus, bonusLeft, curHeight, types.HWidth)
   113  	return
   114  }