mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-10 14:37:57 -05:00
Compare commits
12 Commits
v1.26.5
...
v1.27.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12f3154157 | ||
|
|
51689db315 | ||
|
|
1a8897ff0f | ||
|
|
5ee92bee78 | ||
|
|
eba7a0c88a | ||
|
|
f6a6224968 | ||
|
|
60e8878dc3 | ||
|
|
41d9160b63 | ||
|
|
b3d4c9af08 | ||
|
|
5a8a13d8f3 | ||
|
|
d94e1551a7 | ||
|
|
03e7f15d04 |
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
go build -tags osusergo,netgo -ldflags="-extldflags=-static" -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }}"
|
||||
go build -tags osusergo,netgo -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }} -extldflags -static"
|
||||
tar zcf ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-linux-amd64.tar.gz ${{ needs.env_vars.outputs.binary }}
|
||||
sha256sum ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-linux-amd64.tar.gz | sed -e 's/ .*//' >${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-linux-amd64.tar.gz.sha256
|
||||
- name: Upload binary
|
||||
@@ -84,8 +84,10 @@ jobs:
|
||||
|
||||
- name: Cross compile (ARM64)
|
||||
run: |
|
||||
apt install -y gcc-aarch64-linux-gnu libstdc++-12-pic-arm64-cross
|
||||
CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 go build -tags osusergo,netgo -ldflags="-extldflags=-static" -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }}"
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo apt install -y gcc-aarch64-linux-gnu libstdc++-11-pic-arm64-cross
|
||||
CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 go build -tags osusergo,netgo -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }} -extldflags -static"
|
||||
tar zcf ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-linux-arm64.tar.gz ${{ needs.env_vars.outputs.binary }}
|
||||
sha256sum ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-linux-arm64.tar.gz | sed -e 's/ .*//' >${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-linux-arm64.tar.gz.sha256
|
||||
|
||||
@@ -130,7 +132,7 @@ jobs:
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
go build -tags osusergo,netgo -ldflags="-extldflags=-static" -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }}"
|
||||
go build -tags osusergo,netgo -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }}"
|
||||
tar zcf ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-darwin-amd64.tar.gz ${{ needs.env_vars.outputs.binary }}
|
||||
brew install coreutils
|
||||
sha256sum ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-darwin-amd64.tar.gz | sed -e 's/ .*//' >${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-darwin-amd64.tar.gz.sha256
|
||||
@@ -175,7 +177,7 @@ jobs:
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
go build -tags osusergo,netgo -ldflags="-extldflags=-static" -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }}"
|
||||
go build -v -ldflags="-X github.com/${{ github.repository }}/cmd.ReleaseVersion=${{ needs.env_vars.outputs.release_version }} -extldflags -static"
|
||||
choco install zip
|
||||
zip --junk-paths ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-windows-exe.zip ${{ needs.env_vars.outputs.binary }}.exe
|
||||
$FileHash=(certutil -hashfile ${{ needs.env_vars.outputs.binary }}-${{ needs.env_vars.outputs.release_version }}-windows-exe.zip SHA256 | findstr /v hash | findstr /v SHA).replace(" ", "")
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
dev:
|
||||
- use new build system
|
||||
- support S3 credentials
|
||||
|
||||
1.26.5:
|
||||
- provide validator information in "chain status" verbose output
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.17-bullseye as builder
|
||||
FROM golang:1.18-bullseye as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ func init() {
|
||||
if err := viper.BindPFlag("debug", RootCmd.PersistentFlags().Lookup("debug")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
RootCmd.PersistentFlags().String("connection", "", "URL to an Ethereum 2 node's RET API endpoint")
|
||||
RootCmd.PersistentFlags().String("connection", "", "URL to an Ethereum 2 node's REST API endpoint")
|
||||
if err := viper.BindPFlag("connection", RootCmd.PersistentFlags().Lookup("connection")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ type command struct {
|
||||
|
||||
// Input.
|
||||
account string
|
||||
withdrawalAccount string
|
||||
passphrases []string
|
||||
mnemonic string
|
||||
path string
|
||||
@@ -62,7 +63,7 @@ type command struct {
|
||||
signedOperations []*capella.SignedBLSToExecutionChange
|
||||
}
|
||||
|
||||
func newCommand(ctx context.Context) (*command, error) {
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
@@ -74,6 +75,7 @@ func newCommand(ctx context.Context) (*command, error) {
|
||||
allowInsecureConnections: viper.GetBool("allow-insecure-connections"),
|
||||
prepareOffline: viper.GetBool("prepare-offline"),
|
||||
account: viper.GetString("account"),
|
||||
withdrawalAccount: viper.GetString("withdrawal-account"),
|
||||
passphrases: util.GetPassphrases(),
|
||||
mnemonic: viper.GetString("mnemonic"),
|
||||
path: viper.GetString("path"),
|
||||
@@ -96,8 +98,8 @@ func newCommand(ctx context.Context) (*command, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
if c.account != "" && len(c.passphrases) == 0 {
|
||||
return nil, errors.New("passphrase required with account")
|
||||
if c.withdrawalAccount != "" && len(c.passphrases) == 0 {
|
||||
return nil, errors.New("passphrase required with withdrawal-account")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
||||
@@ -22,7 +22,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *command) output(ctx context.Context) (string, error) {
|
||||
//nolint:unparam
|
||||
func (c *command) output(_ context.Context) (string, error) {
|
||||
if c.quiet {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -43,24 +43,6 @@ var offlinePreparationFilename = "offline-preparation.json"
|
||||
var changeOperationsFilename = "change-operations.json"
|
||||
|
||||
func (c *command) process(ctx context.Context) error {
|
||||
// We should have exactly 1 specifier to know what we're working with.
|
||||
validatorSpecifiers := 0
|
||||
if c.validator != "" {
|
||||
validatorSpecifiers++
|
||||
}
|
||||
if c.mnemonic != "" {
|
||||
validatorSpecifiers++
|
||||
}
|
||||
if c.privateKey != "" {
|
||||
validatorSpecifiers++
|
||||
}
|
||||
if validatorSpecifiers == 0 {
|
||||
return errors.New("one of validator, mmenomic or private key should be specified")
|
||||
}
|
||||
if validatorSpecifiers > 1 {
|
||||
return errors.New("only one of validator, mmenomic or private key should be specified")
|
||||
}
|
||||
|
||||
if err := c.setup(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -82,6 +64,9 @@ func (c *command) process(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if c.json || c.offline {
|
||||
if c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Not broadcasting credentials change operations\n")
|
||||
}
|
||||
// Want JSON output, or cannot broadcast.
|
||||
return nil
|
||||
}
|
||||
@@ -118,7 +103,7 @@ func (c *command) obtainRequiredInformation(ctx context.Context) error {
|
||||
// populateChainInfo populates chain info structure from a beacon node.
|
||||
func (c *command) populateChainInfo(ctx context.Context) error {
|
||||
if c.debug {
|
||||
fmt.Printf("Populating chain info from beacon node\n")
|
||||
fmt.Fprintf(os.Stderr, "Populating chain info from beacon node\n")
|
||||
}
|
||||
|
||||
// Obtain validators.
|
||||
@@ -155,7 +140,7 @@ func (c *command) populateChainInfo(ctx context.Context) error {
|
||||
c.chainInfo.GenesisValidatorsRoot = genesis.GenesisValidatorsRoot
|
||||
}
|
||||
if c.debug {
|
||||
fmt.Printf("Genesis validators root is %#x\n", c.chainInfo.GenesisValidatorsRoot)
|
||||
fmt.Fprintf(os.Stderr, "Genesis validators root is %#x\n", c.chainInfo.GenesisValidatorsRoot)
|
||||
}
|
||||
|
||||
// Obtain epoch.
|
||||
@@ -163,49 +148,16 @@ func (c *command) populateChainInfo(ctx context.Context) error {
|
||||
|
||||
// Obtain fork version.
|
||||
if c.forkVersion != "" {
|
||||
// Fork version supplied manually.
|
||||
forkVersion, err := hex.DecodeString(strings.TrimPrefix(c.forkVersion, "0x"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid fork version supplied")
|
||||
if err := c.populateChainInfoForkVersionFromInput(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(forkVersion) != phase0.ForkVersionLength {
|
||||
return errors.New("invalid length for fork version")
|
||||
}
|
||||
copy(c.chainInfo.ForkVersion[:], forkVersion)
|
||||
} else {
|
||||
// Fork version obtained from beacon node.
|
||||
forkSchedule, err := c.consensusClient.(consensusclient.ForkScheduleProvider).ForkSchedule(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to obtain fork schedule")
|
||||
}
|
||||
if len(forkSchedule) == 0 {
|
||||
return errors.New("beacon node did not provide any fork schedule; provide manually with --fork-version")
|
||||
}
|
||||
if c.debug {
|
||||
fmt.Printf("Genesis fork version is %#x\n", forkSchedule[0].CurrentVersion)
|
||||
}
|
||||
if len(forkSchedule) < 4 {
|
||||
return errors.New("beacon node not providing capella fork schedule; provide manually with --fork-version")
|
||||
}
|
||||
for i := range forkSchedule {
|
||||
// Need to be at least fork 3 (i.e. capella)
|
||||
if i < 3 {
|
||||
continue
|
||||
}
|
||||
if i == 3 {
|
||||
// Force use of capella even if we aren't there yet, to allow credential
|
||||
// change operations to be signed in advance with a signature that will be
|
||||
// valid once capella goes live.
|
||||
c.chainInfo.ForkVersion = forkSchedule[i].CurrentVersion
|
||||
continue
|
||||
}
|
||||
if forkSchedule[i].Epoch <= c.chainInfo.Epoch {
|
||||
c.chainInfo.ForkVersion = forkSchedule[i].CurrentVersion
|
||||
}
|
||||
if err := c.populateChainInfoForkVersionFromChain(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.debug {
|
||||
fmt.Printf("Fork version is %#x\n", c.chainInfo.ForkVersion)
|
||||
fmt.Fprintf(os.Stderr, "Fork version is %#x\n", c.chainInfo.ForkVersion)
|
||||
}
|
||||
|
||||
// Calculate domain.
|
||||
@@ -217,13 +169,71 @@ func (c *command) populateChainInfo(ctx context.Context) error {
|
||||
if !exists {
|
||||
return errors.New("failed to obtain DOMAIN_BLS_TO_EXECUTION_CHANGE")
|
||||
}
|
||||
domainProvider, isProvider := c.consensusClient.(consensusclient.DomainProvider)
|
||||
if !isProvider {
|
||||
return errors.New("consensus node does not provide domain information")
|
||||
if c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Domain type is %#x\n", domainType)
|
||||
}
|
||||
c.chainInfo.Domain, err = domainProvider.Domain(ctx, domainType, c.chainInfo.Epoch)
|
||||
copy(c.chainInfo.Domain[:], domainType[:])
|
||||
|
||||
root, err := (&phase0.ForkData{
|
||||
CurrentVersion: c.chainInfo.ForkVersion,
|
||||
GenesisValidatorsRoot: c.chainInfo.GenesisValidatorsRoot,
|
||||
}).HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to obtain domain")
|
||||
return errors.Wrap(err, "failed to calculate signature domain")
|
||||
}
|
||||
copy(c.chainInfo.Domain[4:], root[:])
|
||||
|
||||
if c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Domain is %#x\n", c.chainInfo.Domain)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) populateChainInfoForkVersionFromInput(_ context.Context) error {
|
||||
// Fork version supplied manually.
|
||||
forkVersion, err := hex.DecodeString(strings.TrimPrefix(c.forkVersion, "0x"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid fork version supplied")
|
||||
}
|
||||
if len(forkVersion) != phase0.ForkVersionLength {
|
||||
return errors.New("invalid length for fork version")
|
||||
}
|
||||
copy(c.chainInfo.ForkVersion[:], forkVersion)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) populateChainInfoForkVersionFromChain(ctx context.Context) error {
|
||||
// Fetch the capella fork version from the specification.
|
||||
spec, err := c.consensusClient.(consensusclient.SpecProvider).Spec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to obtain spec")
|
||||
}
|
||||
tmp, exists := spec["CAPELLA_FORK_VERSION"]
|
||||
if !exists {
|
||||
return errors.New("capella fork version not known by chain")
|
||||
}
|
||||
capellaForkVersion, isForkVersion := tmp.(phase0.Version)
|
||||
if !isForkVersion {
|
||||
//nolint:revive
|
||||
return errors.New("CAPELLA_FORK_VERSION is not a fork version!")
|
||||
}
|
||||
c.chainInfo.ForkVersion = capellaForkVersion
|
||||
|
||||
// Work through the fork schedule to find the latest current fork post-Capella.
|
||||
forkSchedule, err := c.consensusClient.(consensusclient.ForkScheduleProvider).ForkSchedule(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to obtain fork schedule")
|
||||
}
|
||||
foundCapella := false
|
||||
for i := range forkSchedule {
|
||||
if foundCapella && forkSchedule[i].Epoch <= c.chainInfo.Epoch {
|
||||
c.chainInfo.ForkVersion = forkSchedule[i].CurrentVersion
|
||||
}
|
||||
if bytes.Equal(forkSchedule[i].CurrentVersion[:], capellaForkVersion[:]) {
|
||||
foundCapella = true
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -231,7 +241,7 @@ func (c *command) populateChainInfo(ctx context.Context) error {
|
||||
|
||||
// dumpRequiredInformation prepares for an offline run of this command by dumping
|
||||
// the chain information to a file.
|
||||
func (c *command) dumpRequiredInformation(ctx context.Context) error {
|
||||
func (c *command) dumpRequiredInformation(_ context.Context) error {
|
||||
data, err := json.Marshal(c.chainInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -244,7 +254,7 @@ func (c *command) dumpRequiredInformation(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (c *command) generateOperations(ctx context.Context) error {
|
||||
if c.account == "" && c.mnemonic == "" && c.privateKey == "" {
|
||||
if c.account == "" && c.mnemonic == "" && c.privateKey == "" && c.validator == "" {
|
||||
// No input information; fetch the operations from a file.
|
||||
if err := c.loadOperations(ctx); err == nil {
|
||||
return nil
|
||||
@@ -252,47 +262,53 @@ func (c *command) generateOperations(ctx context.Context) error {
|
||||
return fmt.Errorf("no account, mnemonic or private key specified and no %s file found; cannot proceed", changeOperationsFilename)
|
||||
}
|
||||
|
||||
if c.mnemonic != "" && c.path == "" {
|
||||
// Have a mnemonic and no path; scan mnemonic.
|
||||
return c.generateOperationsFromMnemonic(ctx)
|
||||
if c.mnemonic != "" {
|
||||
switch {
|
||||
case c.path != "":
|
||||
// Have a mnemonic and path.
|
||||
return c.generateOperationsFromMnemonicAndPath(ctx)
|
||||
case c.validator != "":
|
||||
// Have a mnemonic and validator.
|
||||
return c.generateOperationsFromMnemonicAndValidator(ctx)
|
||||
case c.privateKey != "":
|
||||
// Have a mnemonic and a private key for the withdrawal address.
|
||||
return c.generateOperationsFromMnemonicAndPrivateKey(ctx)
|
||||
default:
|
||||
// Have a mnemonic and nothing else; scan.
|
||||
return c.generateOperationsFromMnemonic(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if c.mnemonic != "" && c.path != "" {
|
||||
// Have a mnemonic and path.
|
||||
return c.generateOperationsFromMnemonicAndPath(ctx)
|
||||
if c.account != "" {
|
||||
switch {
|
||||
case c.withdrawalAccount != "":
|
||||
// Have an account and a withdrawal account.
|
||||
return c.generateOperationsFromAccountAndWithdrawalAccount(ctx)
|
||||
case c.privateKey != "":
|
||||
// Have an account and a private key for the withdrawal address.
|
||||
return c.generateOperationsFromAccountAndPrivateKey(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Have a validator index or public key ; fetch the validator info.
|
||||
validatorInfo, err := c.fetchValidatorInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
if c.validator != "" && c.privateKey != "" {
|
||||
// Have a validator and a private key for the withdrawal address.
|
||||
return c.generateOperationsFromValidatorAndPrivateKey(ctx)
|
||||
}
|
||||
|
||||
// Fetch the individual account.
|
||||
withdrawalAccount, err := c.fetchAccount(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate the operation.
|
||||
if err := c.generateOperationFromAccount(ctx, validatorInfo, withdrawalAccount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.New("unsupported combination of inputs; see help for details of supported combinations")
|
||||
}
|
||||
|
||||
func (c *command) loadChainInfo(ctx context.Context) error {
|
||||
func (c *command) loadChainInfo(_ context.Context) error {
|
||||
_, err := os.Stat(offlinePreparationFilename)
|
||||
if err != nil {
|
||||
if c.debug {
|
||||
fmt.Printf("Failed to read offline preparation file: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Failed to read offline preparation file: %v\n", err)
|
||||
}
|
||||
return errors.Wrap(err, fmt.Sprintf("cannot find %s", offlinePreparationFilename))
|
||||
}
|
||||
|
||||
if c.debug {
|
||||
fmt.Printf("%s found; loading chain state\n", offlinePreparationFilename)
|
||||
fmt.Fprintf(os.Stderr, "%s found; loading chain state\n", offlinePreparationFilename)
|
||||
}
|
||||
data, err := os.ReadFile(offlinePreparationFilename)
|
||||
if err != nil {
|
||||
@@ -305,17 +321,17 @@ func (c *command) loadChainInfo(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) loadOperations(ctx context.Context) error {
|
||||
func (c *command) loadOperations(_ context.Context) error {
|
||||
_, err := os.Stat(changeOperationsFilename)
|
||||
if err != nil {
|
||||
if c.debug {
|
||||
fmt.Printf("Failed to read change operations file: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Failed to read change operations file: %v\n", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if c.debug {
|
||||
fmt.Printf("%s found; loading operations\n", changeOperationsFilename)
|
||||
fmt.Fprintf(os.Stderr, "%s found; loading operations\n", changeOperationsFilename)
|
||||
}
|
||||
data, err := os.ReadFile(changeOperationsFilename)
|
||||
if err != nil {
|
||||
@@ -346,7 +362,7 @@ func (c *command) generateOperationsFromMnemonic(ctx context.Context) error {
|
||||
for i := 0; ; i++ {
|
||||
if i-lastFoundIndex > maxDistance {
|
||||
if c.debug {
|
||||
fmt.Printf("Gone %d indices without finding a validator, not scanning any further\n", maxDistance)
|
||||
fmt.Fprintf(os.Stderr, "Gone %d indices without finding a validator, not scanning any further\n", maxDistance)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -363,6 +379,68 @@ func (c *command) generateOperationsFromMnemonic(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) generateOperationsFromMnemonicAndPrivateKey(ctx context.Context) error {
|
||||
// Functionally identical to a simple scan, so use that.
|
||||
return c.generateOperationsFromMnemonic(ctx)
|
||||
}
|
||||
|
||||
func (c *command) generateOperationsFromMnemonicAndValidator(ctx context.Context) error {
|
||||
seed, err := util.SeedFromMnemonic(c.mnemonic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validator, err := c.fetchValidatorInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Scan the keys from the seed to find the path.
|
||||
maxDistance := 1024
|
||||
// Start scanning the validator keys.
|
||||
for i := 0; ; i++ {
|
||||
if i == maxDistance {
|
||||
if c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Gone %d indices without finding the validator, not scanning any further\n", maxDistance)
|
||||
}
|
||||
break
|
||||
}
|
||||
validatorKeyPath := fmt.Sprintf("m/12381/3600/%d/0/0", i)
|
||||
validatorPrivkey, err := ethutil.PrivateKeyFromSeedAndPath(seed, validatorKeyPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate validator private key")
|
||||
}
|
||||
validatorPubkey := validatorPrivkey.PublicKey().Marshal()
|
||||
if bytes.Equal(validatorPubkey, validator.Pubkey[:]) {
|
||||
// Recreate the withdrawal credentials to ensure a match.
|
||||
withdrawalKeyPath := strings.TrimSuffix(validatorKeyPath, "/0")
|
||||
withdrawalPrivkey, err := ethutil.PrivateKeyFromSeedAndPath(seed, withdrawalKeyPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate withdrawal private key")
|
||||
}
|
||||
withdrawalPubkey := withdrawalPrivkey.PublicKey()
|
||||
withdrawalCredentials := ethutil.SHA256(withdrawalPubkey.Marshal())
|
||||
withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX
|
||||
if !bytes.Equal(withdrawalCredentials, validator.WithdrawalCredentials) {
|
||||
return fmt.Errorf("validator %#x withdrawal credentials %#x do not match expected credentials, cannot update", validatorPubkey, validator.WithdrawalCredentials)
|
||||
}
|
||||
|
||||
withdrawalAccount, err := util.ParseAccount(ctx, c.mnemonic, []string{withdrawalKeyPath}, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create withdrawal account")
|
||||
}
|
||||
|
||||
err = c.generateOperationFromAccount(ctx, validator, withdrawalAccount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) generateOperationFromSeedAndPath(ctx context.Context,
|
||||
validators map[string]*validatorInfo,
|
||||
seed []byte,
|
||||
@@ -379,45 +457,56 @@ func (c *command) generateOperationFromSeedAndPath(ctx context.Context,
|
||||
validator, exists := validators[validatorPubkey]
|
||||
if !exists {
|
||||
if c.debug {
|
||||
fmt.Printf("No validator found with public key %s at path %s\n", validatorPubkey, path)
|
||||
fmt.Fprintf(os.Stderr, "No validator found with public key %s at path %s\n", validatorPubkey, path)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c.verbose {
|
||||
fmt.Printf("Validator %d found with public key %s at path %s\n", validator.Index, validatorPubkey, path)
|
||||
fmt.Fprintf(os.Stderr, "Validator %d found with public key %s at path %s\n", validator.Index, validatorPubkey, path)
|
||||
}
|
||||
|
||||
if validator.WithdrawalCredentials[0] != byte(0) {
|
||||
if c.debug {
|
||||
fmt.Printf("Validator %s has non-BLS withdrawal credentials %#x\n", validatorPubkey, validator.WithdrawalCredentials)
|
||||
fmt.Fprintf(os.Stderr, "Validator %s has non-BLS withdrawal credentials %#x\n", validatorPubkey, validator.WithdrawalCredentials)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Recreate the withdrawal credentials to ensure a match.
|
||||
withdrawalKeyPath := strings.TrimSuffix(path, "/0")
|
||||
withdrawalPrivkey, err := ethutil.PrivateKeyFromSeedAndPath(seed, withdrawalKeyPath)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to generate withdrawal private key")
|
||||
var withdrawalPubkey []byte
|
||||
var withdrawalAccount e2wtypes.Account
|
||||
if c.privateKey == "" {
|
||||
// Recreate the withdrawal credentials to ensure a match.
|
||||
withdrawalKeyPath := strings.TrimSuffix(path, "/0")
|
||||
withdrawalPrivkey, err := ethutil.PrivateKeyFromSeedAndPath(seed, withdrawalKeyPath)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to generate withdrawal private key")
|
||||
}
|
||||
withdrawalPubkey = withdrawalPrivkey.PublicKey().Marshal()
|
||||
withdrawalAccount, err = util.ParseAccount(ctx, c.mnemonic, []string{withdrawalKeyPath}, true)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to create withdrawal account")
|
||||
}
|
||||
|
||||
} else {
|
||||
// Need the withdrawal credentials from the private key.
|
||||
withdrawalAccount, err = util.ParseAccount(ctx, c.privateKey, nil, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
withdrawalPubkey = withdrawalAccount.PublicKey().Marshal()
|
||||
}
|
||||
withdrawalPubkey := withdrawalPrivkey.PublicKey()
|
||||
withdrawalCredentials := ethutil.SHA256(withdrawalPubkey.Marshal())
|
||||
withdrawalCredentials := ethutil.SHA256(withdrawalPubkey)
|
||||
withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX
|
||||
if !bytes.Equal(withdrawalCredentials, validator.WithdrawalCredentials) {
|
||||
if c.verbose {
|
||||
fmt.Printf("Validator %s withdrawal credentials %#x do not match expected credentials, cannot update\n", validatorPubkey, validator.WithdrawalCredentials)
|
||||
if c.verbose && c.privateKey == "" {
|
||||
fmt.Fprintf(os.Stderr, "Validator %s withdrawal credentials %#x do not match expected credentials, cannot update\n", validatorPubkey, validator.WithdrawalCredentials)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c.debug {
|
||||
fmt.Printf("Validator %s eligible for setting credentials\n", validatorPubkey)
|
||||
}
|
||||
|
||||
withdrawalAccount, err := util.ParseAccount(ctx, c.mnemonic, []string{withdrawalKeyPath}, true)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to create withdrawal account")
|
||||
fmt.Fprintf(os.Stderr, "Validator %s eligible for setting credentials\n", validatorPubkey)
|
||||
}
|
||||
|
||||
err = c.generateOperationFromAccount(ctx, validator, withdrawalAccount)
|
||||
@@ -480,7 +569,7 @@ func (c *command) createSignedOperation(ctx context.Context,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *command) parseWithdrawalAddress(ctx context.Context) error {
|
||||
func (c *command) parseWithdrawalAddress(_ context.Context) error {
|
||||
withdrawalAddressBytes, err := hex.DecodeString(strings.TrimPrefix(c.withdrawalAddressStr, "0x"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to obtain execution address")
|
||||
@@ -513,7 +602,7 @@ func (c *command) validateOperations(ctx context.Context) (bool, string) {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (c *command) validateOperation(ctx context.Context,
|
||||
func (c *command) validateOperation(_ context.Context,
|
||||
validators map[phase0.ValidatorIndex]*validatorInfo,
|
||||
signedOperation *capella.SignedBLSToExecutionChange,
|
||||
) (
|
||||
@@ -525,8 +614,8 @@ func (c *command) validateOperation(ctx context.Context,
|
||||
return false, "validator not known on chain"
|
||||
}
|
||||
if c.debug {
|
||||
fmt.Printf("Credentials change operation: %v", signedOperation)
|
||||
fmt.Printf("On-chain validator info: %v\n", validator)
|
||||
fmt.Fprintf(os.Stderr, "Credentials change operation: %v", signedOperation)
|
||||
fmt.Fprintf(os.Stderr, "On-chain validator info: %v\n", validator)
|
||||
}
|
||||
|
||||
if validator.WithdrawalCredentials[0] != byte(0) {
|
||||
@@ -537,7 +626,7 @@ func (c *command) validateOperation(ctx context.Context,
|
||||
withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX
|
||||
if !bytes.Equal(withdrawalCredentials, validator.WithdrawalCredentials) {
|
||||
if c.debug {
|
||||
fmt.Printf("validator withdrawal credentials %#x do not match calculated operation withdrawal credentials %#x\n", validator.WithdrawalCredentials, withdrawalCredentials)
|
||||
fmt.Fprintf(os.Stderr, "validator withdrawal credentials %#x do not match calculated operation withdrawal credentials %#x\n", validator.WithdrawalCredentials, withdrawalCredentials)
|
||||
}
|
||||
return false, "validator withdrawal credentials do not match those in the operation"
|
||||
}
|
||||
@@ -546,14 +635,7 @@ func (c *command) validateOperation(ctx context.Context,
|
||||
}
|
||||
|
||||
func (c *command) broadcastOperations(ctx context.Context) error {
|
||||
// Broadcast the operations.
|
||||
for _, signedOperation := range c.signedOperations {
|
||||
if err := c.consensusClient.(consensusclient.BLSToExecutionChangeSubmitter).SubmitBLSToExecutionChange(ctx, signedOperation); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return c.consensusClient.(consensusclient.BLSToExecutionChangesSubmitter).SubmitBLSToExecutionChanges(ctx, c.signedOperations)
|
||||
}
|
||||
|
||||
func (c *command) setup(ctx context.Context) error {
|
||||
@@ -633,24 +715,6 @@ func (c *command) fetchValidatorInfo(ctx context.Context) (*validatorInfo, error
|
||||
return validatorInfo, nil
|
||||
}
|
||||
|
||||
func (c *command) fetchAccount(ctx context.Context) (e2wtypes.Account, error) {
|
||||
var account e2wtypes.Account
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case c.account != "":
|
||||
account, err = util.ParseAccount(ctx, c.account, c.passphrases, true)
|
||||
case c.mnemonic != "":
|
||||
account, err = util.ParseAccount(ctx, c.mnemonic, []string{c.path}, true)
|
||||
case c.privateKey != "":
|
||||
account, err = util.ParseAccount(ctx, c.privateKey, nil, true)
|
||||
default:
|
||||
err = errors.New("account, mnemonic or private key must be supplied")
|
||||
}
|
||||
|
||||
return account, err
|
||||
}
|
||||
|
||||
// addressBytesToEIP55 converts a byte array in to an EIP-55 string format.
|
||||
func addressBytesToEIP55(address []byte) string {
|
||||
bytes := []byte(fmt.Sprintf("%x", address))
|
||||
@@ -694,3 +758,101 @@ func (c *command) generateOperationsFromMnemonicAndPath(ctx context.Context) err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) generateOperationsFromAccountAndWithdrawalAccount(ctx context.Context) error {
|
||||
validatorAccount, err := util.ParseAccount(ctx, c.account, nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
withdrawalAccount, err := util.ParseAccount(ctx, c.withdrawalAccount, c.passphrases, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the validator info given its account information.
|
||||
validatorPubkey := validatorAccount.PublicKey().Marshal()
|
||||
var validatorInfo *validatorInfo
|
||||
for _, validator := range c.chainInfo.Validators {
|
||||
if bytes.Equal(validator.Pubkey[:], validatorPubkey) {
|
||||
// Found it.
|
||||
validatorInfo = validator
|
||||
}
|
||||
}
|
||||
if validatorInfo == nil {
|
||||
return errors.New("could not find information for that validator on the chain")
|
||||
}
|
||||
|
||||
if err := c.generateOperationFromAccount(ctx, validatorInfo, withdrawalAccount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) generateOperationsFromAccountAndPrivateKey(ctx context.Context) error {
|
||||
validatorAccount, err := util.ParseAccount(ctx, c.account, nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
withdrawalAccount, err := util.ParseAccount(ctx, c.privateKey, nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the validator info given its account information.
|
||||
validatorPubkey := validatorAccount.PublicKey().Marshal()
|
||||
var validatorInfo *validatorInfo
|
||||
for _, validator := range c.chainInfo.Validators {
|
||||
if bytes.Equal(validator.Pubkey[:], validatorPubkey) {
|
||||
// Found it.
|
||||
validatorInfo = validator
|
||||
}
|
||||
}
|
||||
if validatorInfo == nil {
|
||||
return errors.New("could not find information for that validator on the chain")
|
||||
}
|
||||
|
||||
if err := c.generateOperationFromAccount(ctx, validatorInfo, withdrawalAccount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) generateOperationsFromValidatorAndPrivateKey(ctx context.Context) error {
|
||||
validator, err := c.fetchValidatorInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validatorAccount, err := util.ParseAccount(ctx, validator.Pubkey.String(), nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
withdrawalAccount, err := util.ParseAccount(ctx, c.privateKey, nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the validator info given its account information.
|
||||
validatorPubkey := validatorAccount.PublicKey().Marshal()
|
||||
var validatorInfo *validatorInfo
|
||||
for _, validator := range c.chainInfo.Validators {
|
||||
if bytes.Equal(validator.Pubkey[:], validatorPubkey) {
|
||||
// Found it.
|
||||
validatorInfo = validator
|
||||
}
|
||||
}
|
||||
if validatorInfo == nil {
|
||||
return errors.New("could not find information for that validator on the chain")
|
||||
}
|
||||
|
||||
if err := c.generateOperationFromAccount(ctx, validatorInfo, withdrawalAccount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ var validatorCredentialsSetCmd = &cobra.Command{
|
||||
|
||||
ethdo validator credentials set --validator=primary/validator --withdrawal-address=0x00...13 --private-key=0x00...1f
|
||||
|
||||
The existing account can be specified in one of a number of ways:
|
||||
The validator account can be specified in one of a number of ways:
|
||||
|
||||
- mnemonic using --mnemonic; this will scan the mnemonic and generate all required operations
|
||||
- mnemonic using --mnemonic; this will scan the mnemonic and generate all applicable operations
|
||||
- mnemonic and path to the validator key using --mnemonic and --path; this will generate a single operation
|
||||
- private key using --private-key; this will generate a single operation
|
||||
- account and passphrase using --account and --passphrase; this will generate a single operation
|
||||
- mnemonic and validator index or public key --mnemonic and --validator; this will generate a single operation
|
||||
- mnemonic and withdrawal private key using --mnemonic and --private-key; this will generate all applicable operations
|
||||
- validator and withdrawal private key using --validator and --private-key; this will generate a single operation
|
||||
- account and withdrawal account using --account and --withdrawal-account; this will generate a single operation
|
||||
|
||||
In quiet mode this will return 0 if the credentials operation has been generated (and successfully broadcast if online), otherwise 1.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@@ -56,6 +58,7 @@ func init() {
|
||||
validatorCredentialsFlags(validatorCredentialsSetCmd)
|
||||
validatorCredentialsSetCmd.Flags().Bool("prepare-offline", false, "Create files for offline use")
|
||||
validatorCredentialsSetCmd.Flags().String("validator", "", "Validator for which to set validator credentials")
|
||||
validatorCredentialsSetCmd.Flags().String("withdrawal-account", "", "Account with which the validator's withdrawal credentials were set")
|
||||
validatorCredentialsSetCmd.Flags().String("withdrawal-address", "", "Execution address to which to direct withdrawals")
|
||||
validatorCredentialsSetCmd.Flags().String("signed-operation", "", "Use pre-defined JSON signed operation as created by --json to transmit the credentials change operation")
|
||||
validatorCredentialsSetCmd.Flags().Bool("json", false, "Generate JSON data containing a signed operation rather than broadcast it to the network (implied when offline)")
|
||||
@@ -74,6 +77,9 @@ func validatorCredentialsSetBindings() {
|
||||
if err := viper.BindPFlag("signed-operation", validatorCredentialsSetCmd.Flags().Lookup("signed-operation")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := viper.BindPFlag("withdrawal-account", validatorCredentialsSetCmd.Flags().Lookup("withdrawal-account")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := viper.BindPFlag("withdrawal-address", validatorCredentialsSetCmd.Flags().Lookup("withdrawal-address")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -179,28 +179,36 @@ A mnemonic is a 24-word phrase from which withdrawal and validator keys are deri
|
||||
however this is only a standard and not a restriction, and it is possible for users to have created validators using paths of their own choice.
|
||||
|
||||
```
|
||||
ethdo validator credentials set --validator=123 --mnemonic="abandon abandon abandon … art" --path='m/12381/3600/0/0/0' --withdrawal-address=0x0123…cdef
|
||||
ethdo validator credentials set --mnemonic="abandon abandon abandon … art" --path='m/12381/3600/0/0/0' --withdrawal-address=0x0123…cdef
|
||||
```
|
||||
|
||||
replacing the path with the path to your _withdrawal_ key, and all other parameters with your own values.
|
||||
|
||||
#### Using a private key
|
||||
If you have the private key from which the current withdrawal credentials were derived this can be used to generate and broadcast the credentials change operation with the following command:
|
||||
#### Using a mnemonic and validator.
|
||||
Similar to the previous section, however instead of specifying a path instead the index, public key or account of the validator is provided.
|
||||
|
||||
```
|
||||
ethdo validator credentials set --validator=123 --withdrawal-address=0x8f…9F --private-key=0x3b…9c
|
||||
ethdo validator credentials set --mnemonic="abandon abandon abandon … art" --validator=123 --withdrawal-address=0x0123…cdef
|
||||
```
|
||||
|
||||
replacing the parameters with your own values.
|
||||
#### Using a mnemonic and withdrawal private key.
|
||||
If the withdrawal address was created using a non-standard method then it is possible that you have the private key for the withdrawal address. In this situation you can supply the withdrawal private key.
|
||||
|
||||
|
||||
```
|
||||
ethdo validator credentials set --mnemonic="abandon abandon abandon … art" --private-key=0x3b…9c
|
||||
```
|
||||
|
||||
Note that it is possible for there to be multiple validators that use the provided private key for a withdrawal address, in which case an operation will be generated for each validator that is eligible for change.
|
||||
|
||||
#### Using an account
|
||||
If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate and broadcast the credentials change operation with the following command:
|
||||
If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the accout of the validator and the accout of the withdrawal credentials to generate and broadcast the credentials change operation with the following command:
|
||||
|
||||
```
|
||||
ethdo validator credentials set --validator=123 --withdrawal-address=0x8f…9F --account=Wallet/Account --passphrase=secret
|
||||
ethdo validator credentials set --withdrawal-address=0x8f…9F --account=Wallet/Account --withdrawal-account=Withdrawals/Account --passphrase=secret
|
||||
```
|
||||
|
||||
replacing the parameters with your own values.
|
||||
replacing the parameters with your own values. Note that the passphrase here is the passphrsae of the withdrawal account, not the validator account.
|
||||
|
||||
## Confirming the process has succeeded
|
||||
The final step is confirming the operation has taken place. To do so, run the following command on an online server:
|
||||
|
||||
4
go.mod
4
go.mod
@@ -3,7 +3,7 @@ module github.com/wealdtech/ethdo
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/attestantio/go-eth2-client v0.14.5
|
||||
github.com/attestantio/go-eth2-client v0.15.0
|
||||
github.com/ferranbt/fastssz v0.1.2
|
||||
github.com/gofrs/uuid v4.2.0+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
@@ -32,7 +32,7 @@ require (
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.6.0
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.4.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.17.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.11.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.11.1
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.0
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.10.0
|
||||
github.com/wealdtech/go-string2eth v1.2.0
|
||||
|
||||
8
go.sum
8
go.sum
@@ -73,8 +73,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
|
||||
github.com/attestantio/dirk v1.1.0 h1:hwMTYZkwj/Y0um3OD0LQxg2xSl4/5xqVWV2MRePE4ec=
|
||||
github.com/attestantio/dirk v1.1.0/go.mod h1:2jkOw/XHjvIDdhDcmj+Z3kuVPpxMcQ6zxzzjSSv71PY=
|
||||
github.com/attestantio/go-eth2-client v0.8.1/go.mod h1:kEK9iAAOBoADO5wEkd84FEOzjT1zXgVWveQsqn+uBGg=
|
||||
github.com/attestantio/go-eth2-client v0.14.5 h1:pKOTcbv9KOiVixVKM5Cr8nJrjD1VOIWmrlNFO0YtF64=
|
||||
github.com/attestantio/go-eth2-client v0.14.5/go.mod h1:5kLLzdlyPGboWr8tAwnG/4Kpi43BHd/HWp++WmmP6Ws=
|
||||
github.com/attestantio/go-eth2-client v0.15.0 h1:Ia8U1EPYFJ8KB/vsQ2+oEhzuPgCePlBkWXg1R3e0oWw=
|
||||
github.com/attestantio/go-eth2-client v0.15.0/go.mod h1:5kLLzdlyPGboWr8tAwnG/4Kpi43BHd/HWp++WmmP6Ws=
|
||||
github.com/aws/aws-sdk-go v1.33.17/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.40.41/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.41.19/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
@@ -588,8 +588,8 @@ github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.15/go.mod h1:v/JATYJQ
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.17.0 h1:cq7k9osiIkaYrdpetPQgk3ozl/dFvmxW364OC/uNuww=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.17.0/go.mod h1:Fiw5If3/mgH+qYRKIH+kTpZZ3r6z2KgHUiE5Vf/QrfE=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.10.0/go.mod h1:DhAm7si8N/5qU1sZ/RLavm87LsOthnWuRyQaGWNFiyI=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.11.0 h1:qta5XIXe7o9djqB6L90dmf2CvnLmVunzmKeIAnrUyPs=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.11.0/go.mod h1:azzsylTwr1hnLisDWZJbUz3HToRsrG7ADpLG8TXJgOU=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.11.1 h1:q9/p/UfrT7AfR6MYZfr3nQOKdhcLCuKqldqplNHo3Ws=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.11.1/go.mod h1:azzsylTwr1hnLisDWZJbUz3HToRsrG7ADpLG8TXJgOU=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.3/go.mod h1:V4NUofSBIyzoqc5cNZaGciaDm2WFAgSQikRslOyh5Tg=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.0 h1:1dMKx9jtw1v9JrwOPFf2JaOQKmvpMp1GEeuMRiNfq5o=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.0/go.mod h1:O7BitrDeQVtBFNnvYmOYLzJCZAiCf5ur/4IRucIz+S0=
|
||||
|
||||
@@ -47,10 +47,13 @@ func SetupStore() error {
|
||||
return errors.New("basedir does not apply to the s3 store")
|
||||
}
|
||||
store, err = s3.New(s3.WithPassphrase([]byte(GetStorePassphrase("s3"))),
|
||||
s3.WithID([]byte(viper.GetString("stores.s3.id"))),
|
||||
s3.WithEndpoint(viper.GetString("stores.s3.endpoint")),
|
||||
s3.WithRegion(viper.GetString("stores.s3.region")),
|
||||
s3.WithBucket(viper.GetString("stores.s3.bucket")),
|
||||
s3.WithPath(viper.GetString("stores.s3.path")),
|
||||
s3.WithCredentialsID(viper.GetString("stores.s3.credentials.id")),
|
||||
s3.WithCredentialsSecret(viper.GetString("stores.s3.credentials.secret")),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to access Amazon S3 wallet store")
|
||||
|
||||
Reference in New Issue
Block a user