github.com/Gessiux/neatchain@v1.3.1/chain/core/state/statedb_reward.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/big" 8 "sort" 9 10 "github.com/Gessiux/neatchain/chain/trie" 11 "github.com/Gessiux/neatchain/utilities/common" 12 "github.com/Gessiux/neatchain/utilities/rlp" 13 ) 14 15 // ----- RewardBalance (Total) 16 17 // GetTotalRewardBalance Retrieve the reward balance from the given address or 0 if object not found 18 func (self *StateDB) GetTotalRewardBalance(addr common.Address) *big.Int { 19 stateObject := self.getStateObject(addr) 20 if stateObject != nil { 21 return stateObject.RewardBalance() 22 } 23 return common.Big0 24 } 25 26 func (self *StateDB) AddRewardBalance(addr common.Address, amount *big.Int) { 27 stateObject := self.GetOrNewStateObject(addr) 28 if stateObject != nil { 29 // Add amount to Total Reward Balance 30 stateObject.AddRewardBalance(amount) 31 } 32 } 33 34 func (self *StateDB) SubRewardBalance(addr common.Address, amount *big.Int) { 35 stateObject := self.GetOrNewStateObject(addr) 36 if stateObject != nil { 37 // Add amount to Total Reward Balance 38 stateObject.SubRewardBalance(amount) 39 } 40 } 41 42 // ----- AvailableRewardBalance (Total) 43 44 // GetTotalAvailableRewardBalance retrieve the available reward balance from the given address or 0 if object not found 45 func (self *StateDB) GetTotalAvailableRewardBalance(addr common.Address) *big.Int { 46 stateObject := self.getStateObject(addr) 47 if stateObject != nil { 48 return stateObject.AvailableRewardBalance() 49 } 50 return common.Big0 51 } 52 53 func (self *StateDB) AddAvailableRewardBalance(addr common.Address, amount *big.Int) { 54 stateObject := self.getStateObject(addr) 55 if stateObject != nil { 56 stateObject.AddAvailableRewardBalance(amount) 57 } 58 } 59 60 func (self *StateDB) SubAvailableRewardBalance(addr common.Address, amount *big.Int) { 61 stateObject := self.getStateObject(addr) 62 if stateObject != nil { 63 stateObject.SubAvailableRewardBalance(amount) 64 } 65 } 66 67 // ----- Reward Trie 68 69 func (self *StateDB) GetDelegateRewardAddress(addr common.Address) map[common.Address]struct{} { 70 var deleAddr map[common.Address]struct{} 71 reward := Reward{} 72 73 so := self.getStateObject(addr) 74 if so == nil { 75 return deleAddr 76 } 77 78 it := trie.NewIterator(so.getRewardTrie(self.db).NodeIterator(nil)) 79 for it.Next() { 80 var key common.Address 81 rlp.DecodeBytes(self.trie.GetKey(it.Key), &key) 82 deleAddr[key] = struct{}{} 83 } 84 85 if len(so.dirtyReward) > len(deleAddr) { 86 reward = so.dirtyReward 87 for key := range reward { 88 deleAddr[key] = struct{}{} 89 } 90 } 91 92 if len(so.originReward) > len(deleAddr) { 93 reward = so.originReward 94 for key := range reward { 95 deleAddr[key] = struct{}{} 96 } 97 } 98 99 return deleAddr 100 } 101 102 // GetRewardBalanceByDelegateAddress 103 func (self *StateDB) GetRewardBalanceByDelegateAddress(addr common.Address, deleAddress common.Address) *big.Int { 104 stateObject := self.getStateObject(addr) 105 if stateObject != nil { 106 rewardBalance := stateObject.GetDelegateRewardBalance(self.db, deleAddress) 107 if rewardBalance == nil { 108 return common.Big0 109 } else { 110 return rewardBalance 111 } 112 } 113 return common.Big0 114 } 115 116 // AddRewardBalanceByDelegateAddress adds reward amount to the account associated with delegate address 117 func (self *StateDB) AddRewardBalanceByDelegateAddress(addr common.Address, deleAddress common.Address, amount *big.Int) { 118 stateObject := self.GetOrNewStateObject(addr) 119 if stateObject != nil { 120 // Get EpochRewardBalance and update EpochRewardBalance 121 rewardBalance := stateObject.GetDelegateRewardBalance(self.db, deleAddress) 122 var dirtyRewardBalance *big.Int 123 if rewardBalance == nil { 124 dirtyRewardBalance = amount 125 } else { 126 dirtyRewardBalance = new(big.Int).Add(rewardBalance, amount) 127 } 128 stateObject.SetDelegateRewardBalance(self.db, deleAddress, dirtyRewardBalance) 129 130 // Add amount to Total Reward Balance 131 stateObject.AddRewardBalance(amount) 132 } 133 } 134 135 // AddRewardBalanceByDelegateAddress subtracts reward amount from the account associated with delegate address 136 func (self *StateDB) SubRewardBalanceByDelegateAddress(addr common.Address, deleAddress common.Address, amount *big.Int) { 137 stateObject := self.GetOrNewStateObject(addr) 138 if stateObject != nil { 139 // Get EpochRewardBalance and update EpochRewardBalance 140 rewardBalance := stateObject.GetDelegateRewardBalance(self.db, deleAddress) 141 var dirtyRewardBalance *big.Int 142 if rewardBalance == nil { 143 panic("you can't subtract the amount from nil balance, check the code, this should not happen") 144 } else { 145 dirtyRewardBalance = new(big.Int).Sub(rewardBalance, amount) 146 } 147 stateObject.SetDelegateRewardBalance(self.db, deleAddress, dirtyRewardBalance) 148 149 // Sub amount from Total Reward Balance 150 stateObject.SubRewardBalance(amount) 151 } 152 } 153 154 func (db *StateDB) ForEachReward(addr common.Address, cb func(key common.Address, rewardBalance *big.Int) bool) { 155 so := db.getStateObject(addr) 156 if so == nil { 157 return 158 } 159 it := trie.NewIterator(so.getRewardTrie(db.db).NodeIterator(nil)) 160 for it.Next() { 161 var key common.Address 162 rlp.DecodeBytes(db.trie.GetKey(it.Key), &key) 163 if value, dirty := so.dirtyReward[key]; dirty { 164 cb(key, value) 165 continue 166 } 167 var value big.Int 168 rlp.DecodeBytes(it.Value, &value) 169 cb(key, &value) 170 } 171 } 172 173 // ----- Reward Set 174 175 // MarkAddressReward adds the specified object to the dirty map to avoid 176 func (self *StateDB) MarkAddressReward(addr common.Address) { 177 if _, exist := self.GetRewardSet()[addr]; !exist { 178 self.rewardSet[addr] = struct{}{} 179 self.rewardSetDirty = true 180 } 181 } 182 183 func (self *StateDB) GetRewardSet() RewardSet { 184 if len(self.rewardSet) != 0 { 185 return self.rewardSet 186 } 187 // Try to get from Trie 188 enc, err := self.trie.TryGet(rewardSetKey) 189 if err != nil { 190 self.setError(err) 191 return nil 192 } 193 var value RewardSet 194 if len(enc) > 0 { 195 err := rlp.DecodeBytes(enc, &value) 196 if err != nil { 197 self.setError(err) 198 } 199 self.rewardSet = value 200 } 201 return value 202 } 203 204 func (self *StateDB) commitRewardSet() { 205 data, err := rlp.EncodeToBytes(self.rewardSet) 206 if err != nil { 207 panic(fmt.Errorf("can't encode reward set : %v", err)) 208 } 209 self.setError(self.trie.TryUpdate(rewardSetKey, data)) 210 } 211 212 func (self *StateDB) ClearRewardSetByAddress(addr common.Address) { 213 delete(self.rewardSet, addr) 214 self.rewardSetDirty = true 215 } 216 217 // Store the Reward Address Set 218 219 var rewardSetKey = []byte("RewardSet") 220 221 type RewardSet map[common.Address]struct{} 222 223 func (set RewardSet) EncodeRLP(w io.Writer) error { 224 var list []common.Address 225 for addr := range set { 226 list = append(list, addr) 227 } 228 sort.Slice(list, func(i, j int) bool { 229 return bytes.Compare(list[i].Bytes(), list[j].Bytes()) == 1 230 }) 231 return rlp.Encode(w, list) 232 } 233 234 func (set *RewardSet) DecodeRLP(s *rlp.Stream) error { 235 var list []common.Address 236 if err := s.Decode(&list); err != nil { 237 return err 238 } 239 rewardSet := make(RewardSet, len(list)) 240 for _, addr := range list { 241 rewardSet[addr] = struct{}{} 242 } 243 *set = rewardSet 244 return nil 245 } 246 247 // ----- Side Chain Reward Per Block 248 249 func (self *StateDB) SetSideChainRewardPerBlock(rewardPerBlock *big.Int) { 250 self.sideChainRewardPerBlock = rewardPerBlock 251 self.sideChainRewardPerBlockDirty = true 252 } 253 254 func (self *StateDB) GetSideChainRewardPerBlock() *big.Int { 255 if self.sideChainRewardPerBlock != nil { 256 return self.sideChainRewardPerBlock 257 } 258 // Try to get from Trie 259 enc, err := self.trie.TryGet(sideChainRewardPerBlockKey) 260 if err != nil { 261 self.setError(err) 262 return nil 263 } 264 value := new(big.Int) 265 if len(enc) > 0 { 266 err := rlp.DecodeBytes(enc, value) 267 if err != nil { 268 self.setError(err) 269 } 270 self.sideChainRewardPerBlock = value 271 } 272 return value 273 } 274 275 func (self *StateDB) commitSideChainRewardPerBlock() { 276 data, err := rlp.EncodeToBytes(self.sideChainRewardPerBlock) 277 if err != nil { 278 panic(fmt.Errorf("can't encode side chain reward per block : %v", err)) 279 } 280 self.setError(self.trie.TryUpdate(sideChainRewardPerBlockKey, data)) 281 } 282 283 // Side Chain Reward Per Block 284 285 var sideChainRewardPerBlockKey = []byte("RewardPerBlock")