mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
prysmctl: Add support for writing signed validator exits to disk (#12262)
* prysmctl: Add support for writing signed validator exits to disk * Add dir suffix * Add test to ensure no broadcast call was made --------- Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -49,6 +49,7 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//build/bazel:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
|
||||
@@ -166,6 +166,7 @@ var Commands = &cli.Command{
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.ExitAllFlag,
|
||||
flags.ForceExitFlag,
|
||||
flags.VoluntaryExitJSONOutputPath,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
|
||||
@@ -83,6 +83,7 @@ func AccountsExit(c *cli.Context, r io.Reader) error {
|
||||
accounts.WithBeaconRPCProvider(beaconRPCProvider),
|
||||
accounts.WithBeaconRESTApiProvider(c.String(flags.BeaconRESTApiProviderFlag.Name)),
|
||||
accounts.WithGRPCHeaders(grpcHeaders),
|
||||
accounts.WithExitJSONOutputPath(c.String(flags.VoluntaryExitJSONOutputPath.Name)),
|
||||
}
|
||||
// Get full set of public keys from the keymanager.
|
||||
validatingPublicKeys, err := km.FetchValidatingPublicKeys(c.Context)
|
||||
|
||||
@@ -3,12 +3,15 @@ package accounts
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/prysmaticlabs/prysm/v4/build/bazel"
|
||||
"github.com/prysmaticlabs/prysm/v4/io/file"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
@@ -305,3 +308,93 @@ func TestExitAccountsCli_OK_ForceExit(t *testing.T) {
|
||||
require.Equal(t, 1, len(formattedExitedKeys))
|
||||
assert.Equal(t, "0x"+keystore.Pubkey[:12], formattedExitedKeys[0])
|
||||
}
|
||||
|
||||
func TestExitAccountsCli_WriteJSON_NoBroadcast(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mockValidatorClient := validatormock.NewMockValidatorClient(ctrl)
|
||||
mockNodeClient := validatormock.NewMockNodeClient(ctrl)
|
||||
|
||||
mockValidatorClient.EXPECT().
|
||||
ValidatorIndex(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.ValidatorIndexResponse{Index: 1}, nil)
|
||||
|
||||
// Any time in the past will suffice
|
||||
genesisTime := ×tamppb.Timestamp{
|
||||
Seconds: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC).Unix(),
|
||||
}
|
||||
|
||||
mockNodeClient.EXPECT().
|
||||
GetGenesis(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.Genesis{GenesisTime: genesisTime}, nil)
|
||||
|
||||
mockValidatorClient.EXPECT().
|
||||
DomainData(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil)
|
||||
|
||||
walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
// Write a directory where we will import keys from.
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
// Create keystore file in the keys directory we can then import from in our wallet.
|
||||
keystore, _ := createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// We initialize a wallet with a local keymanager.
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
// Wallet configuration flags.
|
||||
walletDir: walletDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
// Flag required for ImportAccounts to work.
|
||||
keysDir: keysDir,
|
||||
// Flag required for ExitAccounts to work.
|
||||
voluntaryExitPublicKeys: keystore.Pubkey,
|
||||
})
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWalletDir(walletDir),
|
||||
accounts.WithKeymanagerType(keymanager.Local),
|
||||
accounts.WithWalletPassword(password),
|
||||
}
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
require.NoError(t, err)
|
||||
_, err = acc.WalletCreate(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
_, km, err := walletWithKeymanager(cliCtx)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, km)
|
||||
|
||||
validatingPublicKeys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, validatingPublicKeys)
|
||||
|
||||
rawPubKeys, formattedPubKeys, err := accounts.FilterExitAccountsFromUserInput(
|
||||
cliCtx, &bytes.Buffer{}, validatingPublicKeys, true,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, rawPubKeys)
|
||||
require.NotNil(t, formattedPubKeys)
|
||||
|
||||
out := path.Join(bazel.TestTmpDir(), "exits")
|
||||
|
||||
cfg := accounts.PerformExitCfg{
|
||||
ValidatorClient: mockValidatorClient,
|
||||
NodeClient: mockNodeClient,
|
||||
Keymanager: km,
|
||||
RawPubKeys: rawPubKeys,
|
||||
FormattedPubKeys: formattedPubKeys,
|
||||
OutputDirectory: out,
|
||||
}
|
||||
rawExitedKeys, formattedExitedKeys, err := accounts.PerformVoluntaryExit(cliCtx.Context, cfg)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(rawExitedKeys))
|
||||
assert.DeepEqual(t, rawPubKeys[0], rawExitedKeys[0])
|
||||
require.Equal(t, 1, len(formattedExitedKeys))
|
||||
assert.Equal(t, "0x"+keystore.Pubkey[:12], formattedExitedKeys[0])
|
||||
|
||||
require.Equal(t, true, file.FileExists(path.Join(out, "validator-exit-1.json")), "Expected file to exist")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user