mirror of
https://github.com/luxfi/netrunner.git
synced 2026-07-27 00:04:23 +00:00
add permissionless validators
This commit is contained in:
@@ -34,6 +34,7 @@ type Client interface {
|
||||
CreateBlockchains(ctx context.Context, blockchainSpecs []*rpcpb.BlockchainSpec) (*rpcpb.CreateBlockchainsResponse, error)
|
||||
CreateSubnets(ctx context.Context, subnetSpecs []*rpcpb.SubnetSpec) (*rpcpb.CreateSubnetsResponse, error)
|
||||
TransformElasticSubnets(ctx context.Context, elasticSubnetSpecs []*rpcpb.ElasticSubnetSpec) (*rpcpb.TransformElasticSubnetsResponse, error)
|
||||
AddPermissionlessValidator(ctx context.Context, validatorSpec []*rpcpb.PermissionlessValidatorSpec) (*rpcpb.AddPermissionlessValidatorResponse, error)
|
||||
Health(ctx context.Context) (*rpcpb.HealthResponse, error)
|
||||
WaitForHealthy(ctx context.Context) (*rpcpb.WaitForHealthyResponse, error)
|
||||
URIs(ctx context.Context) ([]string, error)
|
||||
@@ -168,6 +169,15 @@ func (c *client) TransformElasticSubnets(ctx context.Context, elasticSubnetSpecs
|
||||
return c.controlc.TransformElasticSubnets(ctx, req)
|
||||
}
|
||||
|
||||
func (c *client) AddPermissionlessValidator(ctx context.Context, validatorSpec []*rpcpb.PermissionlessValidatorSpec) (*rpcpb.AddPermissionlessValidatorResponse, error) {
|
||||
req := &rpcpb.AddPermissionlessValidatorRequest{
|
||||
ValidatorSpec: validatorSpec,
|
||||
}
|
||||
|
||||
c.log.Info("add permissionless validators to elastic subnets")
|
||||
return c.controlc.AddPermissionlessValidator(ctx, req)
|
||||
}
|
||||
|
||||
func (c *client) Health(ctx context.Context) (*rpcpb.HealthResponse, error) {
|
||||
c.log.Info("health")
|
||||
return c.controlc.Health(ctx, &rpcpb.HealthRequest{})
|
||||
|
||||
@@ -61,6 +61,7 @@ func NewCommand() *cobra.Command {
|
||||
newCreateBlockchainsCommand(),
|
||||
newCreateSubnetsCommand(),
|
||||
newTransformElasticSubnetsCommand(),
|
||||
newAddPermissionlessValidatorCommand(),
|
||||
newHealthCommand(),
|
||||
newWaitForHealthyCommand(),
|
||||
newURIsCommand(),
|
||||
@@ -412,6 +413,15 @@ func newTransformElasticSubnetsCommand() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newAddPermissionlessValidatorCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add-permissionless-validator [options]",
|
||||
Short: "Add permissionelss validator to elastic subnets.",
|
||||
RunE: addPermissionlessValidatorFunc,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
func transformElasticSubnetsFunc(_ *cobra.Command, args []string) error {
|
||||
cli, err := newClient()
|
||||
if err != nil {
|
||||
@@ -440,6 +450,34 @@ func transformElasticSubnetsFunc(_ *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func addPermissionlessValidatorFunc(_ *cobra.Command, args []string) error {
|
||||
cli, err := newClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
validatorSpecStr := args[0]
|
||||
|
||||
validatorSpec := []*rpcpb.PermissionlessValidatorSpec{}
|
||||
if err := json.Unmarshal([]byte(validatorSpecStr), &validatorSpec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := getAsyncContext()
|
||||
|
||||
info, err := cli.AddPermissionlessValidator(
|
||||
ctx,
|
||||
validatorSpec,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ux.Print(log, logging.Green.Wrap("add-permissionless-validator response: %+v"), info)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newHealthCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "health [options]",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ava-labs/avalanchego/vms/platformvm/reward"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -53,6 +54,8 @@ const (
|
||||
// check period while waiting for all validators to be ready
|
||||
waitForValidatorsPullFrequency = time.Second
|
||||
defaultTimeout = time.Minute
|
||||
stakingMinimumLeadTime = 25 * time.Second
|
||||
minStakeDuration = 24 * 14 * time.Hour
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -150,6 +153,16 @@ func (ln *localNetwork) RegisterBlockchainAliases(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ln *localNetwork) AddPermissionlessValidator(
|
||||
ctx context.Context,
|
||||
validatorSpec []network.PermissionlessValidatorSpec,
|
||||
) ([]ids.ID, error) {
|
||||
ln.lock.Lock()
|
||||
defer ln.lock.Unlock()
|
||||
|
||||
return ln.addPermissionlessValidators(ctx, validatorSpec)
|
||||
}
|
||||
|
||||
func (ln *localNetwork) TransformSubnet(
|
||||
ctx context.Context,
|
||||
elasticSubnetConfig []network.ElasticSubnetSpec,
|
||||
@@ -769,6 +782,81 @@ func importPChainFromXChain(ctx context.Context, w *wallet, owner *secp256k1fx.O
|
||||
return err
|
||||
}
|
||||
|
||||
func (ln *localNetwork) addPermissionlessValidators(
|
||||
ctx context.Context,
|
||||
validatorSpecs []network.PermissionlessValidatorSpec,
|
||||
) ([]ids.ID, error) {
|
||||
ln.log.Info("adding permissionless validator tx")
|
||||
validatorSpecIDs := make([]ids.ID, len(validatorSpecs))
|
||||
clientURI, err := ln.getClientURI()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// wallet needs txs for all previously created subnets
|
||||
var preloadTXs []ids.ID
|
||||
for _, validatorSpec := range validatorSpecs {
|
||||
if validatorSpec.SubnetID == nil {
|
||||
return nil, errors.New("permissionless validator spec has no subnet ID")
|
||||
} else {
|
||||
subnetID, err := ids.FromString(*validatorSpec.SubnetID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preloadTXs = append(preloadTXs, subnetID)
|
||||
}
|
||||
}
|
||||
w, err := newWallet(ctx, clientURI, preloadTXs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
owner := &secp256k1fx.OutputOwners{
|
||||
Threshold: 1,
|
||||
Addrs: []ids.ShortID{
|
||||
w.addr,
|
||||
},
|
||||
}
|
||||
for i, validatorSpec := range validatorSpecs {
|
||||
ln.log.Info(logging.Green.Wrap("adding permissionless validator"), zap.String("node ID", validatorSpec.NodeID))
|
||||
cctx, cancel := createDefaultCtx(ctx)
|
||||
validatoreNodeID, err := ids.NodeIDFromString(validatorSpec.NodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subnetID, err := ids.FromString(*validatorSpec.SubnetID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
assetID, err := ids.FromString(validatorSpec.AssetID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txID, err := w.pWallet.IssueAddPermissionlessValidatorTx(
|
||||
&txs.SubnetValidator{
|
||||
Validator: txs.Validator{
|
||||
NodeID: validatoreNodeID,
|
||||
Start: uint64(validatorSpec.StartTime.Unix()),
|
||||
End: uint64(validatorSpec.StartTime.Add(validatorSpec.StakeDuration).Unix()),
|
||||
Wght: validatorSpec.StakedAmount,
|
||||
},
|
||||
Subnet: subnetID,
|
||||
},
|
||||
&signer.Empty{},
|
||||
assetID,
|
||||
owner,
|
||||
&secp256k1fx.OutputOwners{},
|
||||
reward.PercentDenominator,
|
||||
common.WithContext(cctx),
|
||||
defaultPoll,
|
||||
)
|
||||
cancel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ln.log.Info("Validator successfully added as permissionless validator", zap.String("TX ID", txID.String()))
|
||||
validatorSpecIDs[i] = txID
|
||||
}
|
||||
return validatorSpecIDs, nil
|
||||
}
|
||||
func (ln *localNetwork) transformToElasticSubnets(
|
||||
ctx context.Context,
|
||||
elasticSubnetSpecs []network.ElasticSubnetSpec,
|
||||
|
||||
@@ -15,6 +15,15 @@ var (
|
||||
ErrNodeNotFound = errors.New("node not found in network")
|
||||
)
|
||||
|
||||
type PermissionlessValidatorSpec struct {
|
||||
SubnetID *string
|
||||
AssetID string
|
||||
NodeID string
|
||||
StakedAmount uint64
|
||||
StartTime time.Time
|
||||
StakeDuration time.Duration
|
||||
}
|
||||
|
||||
type ElasticSubnetSpec struct {
|
||||
SubnetID *string
|
||||
AssetName string
|
||||
@@ -98,4 +107,6 @@ type Network interface {
|
||||
CreateSubnets(context.Context, []SubnetSpec) ([]ids.ID, error)
|
||||
// Transform subnet into elastic subnet
|
||||
TransformSubnet(context.Context, []ElasticSubnetSpec) ([]ids.ID, error)
|
||||
// Add a validator into an elastic subnet
|
||||
AddPermissionlessValidator(context.Context, []PermissionlessValidatorSpec) ([]ids.ID, error)
|
||||
}
|
||||
|
||||
+1024
-753
File diff suppressed because it is too large
Load Diff
+88
-3
@@ -201,6 +201,40 @@ func local_request_ControlService_TransformElasticSubnets_0(ctx context.Context,
|
||||
|
||||
}
|
||||
|
||||
func request_ControlService_AddPermissionlessValidator_0(ctx context.Context, marshaler runtime.Marshaler, client ControlServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq AddPermissionlessValidatorRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.AddPermissionlessValidator(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_ControlService_AddPermissionlessValidator_0(ctx context.Context, marshaler runtime.Marshaler, server ControlServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq AddPermissionlessValidatorRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.AddPermissionlessValidator(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_ControlService_CreateSubnets_0(ctx context.Context, marshaler runtime.Marshaler, client ControlServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CreateSubnetsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@@ -927,7 +961,7 @@ func RegisterControlServiceHandlerServer(ctx context.Context, mux *runtime.Serve
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/rpcpb.ControlService/TransformElasticSubnets", runtime.WithHTTPPathPattern("/v1/control/transformelasticsubnet"))
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/rpcpb.ControlService/TransformElasticSubnets", runtime.WithHTTPPathPattern("/v1/control/transformelasticsubnets"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
@@ -944,6 +978,31 @@ func RegisterControlServiceHandlerServer(ctx context.Context, mux *runtime.Serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_ControlService_AddPermissionlessValidator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/rpcpb.ControlService/AddPermissionlessValidator", runtime.WithHTTPPathPattern("/v1/control/addpermissionlessvalidator"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_ControlService_AddPermissionlessValidator_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ControlService_AddPermissionlessValidator_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_ControlService_CreateSubnets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -1560,7 +1619,7 @@ func RegisterControlServiceHandlerClient(ctx context.Context, mux *runtime.Serve
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/rpcpb.ControlService/TransformElasticSubnets", runtime.WithHTTPPathPattern("/v1/control/transformelasticsubnet"))
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/rpcpb.ControlService/TransformElasticSubnets", runtime.WithHTTPPathPattern("/v1/control/transformelasticsubnets"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
@@ -1576,6 +1635,28 @@ func RegisterControlServiceHandlerClient(ctx context.Context, mux *runtime.Serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_ControlService_AddPermissionlessValidator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/rpcpb.ControlService/AddPermissionlessValidator", runtime.WithHTTPPathPattern("/v1/control/addpermissionlessvalidator"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ControlService_AddPermissionlessValidator_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ControlService_AddPermissionlessValidator_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_ControlService_CreateSubnets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -1982,7 +2063,9 @@ var (
|
||||
|
||||
pattern_ControlService_CreateBlockchains_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "control", "createblockchains"}, ""))
|
||||
|
||||
pattern_ControlService_TransformElasticSubnets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "control", "transformelasticsubnet"}, ""))
|
||||
pattern_ControlService_TransformElasticSubnets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "control", "transformelasticsubnets"}, ""))
|
||||
|
||||
pattern_ControlService_AddPermissionlessValidator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "control", "addpermissionlessvalidator"}, ""))
|
||||
|
||||
pattern_ControlService_CreateSubnets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "control", "createsubnets"}, ""))
|
||||
|
||||
@@ -2030,6 +2113,8 @@ var (
|
||||
|
||||
forward_ControlService_TransformElasticSubnets_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ControlService_AddPermissionlessValidator_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ControlService_CreateSubnets_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ControlService_Health_0 = runtime.ForwardResponseMessage
|
||||
|
||||
@@ -50,6 +50,13 @@ service ControlService {
|
||||
};
|
||||
}
|
||||
|
||||
rpc AddPermissionlessValidator(AddPermissionlessValidatorRequest) returns (AddPermissionlessValidatorResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/control/addpermissionlessvalidator"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
rpc CreateSubnets(CreateSubnetsRequest) returns (CreateSubnetsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/control/createsubnets"
|
||||
@@ -344,6 +351,24 @@ message TransformElasticSubnetsResponse {
|
||||
repeated string tx_ids = 2;
|
||||
}
|
||||
|
||||
message PermissionlessValidatorSpec {
|
||||
string subnet_id = 1;
|
||||
string node_id = 2;
|
||||
uint64 staked_token_amount = 3;
|
||||
string asset_id = 4;
|
||||
string start_time = 5;
|
||||
uint64 stake_duration = 6;
|
||||
}
|
||||
|
||||
message AddPermissionlessValidatorRequest {
|
||||
repeated PermissionlessValidatorSpec validator_spec = 1;
|
||||
}
|
||||
|
||||
message AddPermissionlessValidatorResponse {
|
||||
ClusterInfo cluster_info = 1;
|
||||
repeated string tx_ids = 2;
|
||||
}
|
||||
|
||||
message BlockchainSpec {
|
||||
string vm_name = 1;
|
||||
// either file path or file contents
|
||||
|
||||
+59
-22
@@ -109,28 +109,29 @@ var PingService_ServiceDesc = grpc.ServiceDesc{
|
||||
}
|
||||
|
||||
const (
|
||||
ControlService_RPCVersion_FullMethodName = "/rpcpb.ControlService/RPCVersion"
|
||||
ControlService_Start_FullMethodName = "/rpcpb.ControlService/Start"
|
||||
ControlService_CreateBlockchains_FullMethodName = "/rpcpb.ControlService/CreateBlockchains"
|
||||
ControlService_TransformElasticSubnets_FullMethodName = "/rpcpb.ControlService/TransformElasticSubnets"
|
||||
ControlService_CreateSubnets_FullMethodName = "/rpcpb.ControlService/CreateSubnets"
|
||||
ControlService_Health_FullMethodName = "/rpcpb.ControlService/Health"
|
||||
ControlService_URIs_FullMethodName = "/rpcpb.ControlService/URIs"
|
||||
ControlService_WaitForHealthy_FullMethodName = "/rpcpb.ControlService/WaitForHealthy"
|
||||
ControlService_Status_FullMethodName = "/rpcpb.ControlService/Status"
|
||||
ControlService_StreamStatus_FullMethodName = "/rpcpb.ControlService/StreamStatus"
|
||||
ControlService_RemoveNode_FullMethodName = "/rpcpb.ControlService/RemoveNode"
|
||||
ControlService_AddNode_FullMethodName = "/rpcpb.ControlService/AddNode"
|
||||
ControlService_RestartNode_FullMethodName = "/rpcpb.ControlService/RestartNode"
|
||||
ControlService_PauseNode_FullMethodName = "/rpcpb.ControlService/PauseNode"
|
||||
ControlService_ResumeNode_FullMethodName = "/rpcpb.ControlService/ResumeNode"
|
||||
ControlService_Stop_FullMethodName = "/rpcpb.ControlService/Stop"
|
||||
ControlService_AttachPeer_FullMethodName = "/rpcpb.ControlService/AttachPeer"
|
||||
ControlService_SendOutboundMessage_FullMethodName = "/rpcpb.ControlService/SendOutboundMessage"
|
||||
ControlService_SaveSnapshot_FullMethodName = "/rpcpb.ControlService/SaveSnapshot"
|
||||
ControlService_LoadSnapshot_FullMethodName = "/rpcpb.ControlService/LoadSnapshot"
|
||||
ControlService_RemoveSnapshot_FullMethodName = "/rpcpb.ControlService/RemoveSnapshot"
|
||||
ControlService_GetSnapshotNames_FullMethodName = "/rpcpb.ControlService/GetSnapshotNames"
|
||||
ControlService_RPCVersion_FullMethodName = "/rpcpb.ControlService/RPCVersion"
|
||||
ControlService_Start_FullMethodName = "/rpcpb.ControlService/Start"
|
||||
ControlService_CreateBlockchains_FullMethodName = "/rpcpb.ControlService/CreateBlockchains"
|
||||
ControlService_TransformElasticSubnets_FullMethodName = "/rpcpb.ControlService/TransformElasticSubnets"
|
||||
ControlService_AddPermissionlessValidator_FullMethodName = "/rpcpb.ControlService/AddPermissionlessValidator"
|
||||
ControlService_CreateSubnets_FullMethodName = "/rpcpb.ControlService/CreateSubnets"
|
||||
ControlService_Health_FullMethodName = "/rpcpb.ControlService/Health"
|
||||
ControlService_URIs_FullMethodName = "/rpcpb.ControlService/URIs"
|
||||
ControlService_WaitForHealthy_FullMethodName = "/rpcpb.ControlService/WaitForHealthy"
|
||||
ControlService_Status_FullMethodName = "/rpcpb.ControlService/Status"
|
||||
ControlService_StreamStatus_FullMethodName = "/rpcpb.ControlService/StreamStatus"
|
||||
ControlService_RemoveNode_FullMethodName = "/rpcpb.ControlService/RemoveNode"
|
||||
ControlService_AddNode_FullMethodName = "/rpcpb.ControlService/AddNode"
|
||||
ControlService_RestartNode_FullMethodName = "/rpcpb.ControlService/RestartNode"
|
||||
ControlService_PauseNode_FullMethodName = "/rpcpb.ControlService/PauseNode"
|
||||
ControlService_ResumeNode_FullMethodName = "/rpcpb.ControlService/ResumeNode"
|
||||
ControlService_Stop_FullMethodName = "/rpcpb.ControlService/Stop"
|
||||
ControlService_AttachPeer_FullMethodName = "/rpcpb.ControlService/AttachPeer"
|
||||
ControlService_SendOutboundMessage_FullMethodName = "/rpcpb.ControlService/SendOutboundMessage"
|
||||
ControlService_SaveSnapshot_FullMethodName = "/rpcpb.ControlService/SaveSnapshot"
|
||||
ControlService_LoadSnapshot_FullMethodName = "/rpcpb.ControlService/LoadSnapshot"
|
||||
ControlService_RemoveSnapshot_FullMethodName = "/rpcpb.ControlService/RemoveSnapshot"
|
||||
ControlService_GetSnapshotNames_FullMethodName = "/rpcpb.ControlService/GetSnapshotNames"
|
||||
)
|
||||
|
||||
// ControlServiceClient is the client API for ControlService service.
|
||||
@@ -141,6 +142,7 @@ type ControlServiceClient interface {
|
||||
Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error)
|
||||
CreateBlockchains(ctx context.Context, in *CreateBlockchainsRequest, opts ...grpc.CallOption) (*CreateBlockchainsResponse, error)
|
||||
TransformElasticSubnets(ctx context.Context, in *TransformElasticSubnetsRequest, opts ...grpc.CallOption) (*TransformElasticSubnetsResponse, error)
|
||||
AddPermissionlessValidator(ctx context.Context, in *AddPermissionlessValidatorRequest, opts ...grpc.CallOption) (*AddPermissionlessValidatorResponse, error)
|
||||
CreateSubnets(ctx context.Context, in *CreateSubnetsRequest, opts ...grpc.CallOption) (*CreateSubnetsResponse, error)
|
||||
Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error)
|
||||
URIs(ctx context.Context, in *URIsRequest, opts ...grpc.CallOption) (*URIsResponse, error)
|
||||
@@ -205,6 +207,15 @@ func (c *controlServiceClient) TransformElasticSubnets(ctx context.Context, in *
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlServiceClient) AddPermissionlessValidator(ctx context.Context, in *AddPermissionlessValidatorRequest, opts ...grpc.CallOption) (*AddPermissionlessValidatorResponse, error) {
|
||||
out := new(AddPermissionlessValidatorResponse)
|
||||
err := c.cc.Invoke(ctx, ControlService_AddPermissionlessValidator_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlServiceClient) CreateSubnets(ctx context.Context, in *CreateSubnetsRequest, opts ...grpc.CallOption) (*CreateSubnetsResponse, error) {
|
||||
out := new(CreateSubnetsResponse)
|
||||
err := c.cc.Invoke(ctx, ControlService_CreateSubnets_FullMethodName, in, out, opts...)
|
||||
@@ -398,6 +409,7 @@ type ControlServiceServer interface {
|
||||
Start(context.Context, *StartRequest) (*StartResponse, error)
|
||||
CreateBlockchains(context.Context, *CreateBlockchainsRequest) (*CreateBlockchainsResponse, error)
|
||||
TransformElasticSubnets(context.Context, *TransformElasticSubnetsRequest) (*TransformElasticSubnetsResponse, error)
|
||||
AddPermissionlessValidator(context.Context, *AddPermissionlessValidatorRequest) (*AddPermissionlessValidatorResponse, error)
|
||||
CreateSubnets(context.Context, *CreateSubnetsRequest) (*CreateSubnetsResponse, error)
|
||||
Health(context.Context, *HealthRequest) (*HealthResponse, error)
|
||||
URIs(context.Context, *URIsRequest) (*URIsResponse, error)
|
||||
@@ -435,6 +447,9 @@ func (UnimplementedControlServiceServer) CreateBlockchains(context.Context, *Cre
|
||||
func (UnimplementedControlServiceServer) TransformElasticSubnets(context.Context, *TransformElasticSubnetsRequest) (*TransformElasticSubnetsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TransformElasticSubnets not implemented")
|
||||
}
|
||||
func (UnimplementedControlServiceServer) AddPermissionlessValidator(context.Context, *AddPermissionlessValidatorRequest) (*AddPermissionlessValidatorResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddPermissionlessValidator not implemented")
|
||||
}
|
||||
func (UnimplementedControlServiceServer) CreateSubnets(context.Context, *CreateSubnetsRequest) (*CreateSubnetsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateSubnets not implemented")
|
||||
}
|
||||
@@ -574,6 +589,24 @@ func _ControlService_TransformElasticSubnets_Handler(srv interface{}, ctx contex
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ControlService_AddPermissionlessValidator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AddPermissionlessValidatorRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServiceServer).AddPermissionlessValidator(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ControlService_AddPermissionlessValidator_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServiceServer).AddPermissionlessValidator(ctx, req.(*AddPermissionlessValidatorRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ControlService_CreateSubnets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateSubnetsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -924,6 +957,10 @@ var ControlService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "TransformElasticSubnets",
|
||||
Handler: _ControlService_TransformElasticSubnets_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "AddPermissionlessValidator",
|
||||
Handler: _ControlService_AddPermissionlessValidator_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateSubnets",
|
||||
Handler: _ControlService_CreateSubnets_Handler,
|
||||
|
||||
@@ -293,6 +293,45 @@ func (lc *localNetwork) CreateChains(
|
||||
return chainIDs, nil
|
||||
}
|
||||
|
||||
func (lc *localNetwork) AddPermissionlessValidator(ctx context.Context, validatorSpecs []network.PermissionlessValidatorSpec) ([]ids.ID, error) {
|
||||
lc.lock.Lock()
|
||||
defer lc.lock.Unlock()
|
||||
|
||||
if len(validatorSpecs) == 0 {
|
||||
ux.Print(lc.log, logging.Orange.Wrap(logging.Bold.Wrap("no validator specs provided...")))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
go func(ctx context.Context) {
|
||||
select {
|
||||
case <-lc.stopCh:
|
||||
// The network is stopped; return from method calls below.
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
// This method is done. Don't leak [ctx].
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
if err := lc.awaitHealthyAndUpdateNetworkInfo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txIDs, err := lc.nw.AddPermissionlessValidator(ctx, validatorSpecs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := lc.awaitHealthyAndUpdateNetworkInfo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ux.Print(lc.log, logging.Green.Wrap(logging.Bold.Wrap("finished adding permissionless validators")))
|
||||
return txIDs, nil
|
||||
}
|
||||
|
||||
func (lc *localNetwork) TransformSubnets(ctx context.Context, elasticSubnetSpecs []network.ElasticSubnetSpec) ([]ids.ID, error) {
|
||||
lc.lock.Lock()
|
||||
defer lc.lock.Unlock()
|
||||
|
||||
+93
-1
@@ -51,7 +51,9 @@ const (
|
||||
defaultStartTimeout = 5 * time.Minute
|
||||
waitForHealthyTimeout = 3 * time.Minute
|
||||
|
||||
networkRootDirPrefix = "network"
|
||||
networkRootDirPrefix = "network"
|
||||
timeParseLayout = "2006-01-02 15:04:05"
|
||||
stakingMinimumLeadTime = 25 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -66,6 +68,7 @@ var (
|
||||
ErrNoBlockchainSpec = errors.New("no blockchain spec was provided")
|
||||
ErrNoSubnetID = errors.New("subnetID is missing")
|
||||
ErrNoElasticSubnetSpec = errors.New("no elastic subnet spec was provided")
|
||||
ErrNoValidatorSpec = errors.New("no elastic subnet spec was provided")
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -519,6 +522,72 @@ func (s *server) CreateBlockchains(
|
||||
return &rpcpb.CreateBlockchainsResponse{ClusterInfo: clusterInfo, ChainIds: strChainIDs}, nil
|
||||
}
|
||||
|
||||
func (s *server) AddPermissionlessValidator(
|
||||
_ context.Context,
|
||||
req *rpcpb.AddPermissionlessValidatorRequest,
|
||||
) (*rpcpb.AddPermissionlessValidatorResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.network == nil {
|
||||
return nil, ErrNotBootstrapped
|
||||
}
|
||||
|
||||
s.log.Debug("AddPermissionlessValidator")
|
||||
|
||||
if len(req.GetValidatorSpec()) == 0 {
|
||||
return nil, ErrNoValidatorSpec
|
||||
}
|
||||
|
||||
validatorSpecList := []network.PermissionlessValidatorSpec{}
|
||||
for _, spec := range req.GetValidatorSpec() {
|
||||
validatorSpec, err := getPermissionlessValidatorSpec(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validatorSpecList = append(validatorSpecList, validatorSpec)
|
||||
}
|
||||
|
||||
// check that the given subnets exist
|
||||
subnetsSet := set.Set[string]{}
|
||||
subnetsSet.Add(maps.Keys(s.clusterInfo.Subnets)...)
|
||||
|
||||
for _, validatorSpec := range validatorSpecList {
|
||||
if validatorSpec.SubnetID == nil {
|
||||
return nil, ErrNoSubnetID
|
||||
} else if !subnetsSet.Contains(*validatorSpec.SubnetID) {
|
||||
return nil, fmt.Errorf("subnet id %q does not exist", *validatorSpec.SubnetID)
|
||||
}
|
||||
}
|
||||
|
||||
s.clusterInfo.Healthy = false
|
||||
s.clusterInfo.CustomChainsHealthy = false
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), waitForHealthyTimeout)
|
||||
defer cancel()
|
||||
txIDs, err := s.network.AddPermissionlessValidator(ctx, validatorSpecList)
|
||||
|
||||
s.updateClusterInfo()
|
||||
|
||||
if err != nil {
|
||||
s.log.Error("failed to add permissionless validator", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.log.Info("successfully added permissionless validator")
|
||||
|
||||
strTXIDs := []string{}
|
||||
for _, txID := range txIDs {
|
||||
strTXIDs = append(strTXIDs, txID.String())
|
||||
}
|
||||
|
||||
clusterInfo, err := deepCopy(s.clusterInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rpcpb.AddPermissionlessValidatorResponse{ClusterInfo: clusterInfo, TxIds: strTXIDs}, nil
|
||||
}
|
||||
|
||||
func (s *server) TransformElasticSubnets(
|
||||
_ context.Context,
|
||||
req *rpcpb.TransformElasticSubnetsRequest,
|
||||
@@ -1257,6 +1326,29 @@ func getNetworkElasticSubnetSpec(
|
||||
return elasticSubnetSpec
|
||||
}
|
||||
|
||||
func getPermissionlessValidatorSpec(
|
||||
spec *rpcpb.PermissionlessValidatorSpec,
|
||||
) (network.PermissionlessValidatorSpec, error) {
|
||||
startTime, err := time.Parse(timeParseLayout, spec.StartTime)
|
||||
if err != nil {
|
||||
return network.PermissionlessValidatorSpec{}, err
|
||||
}
|
||||
if startTime.Before(time.Now().Add(stakingMinimumLeadTime)) {
|
||||
return network.PermissionlessValidatorSpec{}, fmt.Errorf("time should be at least %s in the future for validator spec of %s", stakingMinimumLeadTime, spec.NodeId)
|
||||
}
|
||||
stakeDuration := time.Duration(spec.StakeDuration) * time.Hour
|
||||
|
||||
validatorSpec := network.PermissionlessValidatorSpec{
|
||||
SubnetID: &spec.SubnetId,
|
||||
AssetID: spec.AssetId,
|
||||
NodeID: spec.NodeId,
|
||||
StakedAmount: spec.StakedTokenAmount,
|
||||
StartTime: startTime,
|
||||
StakeDuration: stakeDuration,
|
||||
}
|
||||
return validatorSpec, nil
|
||||
}
|
||||
|
||||
func getNetworkBlockchainSpec(
|
||||
log logging.Logger,
|
||||
spec *rpcpb.BlockchainSpec,
|
||||
|
||||
Reference in New Issue
Block a user