mirror of
https://github.com/luxfi/sdk.git
synced 2026-10-30 15:19:23 +00:00
github.com/luxfi/utils is now github.com/luxfi/util. Import paths and the module requirement follow the rename. The json types cross the platformvm and exchangevm client boundary, so this also takes luxfi/vm v1.3.18, where those API structs already speak the renamed types. Co-authored-by: Hanzo Dev <[email protected]>
194 lines
5.5 KiB
Go
194 lines
5.5 KiB
Go
// Copyright (C) 2025, Lux Industries Inc All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package validator provides validator management and configuration utilities.
|
|
package validator
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/luxfi/sdk/constants"
|
|
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/rpc"
|
|
"github.com/luxfi/sdk/contract"
|
|
"github.com/luxfi/sdk/models"
|
|
"github.com/luxfi/sdk/platformvm"
|
|
"github.com/luxfi/util"
|
|
luxdjson "github.com/luxfi/util/json"
|
|
|
|
"github.com/luxfi/crypto"
|
|
)
|
|
|
|
type ValidatorKind int64
|
|
|
|
const (
|
|
UndefinedValidatorKind ValidatorKind = iota
|
|
NonValidator
|
|
SovereignValidator
|
|
NonSovereignValidator
|
|
)
|
|
|
|
// CurrentValidatorInfo enables querying validation IDs from P-Chain.
|
|
type CurrentValidatorInfo struct {
|
|
Weight luxdjson.Uint64 `json:"weight"`
|
|
NodeID ids.NodeID `json:"nodeID"`
|
|
ValidationID ids.ID `json:"validationID"`
|
|
Balance luxdjson.Uint64 `json:"balance"`
|
|
}
|
|
|
|
func GetTotalWeight(network models.Network, chainID ids.ID) (uint64, error) {
|
|
validators, err := GetCurrentValidators(network, chainID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
weight := uint64(0)
|
|
for _, vdr := range validators {
|
|
weight += uint64(vdr.Weight)
|
|
}
|
|
return weight, nil
|
|
}
|
|
|
|
func IsValidator(network models.Network, chainID ids.ID, nodeID ids.NodeID) (bool, error) {
|
|
validators, err := GetCurrentValidators(network, chainID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
nodeIDs := utils.Map(validators, func(v CurrentValidatorInfo) ids.NodeID { return v.NodeID })
|
|
return utils.Belongs(nodeIDs, nodeID), nil
|
|
}
|
|
|
|
func GetValidatorBalance(net models.Network, validationID ids.ID) (uint64, error) {
|
|
validator, err := GetValidatorInfo(net, validationID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
// For L1 validators, the balance is the staked amount
|
|
// Return the validator's weight as the balance
|
|
return validator.Weight, nil
|
|
}
|
|
|
|
func GetValidatorInfo(net models.Network, validationID ids.ID) (platformvm.ClientPermissionlessValidator, error) {
|
|
// Connect to the platform chain
|
|
pClient := platformvm.NewClient(net.Endpoint())
|
|
|
|
// Get current validators for the chain
|
|
ctx, cancel := apiRequestContext()
|
|
defer cancel()
|
|
|
|
// Query the validator by validation ID
|
|
// Since GetL1Validator is not available, we'll query all validators and find the matching one
|
|
validators, err := pClient.GetCurrentValidators(ctx, ids.Empty, nil)
|
|
if err != nil {
|
|
return platformvm.ClientPermissionlessValidator{}, fmt.Errorf("failed to get validators: %w", err)
|
|
}
|
|
|
|
// Search for the validator with matching validation ID
|
|
for _, validator := range validators {
|
|
// Check if this validator matches our validation ID
|
|
// Note: This is a workaround until GetL1Validator is available
|
|
if validator.TxID == validationID {
|
|
// Found the validator
|
|
return platformvm.ClientPermissionlessValidator{
|
|
ClientStaker: platformvm.ClientStaker{
|
|
TxID: validator.TxID,
|
|
StartTime: validator.StartTime,
|
|
EndTime: validator.EndTime,
|
|
Weight: validator.Weight,
|
|
NodeID: validator.NodeID,
|
|
},
|
|
// Other fields will be populated when available
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
return platformvm.ClientPermissionlessValidator{}, fmt.Errorf("validator with ID %s not found", validationID)
|
|
}
|
|
|
|
// GetValidationID returns the validation ID for the Node ID, as registered at the validator manager.
|
|
// Will return ids.Empty in case it is not registered.
|
|
func GetValidationID(
|
|
rpcURL string,
|
|
managerAddress crypto.Address,
|
|
nodeID ids.NodeID,
|
|
) (ids.ID, error) {
|
|
// if specialized, need to retrieve underlying manager
|
|
// needs to directly access the manager, does not work with a proxy
|
|
out, err := contract.CallToMethod(
|
|
rpcURL,
|
|
managerAddress,
|
|
"getStakingManagerSettings()->(address,uint256,uint256,uint64,uint16,uint8,uint256,address,bytes32)",
|
|
)
|
|
if err == nil && len(out) == 9 {
|
|
validatorManager, ok := out[0].(crypto.Address)
|
|
if ok {
|
|
managerAddress = validatorManager
|
|
}
|
|
}
|
|
out, err = contract.CallToMethod(
|
|
rpcURL,
|
|
managerAddress,
|
|
"registeredValidators(bytes)->(bytes32)",
|
|
nodeID[:],
|
|
)
|
|
if err != nil {
|
|
return ids.Empty, err
|
|
}
|
|
return contract.GetSmartContractCallResult[[32]byte]("registeredValidators", out)
|
|
}
|
|
|
|
func GetValidatorKind(
|
|
network models.Network,
|
|
chainID ids.ID,
|
|
nodeID ids.NodeID,
|
|
) (ValidatorKind, error) {
|
|
pClient := platformvm.NewClient(network.Endpoint())
|
|
ctx, cancel := apiRequestContext()
|
|
defer cancel()
|
|
vs, err := pClient.GetCurrentValidators(ctx, chainID, nil)
|
|
if err != nil {
|
|
return UndefinedValidatorKind, err
|
|
}
|
|
for _, v := range vs {
|
|
if v.NodeID == nodeID {
|
|
if v.TxID == ids.Empty {
|
|
return SovereignValidator, nil
|
|
}
|
|
return NonSovereignValidator, nil
|
|
}
|
|
}
|
|
return NonValidator, nil
|
|
}
|
|
|
|
// GetCurrentValidators enables querying the validation IDs from P-Chain.
|
|
func GetCurrentValidators(network models.Network, chainID ids.ID) ([]CurrentValidatorInfo, error) {
|
|
ctx, cancel := apiRequestContext()
|
|
defer cancel()
|
|
requester := rpc.NewEndpointRequester(constants.Chain(network.Endpoint(), "P"))
|
|
res := &platformvm.GetCurrentValidatorsReply{}
|
|
if err := requester.SendRequest(
|
|
ctx,
|
|
"platform.getCurrentValidators",
|
|
&platformvm.GetCurrentValidatorsArgs{
|
|
ChainID: chainID,
|
|
NodeIDs: nil,
|
|
},
|
|
res,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
validators := make([]CurrentValidatorInfo, 0, len(res.Validators))
|
|
for _, vI := range res.Validators {
|
|
vBytes, err := json.Marshal(vI)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var v CurrentValidatorInfo
|
|
if err := json.Unmarshal(vBytes, &v); err != nil {
|
|
return nil, err
|
|
}
|
|
validators = append(validators, v)
|
|
}
|
|
return validators, nil
|
|
}
|