[RPC] Add RPCs to get list of BLS public keys for committees (#3080)

* [rpc] Fix sanity check to accept "latest"

* [rpc] Return as much data possible when using GetAllValidatorInformationByBlockNumber

* [rpc] Remove beacon check for getValidators, returns valid information on all shards

* [rpc] Add GetValidatorKeys to get BLS Keys of committee for a particular epoch

* [rpc] Add getBlockSignerKeys to return public bls keys of signers for a block

* [rpc] Fix lint

* [rpc] Address PR comments

* [rpc] Add common function to API backend instead of separate implementations in V1 & V2

* [rpc] Remove extra parenthesis

* [rpc] Fix lint
[validator] Fix typo

* [rpc] Revert change to sanity check in V2

* [rpc] Fix lint
pull/3109/head
Janet Liang 4 years ago committed by GitHub
parent 607c71a5f6
commit c4db1c0c4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 32
      hmy/api_backend.go
  2. 2
      internal/hmyapi/apiv1/backend.go
  3. 98
      internal/hmyapi/apiv1/blockchain.go
  4. 2
      internal/hmyapi/apiv2/backend.go
  5. 98
      internal/hmyapi/apiv2/blockchain.go
  6. 2
      internal/hmyapi/backend.go
  7. 4
      staking/types/validator.go

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/api/proto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum"
@ -20,6 +21,7 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
@ -848,3 +850,33 @@ func (b *APIBackend) GetNodeMetadata() commonRPC.NodeMetadata {
c,
}
}
// GetBlockSigners ..
func (b *APIBackend) GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *internal_bls.Mask, error) {
block, err := b.BlockByNumber(ctx, blockNr)
if err != nil {
return nil, nil, err
}
blockWithSigners, err := b.BlockByNumber(ctx, blockNr+1)
if err != nil {
return nil, nil, err
}
committee, err := b.GetValidators(block.Epoch())
if err != nil {
return nil, nil, err
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return nil, nil, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return nil, nil, err
}
return committee.Slots, mask, nil
}

@ -14,6 +14,7 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
@ -91,4 +92,5 @@ type Backend interface {
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
}

@ -18,7 +18,6 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
@ -183,9 +182,6 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.Bloc
// GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
if err := s.isBeaconShard(); err != nil {
return nil, err
}
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
@ -217,6 +213,20 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
return result, nil
}
// GetValidatorKeys returns list of bls public keys in the committee for a particular epoch.
func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
}
validators := make([]string, len(committee.Slots))
for i, v := range committee.Slots {
validators[i] = v.BLSPublicKey.Hex()
}
return validators, nil
}
// IsLastBlock checks if block is last epoch block.
func (s *PublicBlockChainAPI) IsLastBlock(blockNum uint64) (bool, error) {
if err := s.isBeaconShard(); err != nil {
@ -241,44 +251,46 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr rpc.B
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
block, err := s.b.BlockByNumber(ctx, blockNr)
if err != nil {
return nil, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, blockNr+1)
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr)
if err != nil {
return nil, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return nil, err
signers := []string{}
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return nil, err
}
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
signers = append(signers, oneAddress)
}
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
return signers, nil
}
// GetBlockSignerKeys returns bls public keys that signed the block.
func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr rpc.BlockNumber) ([]string, error) {
if uint64(blockNr) == 0 {
return []string{}, nil
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr)
if err != nil {
return nil, err
}
result := []string{}
for _, validator := range committee.Slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return nil, err
}
signers := []string{}
for _, validator := range slots {
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
result = append(result, oneAddress)
signers = append(signers, validator.BLSPublicKey.Hex())
}
}
return result, nil
return signers, nil
}
// IsBlockSigner returns true if validator with address signed blockNr block.
@ -289,32 +301,11 @@ func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr rpc.Blo
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return false, err
}
block, err := s.b.BlockByNumber(ctx, blockNr)
if err != nil {
return false, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, blockNr+1)
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr)
if err != nil {
return false, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return false, err
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return false, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return false, err
}
for _, validator := range committee.Slots {
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return false, err
@ -683,17 +674,16 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
validatorsNum = len(addresses) - start
}
}
validators := make([]*staking.ValidatorRPCEnhanced, validatorsNum)
validators := []*staking.ValidatorRPCEnhanced{}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr)
}
for i := start; i < start+validatorsNum; i++ {
information, err := s.b.GetValidatorInformation(addresses[i], block)
if err != nil {
return nil, err
if err == nil {
validators = append(validators, information)
}
validators[i-start] = information
}
return validators, nil
}

