Skip to content

Commit

Permalink
add get_pubkeys_from_mnemonic task
Browse files Browse the repository at this point in the history
  • Loading branch information
pk910 committed Oct 2, 2024
1 parent 0e9670c commit fd33eed
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
32 changes: 32 additions & 0 deletions pkg/coordinator/tasks/get_pubkeys_from_mnemonic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## `get_pubkeys_from_mnemonic` Task

### Description
The `get_pubkeys_from_mnemonic` task generates public keys from a given mnemonic phrase. This task is essential for setting up and verifying validator identities in scenarios involving multiple validators derived from a single mnemonic, commonly used in Ethereum staking operations.

### Configuration Parameters

- **`mnemonic`**:
The mnemonic phrase used to generate the public keys. This should be a BIP-39 compliant seed phrase that is used to derive Ethereum validator keys.

- **`start_index`**:
The starting index from which to begin deriving public keys. This allows users to specify a segment of the key sequence for generation, rather than starting from the beginning.

- **`count`**:
The number of public keys to generate from the specified `start_index`.

### Outputs

- **`pubkeys`**:
A list of validator public keys derived from the mnemonic. Each key corresponds to a validator index starting from the `start_index` and continuing for `count` keys. This output is crucial for tasks that involve setting up validators, validating identities, or performing any operation that requires public key data.

### Defaults

Default settings for the `get_pubkeys_from_mnemonic` task:

```yaml
- name: get_pubkeys_from_mnemonic
config:
mnemonic: ""
start_index: 0
count: 1
```
23 changes: 23 additions & 0 deletions pkg/coordinator/tasks/get_pubkeys_from_mnemonic/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package getpubkeysfrommnemonic

import "fmt"

type Config struct {
Mnemonic string `yaml:"mnemonic" json:"mnemonic"`
StartIndex int `yaml:"start_index" json:"start_index"`
Count int `yaml:"count" json:"count"`
}

func DefaultConfig() Config {
return Config{
Count: 1,
}
}

func (c *Config) Validate() error {
if c.Mnemonic == "" {
return fmt.Errorf("mnemonic is required")
}

return nil
}
103 changes: 103 additions & 0 deletions pkg/coordinator/tasks/get_pubkeys_from_mnemonic/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package getpubkeysfrommnemonic

import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/ethpandaops/assertoor/pkg/coordinator/types"
"github.com/sirupsen/logrus"
"github.com/tyler-smith/go-bip39"
util "github.com/wealdtech/go-eth2-util"
)

var (
TaskName = "get_pubkeys_from_mnemonic"
TaskDescriptor = &types.TaskDescriptor{
Name: TaskName,
Description: "Get public keys from mnemonic",
Config: DefaultConfig(),
NewTask: NewTask,
}
)

type Task struct {
ctx *types.TaskContext
options *types.TaskOptions
config Config
logger logrus.FieldLogger
}

func NewTask(ctx *types.TaskContext, options *types.TaskOptions) (types.Task, error) {
return &Task{
ctx: ctx,
options: options,
logger: ctx.Logger.GetLogger(),
}, nil
}

func (t *Task) Config() interface{} {
return t.config
}

func (t *Task) Timeout() time.Duration {
return t.options.Timeout.Duration
}

func (t *Task) LoadConfig() error {
config := DefaultConfig()

// parse static config
if t.options.Config != nil {
if err := t.options.Config.Unmarshal(&config); err != nil {
return fmt.Errorf("error parsing task config for %v: %w", TaskName, err)
}
}

// load dynamic vars
err := t.ctx.Vars.ConsumeVars(&config, t.options.ConfigVars)
if err != nil {
return err
}

// validate config
if err := config.Validate(); err != nil {
return err
}

t.config = config

return nil
}

func (t *Task) Execute(_ context.Context) error {
mnemonic := strings.TrimSpace(t.config.Mnemonic)
if !bip39.IsMnemonicValid(mnemonic) {
return errors.New("mnemonic is not valid")
}

seed := bip39.NewSeed(mnemonic, "")
pubkeys := make([]string, 0, t.config.Count)

for index := t.config.StartIndex; index < t.config.StartIndex+t.config.Count; index++ {
validatorKeyPath := fmt.Sprintf("m/12381/3600/%d/0/0", index)

validatorPriv, err := util.PrivateKeyFromSeedAndPath(seed, validatorKeyPath)
if err != nil {
return fmt.Errorf("failed generating validator key %v: %w", validatorKeyPath, err)
}

validatorPubkey := validatorPriv.PublicKey().Marshal()
pubkey := fmt.Sprintf("0x%x", validatorPubkey)

t.logger.Infof("Generated pubkey %v: %v", index, pubkey)

pubkeys = append(pubkeys, pubkey)
}

t.ctx.Outputs.SetVar("pubkeys", pubkeys)

return nil
}
2 changes: 2 additions & 0 deletions pkg/coordinator/tasks/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
generateslashings "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/generate_slashings"
generatetransaction "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/generate_transaction"
getconsensusspecs "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/get_consensus_specs"
getpubkeysfrommnemonic "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/get_pubkeys_from_mnemonic"
getrandommnemonic "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/get_random_mnemonic"
getwalletdetails "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/get_wallet_details"
runcommand "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/run_command"
Expand Down Expand Up @@ -56,6 +57,7 @@ var AvailableTaskDescriptors = []*types.TaskDescriptor{
generateexits.TaskDescriptor,
generateslashings.TaskDescriptor,
generatetransaction.TaskDescriptor,
getpubkeysfrommnemonic.TaskDescriptor,
getconsensusspecs.TaskDescriptor,
getrandommnemonic.TaskDescriptor,
getwalletdetails.TaskDescriptor,
Expand Down

0 comments on commit fd33eed

Please sign in to comment.