github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/vesting_state.go (about) 1 package miner 2 3 import ( 4 "sort" 5 6 "github.com/filecoin-project/go-state-types/abi" 7 "github.com/filecoin-project/go-state-types/big" 8 ) 9 10 // VestingFunds represents the vesting table state for the miner. 11 // It is a slice of (VestingEpoch, VestingAmount). 12 // The slice will always be sorted by the VestingEpoch. 13 type VestingFunds struct { 14 Funds []VestingFund 15 } 16 17 func (v *VestingFunds) unlockVestedFunds(currEpoch abi.ChainEpoch) abi.TokenAmount { 18 amountUnlocked := abi.NewTokenAmount(0) 19 20 lastIndexToRemove := -1 21 for i, vf := range v.Funds { 22 if vf.Epoch >= currEpoch { 23 break 24 } 25 26 amountUnlocked = big.Add(amountUnlocked, vf.Amount) 27 lastIndexToRemove = i 28 } 29 30 // remove all entries upto and including lastIndexToRemove 31 if lastIndexToRemove != -1 { 32 v.Funds = v.Funds[lastIndexToRemove+1:] 33 } 34 35 return amountUnlocked 36 } 37 38 func (v *VestingFunds) addLockedFunds(currEpoch abi.ChainEpoch, vestingSum abi.TokenAmount, 39 provingPeriodStart abi.ChainEpoch, spec *VestSpec) { 40 // maps the epochs in VestingFunds to their indices in the slice 41 epochToIndex := make(map[abi.ChainEpoch]int, len(v.Funds)) 42 for i, vf := range v.Funds { 43 epochToIndex[vf.Epoch] = i 44 } 45 46 // Quantization is aligned with when regular cron will be invoked, in the last epoch of deadlines. 47 vestBegin := currEpoch + spec.InitialDelay // Nothing unlocks here, this is just the start of the clock. 48 vestPeriod := big.NewInt(int64(spec.VestPeriod)) 49 vestedSoFar := big.Zero() 50 for e := vestBegin + spec.StepDuration; vestedSoFar.LessThan(vestingSum); e += spec.StepDuration { 51 vestEpoch := quantizeUp(e, spec.Quantization, provingPeriodStart) 52 elapsed := vestEpoch - vestBegin 53 54 targetVest := big.Zero() //nolint:ineffassign 55 if elapsed < spec.VestPeriod { 56 // Linear vesting 57 targetVest = big.Div(big.Mul(vestingSum, big.NewInt(int64(elapsed))), vestPeriod) 58 } else { 59 targetVest = vestingSum 60 } 61 62 vestThisTime := big.Sub(targetVest, vestedSoFar) 63 vestedSoFar = targetVest 64 65 // epoch already exists. Load existing entry 66 // and update amount. 67 if index, ok := epochToIndex[vestEpoch]; ok { 68 currentAmt := v.Funds[index].Amount 69 v.Funds[index].Amount = big.Add(currentAmt, vestThisTime) 70 } else { 71 // append a new entry -> slice will be sorted by epoch later. 72 entry := VestingFund{Epoch: vestEpoch, Amount: vestThisTime} 73 v.Funds = append(v.Funds, entry) 74 epochToIndex[vestEpoch] = len(v.Funds) - 1 75 } 76 } 77 78 // sort slice by epoch 79 sort.Slice(v.Funds, func(first, second int) bool { 80 return v.Funds[first].Epoch < v.Funds[second].Epoch 81 }) 82 } 83 84 func (v *VestingFunds) unlockUnvestedFunds(currEpoch abi.ChainEpoch, target abi.TokenAmount) abi.TokenAmount { 85 amountUnlocked := abi.NewTokenAmount(0) 86 lastIndexToRemove := -1 87 startIndexForRemove := 0 88 89 // retain funds that should have vested and unlock unvested funds 90 for i, vf := range v.Funds { 91 if amountUnlocked.GreaterThanEqual(target) { 92 break 93 } 94 95 if vf.Epoch >= currEpoch { 96 unlockAmount := big.Min(big.Sub(target, amountUnlocked), vf.Amount) 97 amountUnlocked = big.Add(amountUnlocked, unlockAmount) 98 newAmount := big.Sub(vf.Amount, unlockAmount) 99 100 if newAmount.IsZero() { 101 lastIndexToRemove = i 102 } else { 103 v.Funds[i].Amount = newAmount 104 } 105 } else { 106 startIndexForRemove = i + 1 107 } 108 } 109 110 // remove all entries in [startIndexForRemove, lastIndexToRemove] 111 if lastIndexToRemove != -1 { 112 v.Funds = append(v.Funds[0:startIndexForRemove], v.Funds[lastIndexToRemove+1:]...) 113 } 114 115 return amountUnlocked 116 } 117 118 // VestingFund represents miner funds that will vest at the given epoch. 119 type VestingFund struct { 120 Epoch abi.ChainEpoch 121 Amount abi.TokenAmount 122 } 123 124 // ConstructVestingFunds constructs empty VestingFunds state. 125 func ConstructVestingFunds() *VestingFunds { 126 v := new(VestingFunds) 127 v.Funds = nil 128 return v 129 }