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 }