Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions client/obol.go
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)
}
75 changes: 75 additions & 0 deletions rocketpool-cli/commands/obol/cluster.go
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
}

103 changes: 103 additions & 0 deletions rocketpool-cli/commands/obol/commands.go
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)
},
}
},
})
}
45 changes: 45 additions & 0 deletions rocketpool-cli/commands/obol/dv-exit.go
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
}

27 changes: 27 additions & 0 deletions rocketpool-cli/commands/obol/public-keys.go
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
}
82 changes: 82 additions & 0 deletions rocketpool-daemon/api/obol/charon-dkg-handler.go
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),

Choose a reason for hiding this comment

The 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

Choose a reason for hiding this comment

The 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?
If so, we should include options here that can tweak this command (i.e.: use different charon version, publish to different URL, use different dirs, etc.).


output, err := cmd.CombinedOutput()

if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("Error running docker command: %s", err)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return types.ResponseStatus_Error, fmt.Errorf("Error running docker command: %s", err)
return types.ResponseStatus_Error, fmt.Errorf("Error running docker command: %w", err)

Better one for errors

}
log.Printf("Command output: %s", string(output))
return types.ResponseStatus_Success, nil
}

Loading