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

     1  package account_level
     2  
     3  import (
     4  	"math/big"
     5  	"sync"
     6  
     7  	"github.com/sixexorg/magnetic-ring/errors"
     8  
     9  	"time"
    10  
    11  	"fmt"
    12  
    13  	"github.com/sixexorg/magnetic-ring/common"
    14  	"github.com/sixexorg/magnetic-ring/store/mainchain/states"
    15  )
    16  
    17  type LvStatistic struct {
    18  	Count  uint32
    19  	Amount *big.Int
    20  }
    21  
    22  func (this *LvStatistic) sub(num *big.Int) {
    23  	this.Amount.Sub(this.Amount, num)
    24  	this.Count--
    25  }
    26  func (this *LvStatistic) add(num *big.Int) {
    27  	this.Amount.Add(this.Amount, num)
    28  	this.Count++
    29  }
    30  
    31  var lmInstance *LevelManager
    32  
    33  type LevelManager struct {
    34  	m      sync.RWMutex
    35  	cycle  uint64
    36  	height uint64
    37  	//number of account, amount distribution
    38  	distribution map[EasyLevel]*LvStatistic
    39  	nextAccLvl   map[common.Address]*LvlAmount
    40  	math         *lvlMath
    41  	//The levels change and need to be persisted to the database
    42  	lvlChange map[common.Address]EasyLevel
    43  
    44  	LevelStore         *LevelStore
    45  	nextHeaderProperty []uint64
    46  }
    47  
    48  func NewLevelManager(cycle int, lapWidth uint64, dbDir string) (*LevelManager, error) {
    49  	db, err := NewLevelStore(dbDir)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	lm := &LevelManager{
    54  		distribution: make(map[EasyLevel]*LvStatistic, 9),
    55  		nextAccLvl:   make(map[common.Address]*LvlAmount),
    56  		lvlChange:    make(map[common.Address]EasyLevel),
    57  		math:         newLvlMath(cycle, lapWidth),
    58  		LevelStore:   db,
    59  	}
    60  
    61  	for i := lv1; i <= lv9; i++ {
    62  		lm.distribution[i] = &LvStatistic{
    63  			Amount: big.NewInt(0),
    64  			Count:  0,
    65  		}
    66  	}
    67  	return lm, nil
    68  }
    69  
    70  func (this *LevelManager) GetNextHeaderProperty(nextHeight uint64) ([]uint64, error) {
    71  	this.m.RLock()
    72  	defer this.m.RUnlock()
    73  	if nextHeight != this.height+1 {
    74  		return nil, errors.ERR_PARAM_NOT_VALID
    75  	}
    76  FLAG:
    77  	if this.nextHeaderProperty == nil {
    78  		time.Sleep(time.Millisecond * 100)
    79  		goto FLAG
    80  	}
    81  	return this.nextHeaderProperty, nil
    82  }
    83  
    84  //ReceiveAccountStates is calculated the account level after the block is saved
    85  func (this *LevelManager) ReceiveAccountStates(ass states.AccountStates, energyUesd *big.Int, height uint64) {
    86  	this.m.Lock()
    87  	defer this.m.Unlock()
    88  	this.height = height
    89  	this.execAccountStates(ass, height)
    90  	this.levelUpL()
    91  	this.generateReward(height, energyUesd)
    92  }
    93  
    94  var (
    95  	zeroBInt = big.NewInt(0)
    96  )
    97  
    98  func (this *LevelManager) execAccountStates(ass states.AccountStates, height uint64) {
    99  	for _, v := range ass {
   100  		fmt.Printf("🤵 ReceiveAccountStates account:%s height:%d balance:%d \n", v.Address.ToString(), v.Height, v.Data.Balance.Uint64())
   101  		/*		if k != 3 {
   102  				continue
   103  			}*/
   104  		if height == 1 {
   105  			if v.Data.Balance.Cmp(lv9_b) != -1 {
   106  				this.genesisLevel9(v.Address, v.Data.Balance)
   107  				continue
   108  			}
   109  		}
   110  		key := v.Address
   111  		amount := v.Data.Balance
   112  		lvline := rankLevel(v.Data.Balance)
   113  		la := this.nextAccLvl[key]
   114  
   115  		// not exists
   116  		if la == nil {
   117  			//no change
   118  			if lvline == lv0 {
   119  				continue
   120  			}
   121  			//achieve lv
   122  			this.levelWillBe(key, lvline, amount)
   123  			continue
   124  		}
   125  		//already exists
   126  		im, l, _, cur := la.Lv.Decode()
   127  		//clear level
   128  		if lvline == 0 {
   129  			this.levelClear(key, cur, la.Amount)
   130  			continue
   131  		}
   132  
   133  		//new account is bigger
   134  		if lvline > l {
   135  			//bigger than next cur
   136  			if l == cur {
   137  				l++
   138  			}
   139  			this.lvlUpdate(key, im, l, lvline)
   140  			//fmt.Println("等级", l-1, this.distribution[cur])
   141  			this.distribution[cur].amountIncrease(amount, la.Amount)
   142  			this.amountUpdate(key, amount)
   143  			continue
   144  		} else if lvline == l {
   145  			//only amout update
   146  			this.distribution[cur].amountIncrease(amount, la.Amount)
   147  			this.amountUpdate(key, amount)
   148  			continue
   149  		} else if lvline < l {
   150  			//lvl down
   151  			this.levelDown(key, lvline, cur, amount, la.Amount)
   152  			this.amountUpdate(key, amount)
   153  			continue
   154  		}
   155  	}
   156  }
   157  
   158  func (this *LevelManager) generateReward(height uint64, energyUsed *big.Int) {
   159  	dis := this.getLvAmountDistribution()
   160  	rewards := this.math.reward(height, energyUsed, dis)
   161  	//fmt.Printf("🈲️ destroy:%d ,reward:%v\n", energyUsed.Uint64(), rewards)
   162  	this.nextHeaderProperty = rewards
   163  }
   164  func (this *LevelManager) getLvAmountDistribution() []*big.Int {
   165  	s := make([]*big.Int, 0, 9)
   166  	for i := lv1; i <= lv9; i++ {
   167  		s = append(s, big.NewInt(0).Set(this.distribution[i].Amount))
   168  	}
   169  	return s
   170  }
   171  func (this *LevelManager) levelUpL() {
   172  	/*	for j := EasyLevel(1); j <= lv9; j++ {
   173  		fmt.Printf("pre lv %d count:%d amount:%d \n", j, this.distribution[j].Count, this.distribution[j].Amount.Uint64())
   174  	}*/
   175  	for k, v := range this.nextAccLvl {
   176  		im, l, r, _ := v.Lv.Decode()
   177  		//nothing to do
   178  		if r == lv0 {
   179  			continue
   180  		}
   181  		if im {
   182  			//next level is the same as the level after next
   183  			this.levelUp(k, l+1, r, v.Amount)
   184  			continue
   185  		} else {
   186  			this.lvlUpdate(k, true, l, r)
   187  			continue
   188  		}
   189  	}
   190  	err := this.LevelStore.SaveLevels(this.height, this.lvlChange)
   191  	if err != nil {
   192  		panic(err)
   193  	}
   194  	this.lvlChange = make(map[common.Address]EasyLevel)
   195  	//fmt.Println("-------------------")
   196  	/*	for j := EasyLevel(1); j <= lv9; j++ {
   197  		fmt.Printf("aft lv %d count:%d amount:%d \n", j, this.distribution[j].Count, this.distribution[j].Amount.Uint64())
   198  	}*/
   199  }
   200  
   201  func (this *LevelManager) levelWillBe(account common.Address, r EasyLevel, amount *big.Int) {
   202  	this.nextAccLvl[account] = &LvlAmount{
   203  		Amount: amount,
   204  		Lv:     newAccountLevel(false, lv1, r),
   205  	}
   206  }
   207  func (this *LevelManager) levelUp(account common.Address, l, r EasyLevel, amount *big.Int) {
   208  	if l > r && r != lv0 {
   209  		l = r
   210  		r = lv0
   211  	}
   212  	this.lvlUpdate(account, true, l, r)
   213  	curLv := l
   214  	if r == 0 {
   215  		curLv = l
   216  	} else {
   217  		curLv = l - 1
   218  	}
   219  	prevLv := curLv - 1
   220  	this.lvlChange[account] = curLv
   221  	this.lvlAmoutUpdate(curLv, prevLv, amount, amount)
   222  }
   223  
   224  func (this *LevelManager) levelDown(account common.Address, l, prevLv EasyLevel, amount, prevAmount *big.Int) {
   225  	this.lvlUpdate(account, true, l, 0)
   226  	this.lvlChange[account] = l
   227  	this.lvlAmoutUpdate(l, prevLv, amount, prevAmount)
   228  }
   229  
   230  func (this *LevelManager) levelClear(account common.Address, prevLv EasyLevel, prevAmount *big.Int) {
   231  	delete(this.nextAccLvl, account)
   232  	this.lvlChange[account] = lv0
   233  	this.lvlAmoutUpdate(lv0, prevLv, nil, prevAmount)
   234  }
   235  
   236  func (this *LevelManager) lvlUpdate(account common.Address, im bool, left, right EasyLevel) {
   237  	this.nextAccLvl[account].Lv = newAccountLevel(im, left, right)
   238  }
   239  func (this *LevelManager) amountUpdate(account common.Address, amount *big.Int) {
   240  	this.nextAccLvl[account].Amount.Set(amount)
   241  }
   242  func (this *LvStatistic) amountIncrease(amount, prevAmount *big.Int) {
   243  	if this != nil {
   244  		//fmt.Println(1, this.Amount.Uint64(), amount.Uint64())
   245  		this.Amount.Add(this.Amount, amount)
   246  		//fmt.Println(2, this.Amount.Uint64(), prevAmount.Uint64())
   247  		this.Amount.Sub(this.Amount, prevAmount)
   248  		//fmt.Println(3, this.Amount.Uint64())
   249  	}
   250  }
   251  
   252  func (this *LevelManager) lvlAmoutUpdate(curLv, prevLv EasyLevel, amount, prevAmount *big.Int) {
   253  	if curLv > lv0 {
   254  		this.distribution[curLv].add(amount)
   255  	}
   256  	if prevLv > lv0 {
   257  		this.distribution[prevLv].sub(prevAmount)
   258  	}
   259  }
   260  
   261  func (this *LevelManager) genesisLevel9(acc common.Address, amount *big.Int) {
   262  	this.distribution[lv9].Count++
   263  	this.distribution[lv9].add(amount)
   264  	this.nextAccLvl[acc] = &LvlAmount{
   265  		Amount: amount,
   266  		Lv:     newAccountLevel(true, lv9, 0),
   267  	}
   268  	this.lvlChange[acc] = lv9
   269  }