[rpc] add GetValidatorsStakeByBlockNumber (#4254)

GetValidatorsStakeByBlockNumber calculates each validator's total
delegation at the specified block.
pull/4256/head
Max 2 years ago committed by GitHub
parent 35d4722bb2
commit c022075771
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      hmy/hmy.go
  2. 30
      hmy/staking.go
  3. 1
      rpc/metrics.go
  4. 34
      rpc/staking.go

@ -35,6 +35,8 @@ const (
undelegationPayoutsCacheSize = 500 // max number of epochs to store in cache undelegationPayoutsCacheSize = 500 // max number of epochs to store in cache
preStakingBlockRewardsCacheSize = 1024 // max number of block rewards to store in cache preStakingBlockRewardsCacheSize = 1024 // max number of block rewards to store in cache
totalStakeCacheDuration = 20 // number of blocks where the returned total stake will remain the same totalStakeCacheDuration = 20 // number of blocks where the returned total stake will remain the same
// max number of blocks for which the map "validator address -> total delegation to validator" is stored
stakeByBlockNumberCacheSize = 250
) )
var ( var (
@ -78,6 +80,8 @@ type Harmony struct {
preStakingBlockRewardsCache *lru.Cache preStakingBlockRewardsCache *lru.Cache
// totalStakeCache to save on recomputation for `totalStakeCacheDuration` blocks. // totalStakeCache to save on recomputation for `totalStakeCacheDuration` blocks.
totalStakeCache *totalStakeCache totalStakeCache *totalStakeCache
// stakeByBlockNumberCache to save on recomputation for `totalStakeCacheDuration` blocks
stakeByBlockNumberCache *lru.Cache
} }
// NodeAPI is the list of functions from node used to call rpc apis. // NodeAPI is the list of functions from node used to call rpc apis.
@ -125,6 +129,7 @@ func New(
) *Harmony { ) *Harmony {
leaderCache, _ := lru.New(leaderCacheSize) leaderCache, _ := lru.New(leaderCacheSize)
undelegationPayoutsCache, _ := lru.New(undelegationPayoutsCacheSize) undelegationPayoutsCache, _ := lru.New(undelegationPayoutsCacheSize)
stakeByBlockNumberCache, _ := lru.New(stakeByBlockNumberCacheSize)
preStakingBlockRewardsCache, _ := lru.New(preStakingBlockRewardsCacheSize) preStakingBlockRewardsCache, _ := lru.New(preStakingBlockRewardsCacheSize)
totalStakeCache := newTotalStakeCache(totalStakeCacheDuration) totalStakeCache := newTotalStakeCache(totalStakeCacheDuration)
bloomIndexer := NewBloomIndexer(nodeAPI.Blockchain(), params.BloomBitsBlocks, params.BloomConfirms) bloomIndexer := NewBloomIndexer(nodeAPI.Blockchain(), params.BloomBitsBlocks, params.BloomConfirms)
@ -148,6 +153,7 @@ func New(
totalStakeCache: totalStakeCache, totalStakeCache: totalStakeCache,
undelegationPayoutsCache: undelegationPayoutsCache, undelegationPayoutsCache: undelegationPayoutsCache,
preStakingBlockRewardsCache: preStakingBlockRewardsCache, preStakingBlockRewardsCache: preStakingBlockRewardsCache,
stakeByBlockNumberCache: stakeByBlockNumberCache,
} }
// Setup gas price oracle // Setup gas price oracle

@ -10,6 +10,7 @@ import (
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/eth/rpc" "github.com/harmony-one/harmony/eth/rpc"
"github.com/harmony-one/harmony/internal/chain" "github.com/harmony-one/harmony/internal/chain"
@ -226,6 +227,35 @@ func (hmy *Harmony) GetAllValidatorAddresses() []common.Address {
return hmy.BlockChain.ValidatorCandidates() return hmy.BlockChain.ValidatorCandidates()
} }
func (hmy *Harmony) GetValidatorsStakeByBlockNumber(
block *types.Block,
) (map[common.Address]*big.Int, error) {
if cachedReward, ok := hmy.stakeByBlockNumberCache.Get(block.Hash()); ok {
return cachedReward.(map[common.Address]*big.Int), nil
}
validatorAddresses := hmy.GetAllValidatorAddresses()
stakes := make(map[common.Address]*big.Int, len(validatorAddresses))
for _, validatorAddress := range validatorAddresses {
wrapper, err := hmy.BlockChain.ReadValidatorInformationAtRoot(validatorAddress, block.Root())
if err != nil {
if errors.Cause(err) != state.ErrAddressNotPresent {
return nil, errors.Errorf(
"cannot fetch information for validator %s at block %d due to %s",
validatorAddress.Hex(),
block.Number(),
err,
)
} else {
// `validatorAddress` was not a validator back then
continue
}
}
stakes[validatorAddress] = wrapper.TotalDelegation()
}
hmy.stakeByBlockNumberCache.Add(block.Hash(), stakes)
return stakes, nil
}
var ( var (
epochBlocksMap = map[common.Address]map[uint64]staking.EpochSigningEntry{} epochBlocksMap = map[common.Address]map[uint64]staking.EpochSigningEntry{}
mapLock = sync.Mutex{} mapLock = sync.Mutex{}

@ -71,6 +71,7 @@ const (
GetAllValidatorInformationByBlockNumber = "GetAllValidatorInformationByBlockNumber" GetAllValidatorInformationByBlockNumber = "GetAllValidatorInformationByBlockNumber"
GetValidatorInformation = "GetValidatorInformation" GetValidatorInformation = "GetValidatorInformation"
GetValidatorInformationByBlockNumber = "GetValidatorInformationByBlockNumber" GetValidatorInformationByBlockNumber = "GetValidatorInformationByBlockNumber"
GetValidatorsStakeByBlockNumber = "GetValidatorsStakeByBlockNumber"
GetValidatorSelfDelegation = "GetValidatorSelfDelegation" GetValidatorSelfDelegation = "GetValidatorSelfDelegation"
GetValidatorTotalDelegation = "GetValidatorTotalDelegation" GetValidatorTotalDelegation = "GetValidatorTotalDelegation"
GetAllDelegationInformation = "GetAllDelegationInformation" GetAllDelegationInformation = "GetAllDelegationInformation"

@ -458,6 +458,40 @@ func (s *PublicStakingService) GetValidatorInformationByBlockNumber(
return NewStructuredResponse(validatorInfo) return NewStructuredResponse(validatorInfo)
} }
// GetValidatorsStakeByBlockNumber returns the stake per validator at the specified block
func (s *PublicStakingService) GetValidatorsStakeByBlockNumber(
ctx context.Context, blockNumber BlockNumber,
) (StructuredResponse, error) {
timer := DoMetricRPCRequest(GetValidatorsStakeByBlockNumber)
defer DoRPCRequestDuration(GetValidatorsStakeByBlockNumber, timer)
// Process number based on version
blockNum := blockNumber.EthBlockNumber()
// Fetch block
if !isBeaconShard(s.hmy) {
DoMetricRPCQueryInfo(GetValidatorsStakeByBlockNumber, FailedNumber)
return nil, ErrNotBeaconShard
}
if isBlockGreaterThanLatest(s.hmy, blockNum) {
DoMetricRPCQueryInfo(GetValidatorsStakeByBlockNumber, FailedNumber)
return nil, ErrRequestedBlockTooHigh
}
blk, err := s.hmy.BlockByNumber(ctx, blockNum)
if err != nil {
DoMetricRPCQueryInfo(GetValidatorsStakeByBlockNumber, FailedNumber)
return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNum)
}
response, err := s.hmy.GetValidatorsStakeByBlockNumber(blk)
if err != nil {
DoMetricRPCQueryInfo(GetValidatorsStakeByBlockNumber, FailedNumber)
return nil, err
}
// Response output is the same for all versions
return NewStructuredResponse(response)
}
// GetValidatorSelfDelegation returns validator stake. // GetValidatorSelfDelegation returns validator stake.
func (s *PublicStakingService) GetValidatorSelfDelegation( func (s *PublicStakingService) GetValidatorSelfDelegation(
ctx context.Context, address string, ctx context.Context, address string,

Loading…
Cancel
Save