@ -14,6 +14,7 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
@ -87,4 +88,5 @@ type Backend interface {
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
}

@ -17,7 +17,6 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
@ -144,9 +143,6 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart, blockEn
// GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
if err := s.isBeaconShard(); err != nil {
return nil, err
}
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
@ -179,6 +175,20 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
return result, nil
}
// GetValidatorKeys returns list of bls public keys in the committee for a particular epoch.
func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
}
validators := make([]string, len(committee.Slots))
for i, v := range committee.Slots {
validators[i] = v.BLSPublicKey.Hex()
}
return validators, nil
}
// IsLastBlock checks if block is last epoch block.
func (s *PublicBlockChainAPI) IsLastBlock(blockNum uint64) (bool, error) {
if err := s.isBeaconShard(); err != nil {
@ -203,44 +213,46 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr uint6
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr+1))
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return nil, err
signers := []string{}
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return nil, err
}
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
signers = append(signers, oneAddress)
}
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
return signers, nil
}
// GetBlockSignerKeys returns bls public keys that signed the block.
func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr uint64) ([]string, error) {
if blockNr == 0 || blockNr >= uint64(s.BlockNumber()) {
return []string{}, nil
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, err
}
result := []string{}
for _, validator := range committee.Slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return nil, err
}
signers := []string{}
for _, validator := range slots {
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
result = append(result, oneAddress)
signers = append(signers, validator.BLSPublicKey.Hex())
}
}
return result, nil
return signers, nil
}
// IsBlockSigner returns true if validator with address signed blockNr block.
@ -251,32 +263,11 @@ func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr uint64,
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return false, err
}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return false, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr+1))
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return false, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return false, err
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return false, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return false, err
}
for _, validator := range committee.Slots {
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return false, err
@ -629,17 +620,16 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
validatorsNum = len(addresses) - start
}
}
validators := make([]*staking.ValidatorRPCEnhanced, validatorsNum)
validators := []*staking.ValidatorRPCEnhanced{}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr)
}
for i := start; i < start+validatorsNum; i++ {
information, err := s.b.GetValidatorInformation(addresses[i], block)
if err != nil {
return nil, err
if err == nil {
validators = append(validators, information)
}
validators[i-start] = information
}
return validators, nil
}

@ -14,6 +14,7 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/hmyapi/apiv1"
"github.com/harmony-one/harmony/internal/hmyapi/apiv2"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
@ -81,6 +82,7 @@ type Backend interface {
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
}
// GetAPIs returns all the APIs.

@ -62,7 +62,7 @@ var (
errDuplicateSlotKeys = errors.New("slot keys can not have duplicates")
// ErrExcessiveBLSKeys ..
ErrExcessiveBLSKeys = errors.New("more slot keys provided than allowed")
errCannotChangeBannedTaint = errors.New("cannot change validator banned status")
errCannotChangeBannedTrait = errors.New("cannot change validator banned status")
)
// ValidatorSnapshotReader ..
@ -645,7 +645,7 @@ func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator, epoch
switch validator.Status {
case effective.Banned:
return errCannotChangeBannedTaint
return errCannotChangeBannedTrait
default:
switch edit.EPOSStatus {
case effective.Active, effective.Inactive:

Loading…
Cancel
Save