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

     1  package validation
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"sync"
     7  
     8  	"github.com/sixexorg/magnetic-ring/common"
     9  	"github.com/sixexorg/magnetic-ring/core/orgchain/types"
    10  	"github.com/sixexorg/magnetic-ring/errors"
    11  	"github.com/sixexorg/magnetic-ring/store/mainchain/account_level"
    12  	"github.com/sixexorg/magnetic-ring/store/mainchain/states"
    13  	"github.com/sixexorg/magnetic-ring/store/mainchain/storages"
    14  )
    15  
    16  //just sub balance
    17  func (s *StateValidate) verifyBonus(oplog *OpLog) (extra []*OpLog, err error) {
    18  	s.M.Lock()
    19  	defer s.M.Unlock()
    20  	{
    21  		if oplog.method == Account_bonus_fee {
    22  			aa := oplog.data.(*OPAddressBigInt)
    23  			err := s.getAccountState(aa.Address)
    24  			if err != nil {
    25  				return nil, err
    26  			}
    27  			amount, bonusHeight, err := calculateReward(s.ledgerStore, aa.Address, s.MemoAccountState[aa.Address].Data.BonusHeight, s.currentBlockHeight)
    28  			if err != nil {
    29  				return nil, err
    30  			}
    31  			if amount.Cmp(aa.Num) == -1 {
    32  				return nil, errors.ERR_STATE_BONUS_NOT_ENOUGH
    33  			}
    34  			amount.Sub(amount, aa.Num)
    35  			ops := analysisBonusAfter(aa.Address, bonusHeight, amount)
    36  			return ops, nil
    37  
    38  		}
    39  		return nil, nil
    40  	}
    41  }
    42  
    43  func (s *StateValidate) calculateReward(account common.Address, bonusLeft uint64) (amount *big.Int, bonusHeight uint64, err error) {
    44  
    45  	bonusLeft = bonusLeft + types.HWidth
    46  	// get account state between bonusHeight+1 and s.targetHeight
    47  	// get headlvs
    48  	// get height level of account
    49  	ass, err := s.ledgerStore.GetAccountRange(bonusLeft, s.currentBlockHeight, account)
    50  	if err != nil {
    51  		return nil, 0, err
    52  	}
    53  	as, _ := s.ledgerStore.GetAccountByHeight(bonusLeft, account)
    54  	if ass.Len() > 0 {
    55  		if as.Height < ass[0].Height {
    56  			ass = append(states.AccountStates{as}, ass...)
    57  		}
    58  	} else {
    59  		ass = states.AccountStates{as}
    60  	}
    61  	assFTree := make([]common.FTreer, 0, len(ass))
    62  	for _, v := range ass {
    63  		assFTree = append(assFTree, v)
    64  	}
    65  
    66  	lvlFTree := s.ledgerStore.GetAccountLvlRange(bonusLeft, s.currentBlockHeight, account)
    67  	lvl := s.ledgerStore.GetAccountLevel(bonusLeft, account)
    68  
    69  	if len(lvlFTree) > 0 {
    70  		if bonusLeft < lvlFTree[0].GetHeight() {
    71  			lvlFTree = append([]common.FTreer{&account_level.HeightLevel{Height: bonusLeft, Lv: lvl}}, lvlFTree...)
    72  		}
    73  	} else {
    74  		lvlFTree = []common.FTreer{&account_level.HeightLevel{Height: bonusLeft, Lv: lvl}}
    75  	}
    76  	hbonus := s.ledgerStore.GetBouns()
    77  	amount, bonusHeight = aggregateBonus(assFTree, lvlFTree, hbonus, bonusLeft, s.currentBlockHeight, types.HWidth)
    78  	return
    79  }
    80  
    81  func aggregateBonus(assFTree, lvlFTree []common.FTreer, hbonus map[uint64][]uint64, start, end, lapWidth uint64) (amount *big.Int, bonusLeft uint64) {
    82  	if start == 0 {
    83  		start += lapWidth
    84  	}
    85  	l := (end-start)/lapWidth + 1
    86  	balances := make([]*big.Int, 0, l)
    87  	levels := make([]account_level.EasyLevel, 0, l)
    88  	wg := new(sync.WaitGroup)
    89  	wg.Add(2)
    90  	go func() {
    91  		//fmt.Println("㊗️ ㊗️ ㊗️ aggregateBonus", start, end, lapWidth, len(assFTree))
    92  		aft := common.NewForwardTree(lapWidth, start, end, assFTree)
    93  		for !aft.Next() {
    94  			balances = append(balances, aft.Val().(*big.Int))
    95  		}
    96  		wg.Done()
    97  	}()
    98  	go func() {
    99  		lft := common.NewForwardTree(lapWidth, start, end, lvlFTree)
   100  		for !lft.Next() {
   101  			levels = append(levels, lft.Val().(account_level.EasyLevel))
   102  		}
   103  		wg.Done()
   104  	}()
   105  	wg.Wait()
   106  	sum := big.NewInt(0)
   107  	sp := big.NewInt(0)
   108  	bonBig := big.NewInt(0)
   109  	/*for k, v := range hbonus {
   110  		fmt.Println("🚫 🚫 🚫 🚫 🚫 🚫 🚫 🚫", k, v, start)
   111  	}*/
   112  
   113  	for k, v := range levels {
   114  		if v > 1 {
   115  			//fmt.Println(start, int(v-1))
   116  			bal := balances[k]
   117  			bon := hbonus[start][int(v)-1]
   118  			sp.Mul(bal, bonBig.SetUint64(bon))
   119  			sum.Add(sum, sp)
   120  		}
   121  		bonusLeft = start
   122  		start += lapWidth
   123  	}
   124  	return sum, bonusLeft
   125  }
   126  func CalculateBonus(ledger *storages.LedgerStoreImp, account common.Address) (amount *big.Int, bonusHeight uint64, err error) {
   127  	as, err := ledger.GetAccountByHeight(ledger.GetCurrentBlockHeight(), account)
   128  	if err != nil {
   129  		return nil, 0, err
   130  	}
   131  	return calculateReward(ledger, account, as.Data.BonusHeight, ledger.GetCurrentBlockHeight())
   132  }
   133  func calculateReward(ledger *storages.LedgerStoreImp, account common.Address, bonusLeft, curHeight uint64) (amount *big.Int, bonusHeight uint64, err error) {
   134  	bonusLeft = bonusLeft + types.HWidth
   135  	// get account state between bonusHeight+1 and s.targetHeight
   136  	// get headlvs
   137  	// get height level of account
   138  	ass, err := ledger.GetAccountRange(bonusLeft, curHeight, account)
   139  	if err != nil {
   140  		return nil, 0, err
   141  	}
   142  	as, _ := ledger.GetAccountByHeight(bonusLeft, account)
   143  	if ass.Len() > 0 {
   144  		if as.Height < ass[0].Height {
   145  			ass = append(states.AccountStates{as}, ass...)
   146  		}
   147  	} else {
   148  		ass = states.AccountStates{as}
   149  	}
   150  	assFTree := make([]common.FTreer, 0, len(ass))
   151  	for _, v := range ass {
   152  		assFTree = append(assFTree, v)
   153  	}
   154  
   155  	lvlFTree := ledger.GetAccountLvlRange(bonusLeft, curHeight, account)
   156  	lvl := ledger.GetAccountLevel(bonusLeft, account)
   157  
   158  	if len(lvlFTree) > 0 {
   159  		if bonusLeft < lvlFTree[0].GetHeight() {
   160  			lvlFTree = append([]common.FTreer{&account_level.HeightLevel{Height: bonusLeft, Lv: lvl}}, lvlFTree...)
   161  		}
   162  	} else {
   163  		lvlFTree = []common.FTreer{&account_level.HeightLevel{Height: bonusLeft, Lv: lvl}}
   164  	}
   165  	hbonus := ledger.GetBouns()
   166  	amount, bonusHeight = aggregateBonus(assFTree, lvlFTree, hbonus, bonusLeft, curHeight, types.HWidth)
   167  	return
   168  }