Add full block reward integration; fix staking index bug; add staking txn signer check (#1889)

* Fix block rewards; Add staking signer check; Allow 0 MaxTotalDelegation

* Fix lint

* Add full block reward integration; fix staking index bug; add staking txn signer check
pull/1890/head
Rongjian Lan 5 years ago committed by Edgar Aroutiounian
parent aaf289c070
commit 1a5757b249
  1. 15
      core/blockchain.go
  2. 5
      core/chain_makers.go
  3. 6
      core/rawdb/accessors_chain.go
  4. 2
      core/rawdb/accessors_indexes.go
  5. 30
      core/state/statedb.go
  6. 30
      core/state_transition.go
  7. 3
      core/vm/interface.go
  8. 8
      hmy/api_backend.go
  9. 18
      internal/chain/reward.go
  10. 5
      shard/committee/assignment.go

@ -2306,8 +2306,8 @@ func (bc *BlockChain) ReadTxLookupEntry(txID common.Hash) (common.Hash, uint64,
return rawdb.ReadTxLookupEntry(bc.db, txID)
}
// ReadValidatorDataAt reads staking information of given validatorWrapper at a specific state root
func (bc *BlockChain) ReadValidatorDataAt(addr common.Address, root common.Hash) (*staking.ValidatorWrapper, error) {
// ReadValidatorInformationAt reads staking information of given validatorWrapper at a specific state root
func (bc *BlockChain) ReadValidatorInformationAt(addr common.Address, root common.Hash) (*staking.ValidatorWrapper, error) {
state, err := bc.StateAt(root)
if err != nil || state == nil {
return nil, err
@ -2319,13 +2319,12 @@ func (bc *BlockChain) ReadValidatorDataAt(addr common.Address, root common.Hash)
return wrapper, nil
}
// ReadValidatorData reads staking information of given validatorWrapper
func (bc *BlockChain) ReadValidatorData(addr common.Address) (*staking.ValidatorWrapper, error) {
return bc.ReadValidatorDataAt(addr, bc.CurrentBlock().Root())
// ReadValidatorInformation reads staking information of given validator address
func (bc *BlockChain) ReadValidatorInformation(addr common.Address) (*staking.ValidatorWrapper, error) {
return bc.ReadValidatorInformationAt(addr, bc.CurrentBlock().Root())
}
// ReadValidatorSnapshot reads the snapshot staking information of given validator address
// TODO: put epoch number in to snapshot too.
func (bc *BlockChain) ReadValidatorSnapshot(addr common.Address) (*staking.ValidatorWrapper, error) {
if cached, ok := bc.validatorCache.Get("validator-snapshot-" + string(addr.Bytes())); ok {
by := cached.([]byte)
@ -2344,7 +2343,7 @@ func (bc *BlockChain) WriteValidatorSnapshots(addrs []common.Address) error {
// Read all validator's current data
validators := []*staking.ValidatorWrapper{}
for _, addr := range addrs {
validator, err := bc.ReadValidatorData(addr)
validator, err := bc.ReadValidatorInformation(addr)
if err != nil {
return err
}
@ -2661,7 +2660,7 @@ func (bc *BlockChain) addDelegationIndex(delegatorAddress, validatorAddress comm
// Found the delegation from state and add the delegation index
// Note this should read from the state of current block in concern
wrapper, err := bc.ReadValidatorDataAt(validatorAddress, root)
wrapper, err := bc.ReadValidatorInformationAt(validatorAddress, root)
if err != nil {
return err
}

@ -273,7 +273,10 @@ func (cr *fakeChainReader) ReadShardState(epoch *big.Int) (shard.State, error)
func (cr *fakeChainReader) ReadActiveValidatorList() ([]common.Address, error) { return nil, nil }
func (cr *fakeChainReader) ValidatorCandidates() []common.Address { return nil }
func (cr *fakeChainReader) ReadValidatorData(addr common.Address) (*staking.ValidatorWrapper, error) {
func (cr *fakeChainReader) ReadValidatorInformation(addr common.Address) (*staking.ValidatorWrapper, error) {
return nil, nil
}
func (cr *fakeChainReader) ReadValidatorSnapshot(addr common.Address) (*staking.ValidatorWrapper, error) {
return nil, nil
}
func (cr *fakeChainReader) ValidatorStakingWithDelegation(addr common.Address) *big.Int { return nil }

@ -614,11 +614,11 @@ func WriteCXReceiptsProofUnspentCheckpoint(db DatabaseWriter, shardID uint32, bl
return db.Put(cxReceiptUnspentCheckpointKey(shardID), by)
}
// ReadValidatorData retrieves staking validator by its address
func ReadValidatorData(db DatabaseReader, addr common.Address) (*staking.ValidatorWrapper, error) {
// ReadValidatorInformation retrieves staking validator by its address
func ReadValidatorInformation(db DatabaseReader, addr common.Address) (*staking.ValidatorWrapper, error) {
data, err := db.Get(validatorKey(addr))
if err != nil || len(data) == 0 {
utils.Logger().Info().Err(err).Msg("ReadValidatorData")
utils.Logger().Info().Err(err).Msg("ReadValidatorInformation")
return nil, err
}
v := staking.ValidatorWrapper{}

@ -61,7 +61,7 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
entry := TxLookupEntry{
BlockHash: block.Hash(),
BlockIndex: block.NumberU64(),
Index: uint64(len(block.Transactions()) + i),
Index: uint64(i),
}
data, err := rlp.EncodeToBytes(entry)
if err != nil {

@ -734,42 +734,38 @@ func (db *DB) IsValidator(addr common.Address) bool {
}
// AddReward distributes the reward to all the delegators based on stake percentage.
func (db *DB) AddReward(validator common.Address, reward *big.Int) error {
func (db *DB) AddReward(snapshot *stk.ValidatorWrapper, reward *big.Int) error {
rewardPool := big.NewInt(0).Set(reward)
wrapper := db.GetStakingInfo(validator)
if wrapper == nil {
curValidator := db.GetStakingInfo(snapshot.Validator.Address)
if curValidator == nil {
return errors.New("failed to distribute rewards: validator does not exist")
}
// Payout commission
commissionInt := wrapper.Validator.CommissionRates.Rate.MulInt(reward).RoundInt()
wrapper.Delegations[0].Reward.Add(wrapper.Delegations[0].Reward, commissionInt)
commissionInt := snapshot.Validator.CommissionRates.Rate.MulInt(reward).RoundInt()
curValidator.Delegations[0].Reward.Add(curValidator.Delegations[0].Reward, commissionInt)
rewardPool.Sub(rewardPool, commissionInt)
totalRewardForDelegators := big.NewInt(0).Set(rewardPool)
// Payout each delegator's reward pro-rata
totalDelegationDec := numeric.NewDecFromBigInt(wrapper.TotalDelegation())
for i := range wrapper.Delegations {
delegation := wrapper.Delegations[i]
totalDelegationDec := numeric.NewDecFromBigInt(snapshot.TotalDelegation())
for i := range snapshot.Delegations {
delegation := snapshot.Delegations[i]
percentage := numeric.NewDecFromBigInt(delegation.Amount).Quo(totalDelegationDec) // percentage = <this_delegator_amount>/<total_delegation>
rewardInt := percentage.MulInt(totalRewardForDelegators).RoundInt()
delegation.Reward.Add(delegation.Reward, rewardInt)
curDelegation := curValidator.Delegations[i]
curDelegation.Reward.Add(curDelegation.Reward, rewardInt)
rewardPool.Sub(rewardPool, rewardInt)
}
// The last remaining bit belongs to the validator (remember the validator's self delegation is always at index 0)
if rewardPool.Cmp(big.NewInt(0)) > 0 {
wrapper.Delegations[0].Reward.Add(wrapper.Delegations[0].Reward, rewardPool)
curValidator.Delegations[0].Reward.Add(curValidator.Delegations[0].Reward, rewardPool)
}
return db.UpdateStakingInfo(validator, wrapper)
}
// CollectReward moves the rewards into the delegator's normal balance.
func (db *DB) CollectReward(delegator common.Address) {
// The reward will be withdrawn to the delegator's address balance as a whole.
return db.UpdateStakingInfo(curValidator.Validator.Address, curValidator)
}

@ -303,51 +303,51 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) {
switch msg.Type() {
case types.StakeNewVal:
stkMsg := &staking.CreateValidator{}
if msg.From() != stkMsg.ValidatorAddress {
return 0, errInvalidSigner
}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
return 0, err
}
if msg.From() != stkMsg.ValidatorAddress {
return 0, errInvalidSigner
}
err = st.applyCreateValidatorTx(stkMsg, msg.BlockNum())
case types.StakeEditVal:
stkMsg := &staking.EditValidator{}
if msg.From() != stkMsg.ValidatorAddress {
return 0, errInvalidSigner
}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
return 0, err
}
if msg.From() != stkMsg.ValidatorAddress {
return 0, errInvalidSigner
}
err = st.applyEditValidatorTx(stkMsg, msg.BlockNum())
case types.Delegate:
stkMsg := &staking.Delegate{}
if msg.From() != stkMsg.DelegatorAddress {
return 0, errInvalidSigner
}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
return 0, err
}
if msg.From() != stkMsg.DelegatorAddress {
return 0, errInvalidSigner
}
err = st.applyDelegateTx(stkMsg)
case types.Undelegate:
stkMsg := &staking.Undelegate{}
if msg.From() != stkMsg.DelegatorAddress {
return 0, errInvalidSigner
}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
return 0, err
}
err = st.applyUndelegateTx(stkMsg)
case types.CollectRewards:
stkMsg := &staking.CollectRewards{}
if msg.From() != stkMsg.DelegatorAddress {
return 0, errInvalidSigner
}
err = st.applyUndelegateTx(stkMsg)
case types.CollectRewards:
stkMsg := &staking.CollectRewards{}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
return 0, err
}
if msg.From() != stkMsg.DelegatorAddress {
return 0, errInvalidSigner
}
err = st.applyCollectRewards(stkMsg)
default:
return 0, staking.ErrInvalidStakingKind

@ -45,8 +45,7 @@ type StateDB interface {
SetValidatorFlag(common.Address)
UnsetValidatorFlag(common.Address)
IsValidator(common.Address) bool
AddReward(common.Address, *big.Int) error
CollectReward(common.Address)
AddReward(*staking.ValidatorWrapper, *big.Int) error
AddRefund(uint64)
SubRefund(uint64)

@ -303,7 +303,7 @@ func (b *APIBackend) GetAllValidatorAddresses() []common.Address {
// GetValidatorInformation returns the information of validator
func (b *APIBackend) GetValidatorInformation(addr common.Address) *staking.Validator {
val, _ := b.hmy.BlockChain().ReadValidatorData(addr)
val, _ := b.hmy.BlockChain().ReadValidatorInformation(addr)
return &val.Validator
}
@ -315,7 +315,7 @@ func (b *APIBackend) GetValidatorStats(addr common.Address) *staking.ValidatorSt
// GetDelegationsByValidator returns all delegation information of a validator
func (b *APIBackend) GetDelegationsByValidator(validator common.Address) []*staking.Delegation {
wrapper, err := b.hmy.BlockChain().ReadValidatorData(validator)
wrapper, err := b.hmy.BlockChain().ReadValidatorInformation(validator)
if err != nil || wrapper == nil {
return nil
}
@ -336,7 +336,7 @@ func (b *APIBackend) GetDelegationsByDelegator(delegator common.Address) ([]comm
}
for i := range delegationIndexes {
wrapper, err := b.hmy.BlockChain().ReadValidatorData(delegationIndexes[i].ValidatorAddress)
wrapper, err := b.hmy.BlockChain().ReadValidatorInformation(delegationIndexes[i].ValidatorAddress)
if err != nil || wrapper == nil {
return nil, nil
}
@ -353,7 +353,7 @@ func (b *APIBackend) GetDelegationsByDelegator(delegator common.Address) ([]comm
// GetValidatorSelfDelegation returns the amount of staking after applying all delegated stakes
func (b *APIBackend) GetValidatorSelfDelegation(addr common.Address) *big.Int {
wrapper, err := b.hmy.BlockChain().ReadValidatorData(addr)
wrapper, err := b.hmy.BlockChain().ReadValidatorInformation(addr)
if err != nil || wrapper == nil {
return nil
}

@ -134,7 +134,7 @@ func whatPercentStakedNow(
return nil, err
}
for i := range active {
wrapper, err := beaconchain.ReadValidatorData(active[i])
wrapper, err := beaconchain.ReadValidatorInformation(active[i])
if err != nil {
return nil, err
}
@ -166,6 +166,7 @@ func AccumulateRewards(
return nil
}
//// After staking
if bc.Config().IsStaking(header.Epoch()) &&
bc.CurrentHeader().ShardID() == shard.BeaconChainShardID {
@ -209,7 +210,11 @@ func AccumulateRewards(
due := defaultReward.Mul(
voter.EffectivePercent.Quo(votepower.StakersShare),
)
state.AddBalance(voter.EarningAccount, due.RoundInt())
snapshot, err := bc.ReadValidatorSnapshot(voter.EarningAccount)
if err != nil {
return err
}
state.AddReward(snapshot, due.RoundInt())
}
}
@ -296,8 +301,12 @@ func AccumulateRewards(
// Finally do the pay
for bucket := range resultsHandle {
for payThem := range resultsHandle[bucket] {
state.AddBalance(
resultsHandle[bucket][payThem].payee,
snapshot, err := bc.ReadValidatorSnapshot(resultsHandle[bucket][payThem].payee)
if err != nil {
return err
}
state.AddReward(
snapshot,
resultsHandle[bucket][payThem].effective.TruncateInt(),
)
}
@ -306,6 +315,7 @@ func AccumulateRewards(
return nil
}
//// Before staking
payable := []struct {
string
common.Address

@ -31,7 +31,8 @@ type Reader interface {
// StakingCandidatesReader ..
type StakingCandidatesReader interface {
ReadValidatorData(addr common.Address) (*staking.ValidatorWrapper, error)
ReadValidatorInformation(addr common.Address) (*staking.ValidatorWrapper, error)
ReadValidatorSnapshot(addr common.Address) (*staking.ValidatorWrapper, error)
ValidatorCandidates() []common.Address
}
@ -114,7 +115,7 @@ func eposStakedCommittee(
// TODO benchmark difference if went with data structure that sorts on insert
for i := range candidates {
validator, err := stakerReader.ReadValidatorData(candidates[i])
validator, err := stakerReader.ReadValidatorInformation(candidates[i])
validatorStake := big.NewInt(0)
for _, delegation := range validator.Delegations {
validatorStake.Add(validatorStake, delegation.Amount)

Loading…
Cancel
Save