-
Notifications
You must be signed in to change notification settings - Fork 0
feat: added Obol commands #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package client | ||
|
|
||
| import ( | ||
| "github.com/rocket-pool/node-manager-core/api/client" | ||
| "github.com/rocket-pool/node-manager-core/api/types" | ||
| "github.com/rocket-pool/smartnode/v2/shared/types/api" | ||
| ) | ||
|
|
||
| type ObolRequester struct { | ||
| context client.IRequesterContext | ||
| } | ||
|
|
||
| func NewObolRequester(context client.IRequesterContext) *ObolRequester { | ||
| return &ObolRequester{ | ||
| context: context, | ||
| } | ||
| } | ||
|
|
||
| func (r *ObolRequester) GetName() string { | ||
| return "DvTest" | ||
| } | ||
| func (r *ObolRequester) GetRoute() string { | ||
| return "dvtest" | ||
| } | ||
| func (r *ObolRequester) GetContext() client.IRequesterContext { | ||
| return r.context | ||
| } | ||
|
|
||
| // Trigger a DV exit broadcast | ||
| func (r *ObolRequester) DvExitBroadcast() (*types.ApiResponse[api.DvExitBroadcastData], error) { | ||
| return client.SendGetRequest[api.DvExitBroadcastData](r, "obol/dv-exit-broadcast", "DvExitBroadcast", nil) | ||
| } | ||
|
|
||
| // Trigger a DV exit sign | ||
| func (r *ObolRequester) DvExitSign() (*types.ApiResponse[api.DvExitSignData], error) { | ||
| return client.SendGetRequest[api.DvExitSignData](r, "obol/dv-exit-sign", "DvExitSign", nil) | ||
| } | ||
|
|
||
| // Retrieve validator public keys | ||
| func (r *ObolRequester) GetValidatorPublicKeys() (*types.ApiResponse[api.GetValidatorPublicKeysData], error) { | ||
| return client.SendGetRequest[api.GetValidatorPublicKeysData](r, "obol/get-validator-public-keys", "GetValidatorPublicKeys", nil) | ||
| } | ||
|
|
||
| // Creates cluster - DKG | ||
| func (r *ObolRequester) CharonDkg() (*types.ApiResponse[api.CharonDkgData], error) { | ||
| return client.SendGetRequest[api.CharonDkgData](r, "obol/charon-dkg", "CharonDkg", nil) | ||
| } | ||
|
|
||
| // Creates ENR | ||
| func (r *ObolRequester) CreateENR() (*types.ApiResponse[api.CreateENRData], error) { | ||
| return client.SendGetRequest[api.CreateENRData](r, "obol/create-enr", "CreateENR", nil) | ||
| } | ||
|
|
||
| // Manages Charon service | ||
| func (r *ObolRequester) ManageCharonService() (*types.ApiResponse[api.ManageCharonServiceData], error) { | ||
| return client.SendGetRequest[api.ManageCharonServiceData](r, "obol/manage-charon-service", "ManageCharonService", nil) | ||
| } | ||
|
|
||
| // Retrieve Charon service health | ||
| func (r *ObolRequester) GetCharonHealth() (*types.ApiResponse[api.GetCharonHealthData], error) { | ||
| return client.SendGetRequest[api.GetCharonHealthData](r, "obol/get-charon-health", "GetCharonHealth", nil) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package obol | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/urfave/cli/v2" | ||
|
|
||
| "github.com/rocket-pool/smartnode/v2/rocketpool-cli/client" | ||
| "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils/tx" | ||
| ) | ||
|
|
||
| func charonDkg(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| response, err := rp.Api.Obol.CharonDkg() | ||
| if err != nil { | ||
| return fmt.Errorf("Error creating a DV cluster: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully triggered cluster DKG creation.") | ||
| return nil | ||
| } | ||
|
|
||
| func createENR(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| response, err := rp.Api.Obol.CreateENR() | ||
| if err != nil { | ||
| return fmt.Errorf("Error creating ENR: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully created ENR") | ||
| return nil | ||
| } | ||
|
|
||
| func manageCharonService(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| response, err := rp.Api.Obol.ManageCharonService() | ||
| if err != nil { | ||
| return fmt.Errorf("Error managinig charon service: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully updated Charon service state") | ||
| return nil | ||
| } | ||
|
|
||
| func getCharonHealth(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| response, err := rp.Api.Obol.GetCharonHealth() | ||
| if err != nil { | ||
| return fmt.Errorf("Error fetching charon health: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully fetched charon health") | ||
| return nil | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| package obol | ||
|
|
||
| import ( | ||
| "github.com/urfave/cli/v2" | ||
|
|
||
| cliutils "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils" | ||
| "github.com/rocket-pool/smartnode/v2/shared/utils" | ||
| ) | ||
|
|
||
| // Register commands | ||
| func RegisterCommands(app *cli.App, name string, aliases []string) { | ||
| app.Commands = append(app.Commands, &cli.Command{ | ||
| Name: name, | ||
| Aliases: aliases, | ||
| Usage: "Manage Obol Distributed Validator", | ||
| Subcommands: []*cli.Command{ | ||
| { | ||
| Name: "health", | ||
| Aliases: []string{"h"}, | ||
| Usage: "Get Charon service health", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return getCharonHealth(c) | ||
| }, | ||
| }, | ||
| { | ||
| Name: "manage-charon-service", | ||
| Aliases: []string{"s"}, | ||
| Usage: "Start, stop or restart the Charon service", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return manageCharonService(c) | ||
| }, | ||
| }, | ||
| { | ||
| Name: "create-enr", | ||
| Aliases: []string{"n"}, | ||
| Usage: "Create ENR for a Charon client", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return createENR(c) | ||
| }, | ||
| }, | ||
| { | ||
| Name: "charon-dkg", | ||
| Aliases: []string{"d"}, | ||
| Usage: "Run the Distributed Key Generation (DKG) ceremony", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return runCharonDkg(c) | ||
| }, | ||
| }, | ||
| { | ||
| Name: "get-validator-public-keys", | ||
| Aliases: []string{"k"}, | ||
| Usage: "Retrieves validator public keys", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return getValidatorPublicKeys(c) | ||
| }, | ||
| }, | ||
| { | ||
| Name: "dv-exit-sign", | ||
| Aliases: []string{"e"}, | ||
| Usage: "Sign a partial DV exit", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return dvExitSign(c) | ||
| }, | ||
| }, | ||
| { | ||
| Name: "dv-exit-broadcast", | ||
| Aliases: []string{"b"}, | ||
| Usage: "Publish a DV exit", | ||
| Action: func(c *cli.Context) error { | ||
| // Validate args | ||
| utils.ValidateArgCount(c, 0) | ||
|
|
||
| // Run | ||
| return dvExitBroadcast(c) | ||
| }, | ||
| } | ||
| }, | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package obol | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/urfave/cli/v2" | ||
|
|
||
| "github.com/rocket-pool/smartnode/v2/rocketpool-cli/client" | ||
| "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils/tx" | ||
| ) | ||
|
|
||
| func dvExitBroadcast(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Check lot can be created | ||
| response, err := rp.Api.Obol.DvExitBroadcast() | ||
| if err != nil { | ||
| return fmt.Errorf("Error triggering broadcast for a DV exit: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully triggered DV exit broadcast.") | ||
| return nil | ||
| } | ||
|
|
||
| func dvExitSign(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Check lot can be created | ||
| response, err := rp.Api.Obol.DvExitSign() | ||
| if err != nil { | ||
| return fmt.Errorf("Error signing for a DV exit: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully signed for a DV exit.") | ||
| return nil | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package obol | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/urfave/cli/v2" | ||
|
|
||
| "github.com/rocket-pool/smartnode/v2/rocketpool-cli/client" | ||
| "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils/tx" | ||
| ) | ||
|
|
||
| func getValidatorPublicKeys(c *cli.Context) error { | ||
| // Get RP client | ||
| rp, err := client.NewClientFromCtx(c) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Check lot can be created | ||
| response, err := rp.Api.Obol.GetValidatorPublicKeys() | ||
| if err != nil { | ||
| return fmt.Errorf("Error fetching validator public keys: %w", err) | ||
| } | ||
| // Log & return | ||
| fmt.Println("Successfully fetched validator public keys.") | ||
| return nil | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,82 @@ | ||||||||
| package obol | ||||||||
|
|
||||||||
| import ( | ||||||||
| "fmt" | ||||||||
| "net/url" | ||||||||
|
|
||||||||
| "log" | ||||||||
|
|
||||||||
| "os/exec" | ||||||||
|
|
||||||||
| "github.com/ethereum/go-ethereum/accounts/abi/bind" | ||||||||
| "github.com/gorilla/mux" | ||||||||
| batch "github.com/rocket-pool/batch-query" | ||||||||
| "github.com/rocket-pool/rocketpool-go/v2/rocketpool" | ||||||||
|
|
||||||||
| "github.com/rocket-pool/node-manager-core/api/server" | ||||||||
| "github.com/rocket-pool/node-manager-core/api/types" | ||||||||
| "github.com/rocket-pool/smartnode/v2/shared/types/api" | ||||||||
| ) | ||||||||
|
|
||||||||
| // =============== | ||||||||
| // === Factory === | ||||||||
| // =============== | ||||||||
|
|
||||||||
| type CharonDkgContextFactory struct { | ||||||||
| handler *ObolHandler | ||||||||
| } | ||||||||
|
|
||||||||
| func (f *CharonDkgContextFactory) Create(args url.Values) (*CharonDkgContext, error) { | ||||||||
| c := &CharonDkgContext{ | ||||||||
| handler: f.handler, | ||||||||
| } | ||||||||
| return c, nil | ||||||||
| } | ||||||||
|
|
||||||||
| func (f *CharonDkgContextFactory) RegisterRoute(router *mux.Router) { | ||||||||
| server.RegisterSingleStageRoute[*CharonDkgContext, api.CharonDkgData]( | ||||||||
| router, "obol/charon-dkg", f, f.handler.logger.Logger, f.handler.serviceProvider.ServiceProvider, | ||||||||
| ) | ||||||||
| } | ||||||||
|
|
||||||||
| // =============== | ||||||||
| // === Context === | ||||||||
| // =============== | ||||||||
|
|
||||||||
| type CharonDkgContext struct { | ||||||||
| handler *ObolHandler | ||||||||
| rp *rocketpool.RocketPool | ||||||||
|
|
||||||||
| password string | ||||||||
| } | ||||||||
|
|
||||||||
| func (c *CharonDkgContext) Initialize() (types.ResponseStatus, error) { | ||||||||
| sp := c.handler.serviceProvider | ||||||||
| c.rp = sp.GetRocketPool() | ||||||||
|
|
||||||||
| // Requirements | ||||||||
| status, err := sp.RequireNodeRegistered(c.handler.ctx) | ||||||||
| if err != nil { | ||||||||
| return status, err | ||||||||
| } | ||||||||
|
|
||||||||
| return types.ResponseStatus_Success, nil | ||||||||
| } | ||||||||
|
|
||||||||
| func (c *CharonDkgContext) PrepareData(data *api.CharonDkgData, opts *bind.TransactOpts) (types.ResponseStatus, error) { | ||||||||
| cmd := exec.Command( | ||||||||
| "docker", "run", "--rm", | ||||||||
| "-v", fmt.Sprintf("%s:/opt/charon", c.password), | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is there a password here? This is supposed to be a directory at the host's machine, shouldn't be anything related to a password? |
||||||||
| "obolnetwork/charon:v1.1.0", | ||||||||
| "dkg", "--publish", | ||||||||
| ) | ||||||||
|
Comment on lines
+67
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we assume everyone is running this on a machine that has docker and wants to run it with docker? |
||||||||
|
|
||||||||
| output, err := cmd.CombinedOutput() | ||||||||
|
|
||||||||
| if err != nil { | ||||||||
| return types.ResponseStatus_Error, fmt.Errorf("Error running docker command: %s", err) | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Better one for errors |
||||||||
| } | ||||||||
| log.Printf("Command output: %s", string(output)) | ||||||||
| return types.ResponseStatus_Success, nil | ||||||||
| } | ||||||||
|
|
||||||||
Uh oh!
There was an error while loading. Please reload this page.