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")