mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
133 lines
3.5 KiB
Go
133 lines
3.5 KiB
Go
// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
package utils
|
|
|
|
import (
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/luxfi/cli/v2/pkg/constants"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/node/v2/v2/staking"
|
|
"github.com/luxfi/crypto/bls"
|
|
"github.com/luxfi/crypto/bls/signer/localsigner"
|
|
"github.com/luxfi/node/v2/v2/vms/platformvm"
|
|
evmclient "github.com/luxfi/evm/v2/plugin/evm/client"
|
|
)
|
|
|
|
func NewBlsSecretKeyBytes() ([]byte, error) {
|
|
blsSignerKey, err := localsigner.New()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return blsSignerKey.ToBytes(), nil
|
|
}
|
|
|
|
func ToNodeID(certBytes []byte) (ids.NodeID, error) {
|
|
block, _ := pem.Decode(certBytes)
|
|
if block == nil {
|
|
return ids.EmptyNodeID, fmt.Errorf("failed to decode certificate")
|
|
}
|
|
cert, err := staking.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
return ids.EmptyNodeID, err
|
|
}
|
|
// Convert staking.Certificate to ids.Certificate
|
|
idsCert := &ids.Certificate{
|
|
Raw: cert.Raw,
|
|
PublicKey: cert.PublicKey,
|
|
}
|
|
return ids.NodeIDFromCert(idsCert), nil
|
|
}
|
|
|
|
func ToBLSPoP(keyBytes []byte) (
|
|
[]byte, // bls public key
|
|
[]byte, // bls proof of possession
|
|
error,
|
|
) {
|
|
signer, err := localsigner.FromBytes(keyBytes)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Get the public key
|
|
pk := signer.PublicKey()
|
|
pkBytes := bls.PublicKeyToCompressedBytes(pk)
|
|
|
|
// Create proof of possession
|
|
sig, err := signer.SignProofOfPossession(pkBytes)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
sigBytes := bls.SignatureToBytes(sig)
|
|
|
|
return pkBytes, sigBytes, nil
|
|
}
|
|
|
|
// GetNodeParams returns node id, bls public key and bls proof of possession
|
|
func GetNodeParams(nodeDir string) (
|
|
ids.NodeID,
|
|
[]byte, // bls public key
|
|
[]byte, // bls proof of possession
|
|
error,
|
|
) {
|
|
certBytes, err := os.ReadFile(filepath.Join(nodeDir, constants.StakerCertFileName))
|
|
if err != nil {
|
|
return ids.EmptyNodeID, nil, nil, err
|
|
}
|
|
nodeID, err := ToNodeID(certBytes)
|
|
if err != nil {
|
|
return ids.EmptyNodeID, nil, nil, err
|
|
}
|
|
blsKeyBytes, err := os.ReadFile(filepath.Join(nodeDir, constants.BLSKeyFileName))
|
|
if err != nil {
|
|
return ids.EmptyNodeID, nil, nil, err
|
|
}
|
|
blsPub, blsPoP, err := ToBLSPoP(blsKeyBytes)
|
|
if err != nil {
|
|
return ids.EmptyNodeID, nil, nil, err
|
|
}
|
|
return nodeID, blsPub, blsPoP, nil
|
|
}
|
|
|
|
func GetRemainingValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.ID, startTime time.Time) (time.Duration, error) {
|
|
ctx, cancel := GetAPIContext()
|
|
defer cancel()
|
|
platformCli := platformvm.NewClient(networkEndpoint)
|
|
vs, err := platformCli.GetCurrentValidators(ctx, subnetID, nil)
|
|
cancel()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
for _, v := range vs {
|
|
if v.NodeID == nodeID {
|
|
return time.Unix(int64(v.EndTime), 0).Sub(startTime), nil
|
|
}
|
|
}
|
|
return 0, errors.New("nodeID not found in validator set: " + nodeID.String())
|
|
}
|
|
|
|
// GetL1ValidatorUptimeSeconds returns the uptime of the L1 validator
|
|
func GetL1ValidatorUptimeSeconds(rpcURL string, nodeID ids.NodeID) (uint64, error) {
|
|
ctx, cancel := GetAPIContext()
|
|
defer cancel()
|
|
networkEndpoint, blockchainID, err := SplitLuxgoRPCURI(rpcURL)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
evmCli := evmclient.NewClient(networkEndpoint, blockchainID)
|
|
validators, err := evmCli.GetCurrentValidators(ctx, []ids.NodeID{nodeID})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if len(validators) > 0 {
|
|
return validators[0].UptimeSeconds - uint64(constants.ValidatorUptimeDeductible.Seconds()), nil
|
|
}
|
|
|
|
return 0, errors.New("nodeID not found in validator set: " + nodeID.String())
|
|
}
|