mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
HTTP validator API: wallet endpoints (#13171)
* converting wallet calls to pure http * fixing proto and gaz * adding routes and fixing test * fixing error handling * fixing protos after conflict with develop * adding deprecation notice * fixing route test * review feedback * addressing more comments * updating comment to be more clear * fixing web_api proto
This commit is contained in:
@@ -794,7 +794,6 @@ func (c *ValidatorClient) registerRPCGatewayService(router *mux.Router) error {
|
||||
|
||||
registrations := []gateway.PbHandlerRegistration{
|
||||
validatorpb.RegisterAuthHandler,
|
||||
validatorpb.RegisterWalletHandler,
|
||||
pb.RegisterHealthHandler,
|
||||
validatorpb.RegisterAccountsHandler,
|
||||
validatorpb.RegisterBeaconHandler,
|
||||
|
||||
@@ -6,6 +6,7 @@ go_library(
|
||||
"accounts.go",
|
||||
"auth_token.go",
|
||||
"beacon.go",
|
||||
"handler_wallet.go",
|
||||
"handlers_health.go",
|
||||
"handlers_keymanager.go",
|
||||
"handlers_slashing.go",
|
||||
@@ -13,7 +14,6 @@ go_library(
|
||||
"log.go",
|
||||
"server.go",
|
||||
"structs.go",
|
||||
"wallet.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v4/validator/rpc",
|
||||
visibility = [
|
||||
@@ -91,12 +91,12 @@ go_test(
|
||||
"accounts_test.go",
|
||||
"auth_token_test.go",
|
||||
"beacon_test.go",
|
||||
"handler_wallet_test.go",
|
||||
"handlers_health_test.go",
|
||||
"handlers_keymanager_test.go",
|
||||
"handlers_slashing_test.go",
|
||||
"intercepter_test.go",
|
||||
"server_test.go",
|
||||
"wallet_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
||||
@@ -120,7 +120,7 @@ func (s *Server) BackupAccounts(
|
||||
return nil, status.Errorf(codes.Internal, "Could not backup accounts for derived keymanager: %v", err)
|
||||
}
|
||||
default:
|
||||
return nil, status.Error(codes.FailedPrecondition, "Only HD or imported wallets can backup accounts")
|
||||
return nil, status.Error(codes.FailedPrecondition, "Only HD or IMPORTED wallets can backup accounts")
|
||||
}
|
||||
if len(keystoresToBackup) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "No keystores to backup")
|
||||
|
||||
@@ -4,66 +4,76 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/io/file"
|
||||
"github.com/prysmaticlabs/prysm/v4/io/prompt"
|
||||
pb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
|
||||
httputil "github.com/prysmaticlabs/prysm/v4/network/http"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/keymanager"
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
"github.com/tyler-smith/go-bip39/wordlists"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
const (
|
||||
checkExistsErrMsg = "Could not check if wallet exists"
|
||||
checkValidityErrMsg = "Could not check if wallet is valid"
|
||||
invalidWalletMsg = "Directory does not contain a valid wallet"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// CreateWallet via an API request, allowing a user to save a new
|
||||
// imported wallet via RPC.
|
||||
// DEPRECATE: Prysm Web UI and associated endpoints will be fully removed in a future hard fork.
|
||||
func (s *Server) CreateWallet(ctx context.Context, req *pb.CreateWalletRequest) (*pb.CreateWalletResponse, error) {
|
||||
func (s *Server) CreateWallet(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.web.CreateWallet")
|
||||
defer span.End()
|
||||
|
||||
var req CreateWalletRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
httputil.HandleError(w, "No data submitted", http.StatusBadRequest)
|
||||
return
|
||||
case err != nil:
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
walletDir := s.walletDir
|
||||
exists, err := wallet.Exists(walletDir)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not check for existing wallet: %v", err)
|
||||
httputil.HandleError(w, "Could not check for existing wallet: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if exists {
|
||||
if err := s.initializeWallet(ctx, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: req.WalletPassword,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, "Could not initialize wallet: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
keymanagerKind := pb.KeymanagerKind_IMPORTED
|
||||
keymanagerKind := importedKeymanagerKind
|
||||
switch s.wallet.KeymanagerKind() {
|
||||
case keymanager.Derived:
|
||||
keymanagerKind = pb.KeymanagerKind_DERIVED
|
||||
keymanagerKind = derivedKeymanagerKind
|
||||
case keymanager.Web3Signer:
|
||||
keymanagerKind = pb.KeymanagerKind_WEB3SIGNER
|
||||
keymanagerKind = web3signerKeymanagerKind
|
||||
}
|
||||
return &pb.CreateWalletResponse{
|
||||
Wallet: &pb.WalletResponse{
|
||||
response := &CreateWalletResponse{
|
||||
Wallet: &WalletResponse{
|
||||
WalletPath: walletDir,
|
||||
KeymanagerKind: keymanagerKind,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
return
|
||||
}
|
||||
if err := prompt.ValidatePasswordInput(req.WalletPassword); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Password too weak: %v", err)
|
||||
httputil.HandleError(w, "Password too weak: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if req.Keymanager == pb.KeymanagerKind_IMPORTED {
|
||||
if req.Keymanager == importedKeymanagerKind {
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWalletDir(walletDir),
|
||||
accounts.WithKeymanagerType(keymanager.Local),
|
||||
@@ -72,84 +82,112 @@ func (s *Server) CreateWallet(ctx context.Context, req *pb.CreateWalletRequest)
|
||||
}
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, "Could not create CLI Manager: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, err = acc.WalletCreate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, "Could not create wallet: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := s.initializeWallet(ctx, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: req.WalletPassword,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := writeWalletPasswordToDisk(walletDir, req.WalletPassword); err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not write wallet password to disk")
|
||||
httputil.HandleError(w, "Could not write wallet password to disk: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return &pb.CreateWalletResponse{
|
||||
Wallet: &pb.WalletResponse{
|
||||
response := &CreateWalletResponse{
|
||||
Wallet: &WalletResponse{
|
||||
WalletPath: walletDir,
|
||||
KeymanagerKind: pb.KeymanagerKind_IMPORTED,
|
||||
KeymanagerKind: importedKeymanagerKind,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
return
|
||||
}
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Keymanager type %T create wallet not supported through web", req.Keymanager)
|
||||
httputil.HandleError(w, fmt.Sprintf("Keymanager type %s create wallet not supported through web", req.Keymanager), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// WalletConfig returns the wallet's configuration. If no wallet exists, we return an empty response.
|
||||
// DEPRECATE: Prysm Web UI and associated endpoints will be fully removed in a future hard fork.
|
||||
func (s *Server) WalletConfig(_ context.Context, _ *empty.Empty) (*pb.WalletResponse, error) {
|
||||
func (s *Server) WalletConfig(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := trace.StartSpan(r.Context(), "validator.web.WalletConfig")
|
||||
defer span.End()
|
||||
|
||||
exists, err := wallet.Exists(s.walletDir)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, checkExistsErrMsg)
|
||||
httputil.HandleError(w, wallet.CheckExistsErrMsg+": "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
// If no wallet is found, we simply return an empty response.
|
||||
return &pb.WalletResponse{}, nil
|
||||
httputil.WriteJson(w, &WalletResponse{})
|
||||
return
|
||||
}
|
||||
valid, err := wallet.IsValid(s.walletDir)
|
||||
if errors.Is(err, wallet.ErrNoWalletFound) {
|
||||
return &pb.WalletResponse{}, nil
|
||||
httputil.WriteJson(w, &WalletResponse{})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, checkValidityErrMsg)
|
||||
httputil.HandleError(w, wallet.CheckValidityErrMsg+": "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !valid {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, invalidWalletMsg)
|
||||
httputil.HandleError(w, wallet.InvalidWalletErrMsg, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if s.wallet == nil || s.validatorService == nil {
|
||||
// If no wallet is found, we simply return an empty response.
|
||||
return &pb.WalletResponse{}, nil
|
||||
httputil.WriteJson(w, &WalletResponse{})
|
||||
return
|
||||
}
|
||||
var keymanagerKind pb.KeymanagerKind
|
||||
var keymanagerKind KeymanagerKind
|
||||
switch s.wallet.KeymanagerKind() {
|
||||
case keymanager.Derived:
|
||||
keymanagerKind = pb.KeymanagerKind_DERIVED
|
||||
keymanagerKind = derivedKeymanagerKind
|
||||
case keymanager.Local:
|
||||
keymanagerKind = pb.KeymanagerKind_IMPORTED
|
||||
keymanagerKind = importedKeymanagerKind
|
||||
case keymanager.Web3Signer:
|
||||
keymanagerKind = pb.KeymanagerKind_WEB3SIGNER
|
||||
keymanagerKind = web3signerKeymanagerKind
|
||||
}
|
||||
|
||||
return &pb.WalletResponse{
|
||||
httputil.WriteJson(w, &WalletResponse{
|
||||
WalletPath: s.walletDir,
|
||||
KeymanagerKind: keymanagerKind,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
// RecoverWallet via an API request, allowing a user to recover a derived.
|
||||
// RecoverWallet via an API request, allowing a user to recover a derived wallet.
|
||||
// Generate the seed from the mnemonic + language + 25th passphrase(optional).
|
||||
// Create N validator keystores from the seed specified by req.NumAccounts.
|
||||
// Set the wallet password to req.WalletPassword, then create the wallet from
|
||||
// the provided Mnemonic and return CreateWalletResponse.
|
||||
// DEPRECATE: Prysm Web UI and associated endpoints will be fully removed in a future hard fork.
|
||||
func (s *Server) RecoverWallet(ctx context.Context, req *pb.RecoverWalletRequest) (*pb.CreateWalletResponse, error) {
|
||||
// DEPRECATED: this endpoint will be removed to improve the safety and security of interacting with wallets
|
||||
func (s *Server) RecoverWallet(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.web.RecoverWallet")
|
||||
defer span.End()
|
||||
|
||||
var req RecoverWalletRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
httputil.HandleError(w, "No data submitted", http.StatusBadRequest)
|
||||
return
|
||||
case err != nil:
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
numAccounts := int(req.NumAccounts)
|
||||
if numAccounts == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Must create at least 1 validator account")
|
||||
httputil.HandleError(w, "Must create at least 1 validator account", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check validate mnemonic with chosen language
|
||||
@@ -166,17 +204,20 @@ func (s *Server) RecoverWallet(ctx context.Context, req *pb.RecoverWalletRequest
|
||||
"spanish": wordlists.Spanish,
|
||||
}
|
||||
if _, ok := allowedLanguages[language]; !ok {
|
||||
return nil, status.Error(codes.InvalidArgument, "input not in the list of supported languages")
|
||||
httputil.HandleError(w, "input not in the list of supported languages", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
bip39.SetWordList(allowedLanguages[language])
|
||||
mnemonic := req.Mnemonic
|
||||
if err := accounts.ValidateMnemonic(mnemonic); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid mnemonic in request")
|
||||
httputil.HandleError(w, "invalid mnemonic in request: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check it is not null and not an empty string.
|
||||
// Check it is not whitespace-only (empty is valid)
|
||||
if req.Mnemonic25ThWord != "" && strings.TrimSpace(req.Mnemonic25ThWord) == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "mnemonic 25th word cannot be empty")
|
||||
httputil.HandleError(w, "mnemonic 25th word cannot be empty", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Web UI is structured to only write to the default wallet directory
|
||||
@@ -186,7 +227,8 @@ func (s *Server) RecoverWallet(ctx context.Context, req *pb.RecoverWalletRequest
|
||||
// Web UI should check the new and confirmed password are equal.
|
||||
walletPassword := req.WalletPassword
|
||||
if err := prompt.ValidatePasswordInput(walletPassword); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "password did not pass validation")
|
||||
httputil.HandleError(w, "password did not pass validation: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
opts := []accounts.Option{
|
||||
@@ -198,50 +240,68 @@ func (s *Server) RecoverWallet(ctx context.Context, req *pb.RecoverWalletRequest
|
||||
}
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, "Could not create CLI Manager: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := acc.WalletRecover(ctx); err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, "Failed to recover wallet: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := s.initializeWallet(ctx, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Derived,
|
||||
WalletPassword: walletPassword,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
httputil.HandleError(w, "Failed to initialize wallet: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := writeWalletPasswordToDisk(walletDir, walletPassword); err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not write wallet password to disk")
|
||||
httputil.HandleError(w, "Could not write wallet password to disk: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return &pb.CreateWalletResponse{
|
||||
Wallet: &pb.WalletResponse{
|
||||
httputil.WriteJson(w, &CreateWalletResponse{
|
||||
Wallet: &WalletResponse{
|
||||
WalletPath: walletDir,
|
||||
KeymanagerKind: pb.KeymanagerKind_DERIVED,
|
||||
KeymanagerKind: derivedKeymanagerKind,
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ValidateKeystores checks whether a set of EIP-2335 keystores in the request
|
||||
// can indeed be decrypted using a password in the request. If there is no issue,
|
||||
// we return an empty response with no error. If the password is incorrect for a single keystore,
|
||||
// we return an appropriate error.
|
||||
// DEPRECATE: Prysm Web UI and associated endpoints will be fully removed in a future hard fork.
|
||||
func (*Server) ValidateKeystores(
|
||||
_ context.Context, req *pb.ValidateKeystoresRequest,
|
||||
) (*emptypb.Empty, error) {
|
||||
func (*Server) ValidateKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := trace.StartSpan(r.Context(), "validator.web.ValidateKeystores")
|
||||
defer span.End()
|
||||
|
||||
var req ValidateKeystoresRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
httputil.HandleError(w, "No data submitted", http.StatusBadRequest)
|
||||
return
|
||||
case err != nil:
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.KeystoresPassword == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "Password required for keystores")
|
||||
httputil.HandleError(w, "Password required for keystores", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Needs to unmarshal the keystores from the requests.
|
||||
if req.Keystores == nil || len(req.Keystores) < 1 {
|
||||
return nil, status.Error(codes.InvalidArgument, "No keystores included in request")
|
||||
httputil.HandleError(w, "No keystores included in request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
decryptor := keystorev4.New()
|
||||
for i := 0; i < len(req.Keystores); i++ {
|
||||
encoded := req.Keystores[i]
|
||||
keystore := &keymanager.Keystore{}
|
||||
if err := json.Unmarshal([]byte(encoded), &keystore); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Not a valid EIP-2335 keystore JSON file: %v", err)
|
||||
httputil.HandleError(w, "Not a valid EIP-2335 keystore JSON file: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if keystore.Description == "" && keystore.Name != "" {
|
||||
keystore.Description = keystore.Name
|
||||
@@ -249,23 +309,19 @@ func (*Server) ValidateKeystores(
|
||||
if _, err := decryptor.Decrypt(keystore.Crypto, req.KeystoresPassword); err != nil {
|
||||
doesNotDecrypt := strings.Contains(err.Error(), keymanager.IncorrectPasswordErrMsg)
|
||||
if doesNotDecrypt {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"Password for keystore with public key %s is incorrect. "+
|
||||
"Prysm web only supports importing batches of keystores with the same password for all of them",
|
||||
keystore.Pubkey,
|
||||
)
|
||||
httputil.HandleError(w, fmt.Sprintf("Password for keystore with public key %s is incorrect. "+
|
||||
"Prysm web only supports importing batches of keystores with the same password for all of them",
|
||||
keystore.Pubkey), http.StatusBadRequest)
|
||||
return
|
||||
} else {
|
||||
return nil, status.Errorf(codes.Internal, "Unexpected error decrypting keystore: %v", err)
|
||||
httputil.HandleError(w, "Unexpected error decrypting keystore: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// Initialize a wallet and send it over a global feed.
|
||||
// DEPRECATE: Prysm Web UI and associated endpoints will be fully removed in a future hard fork.
|
||||
func (s *Server) initializeWallet(ctx context.Context, cfg *wallet.Config) error {
|
||||
// We first ensure the user has a wallet.
|
||||
exists, err := wallet.Exists(cfg.WalletDir)
|
||||
@@ -10,14 +10,12 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/google/uuid"
|
||||
"github.com/prysmaticlabs/prysm/v4/async/event"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v4/crypto/rand"
|
||||
"github.com/prysmaticlabs/prysm/v4/io/file"
|
||||
pb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts"
|
||||
@@ -60,13 +58,20 @@ func TestServer_CreateWallet_Local(t *testing.T) {
|
||||
walletDir: defaultWalletPath,
|
||||
validatorService: vs,
|
||||
}
|
||||
|
||||
_, err = s.CreateWallet(ctx, &pb.CreateWalletRequest{
|
||||
Keymanager: pb.KeymanagerKind_IMPORTED,
|
||||
request := &CreateWalletRequest{
|
||||
Keymanager: importedKeymanagerKind,
|
||||
WalletPassword: strongPass,
|
||||
})
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/create", &buf)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.CreateWallet(wr, req)
|
||||
require.Equal(t, http.StatusOK, wr.Code)
|
||||
|
||||
encryptor := keystorev4.New()
|
||||
keystores := make([]string, 3)
|
||||
passwords := make([]string, 3)
|
||||
@@ -98,12 +103,11 @@ func TestServer_CreateWallet_Local(t *testing.T) {
|
||||
Passwords: passwords,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = json.NewEncoder(&buf).Encode(importReq)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/eth/v1/keystores"), &buf)
|
||||
wr := httptest.NewRecorder()
|
||||
req = httptest.NewRequest(http.MethodPost, fmt.Sprintf("/eth/v1/keystores"), &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.ImportKeystores(wr, req)
|
||||
require.Equal(t, http.StatusOK, wr.Code)
|
||||
@@ -120,76 +124,128 @@ func TestServer_CreateWallet_Local(t *testing.T) {
|
||||
func TestServer_CreateWallet_Local_PasswordTooWeak(t *testing.T) {
|
||||
localWalletDir := setupWalletDir(t)
|
||||
defaultWalletPath = localWalletDir
|
||||
ctx := context.Background()
|
||||
s := &Server{
|
||||
walletInitializedFeed: new(event.Feed),
|
||||
walletDir: defaultWalletPath,
|
||||
}
|
||||
req := &pb.CreateWalletRequest{
|
||||
Keymanager: pb.KeymanagerKind_IMPORTED,
|
||||
request := &CreateWalletRequest{
|
||||
Keymanager: importedKeymanagerKind,
|
||||
WalletPassword: "", // Weak password, empty string
|
||||
}
|
||||
_, err := s.CreateWallet(ctx, req)
|
||||
require.ErrorContains(t, "Password too weak", err)
|
||||
|
||||
req = &pb.CreateWalletRequest{
|
||||
Keymanager: pb.KeymanagerKind_IMPORTED,
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/create", &buf)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.CreateWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "Password too weak", wr.Body.String())
|
||||
|
||||
request = &CreateWalletRequest{
|
||||
Keymanager: importedKeymanagerKind,
|
||||
WalletPassword: "a", // Weak password, too short
|
||||
}
|
||||
_, err = s.CreateWallet(ctx, req)
|
||||
require.ErrorContains(t, "Password too weak", err)
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/create", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.CreateWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "Password too weak", wr.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_RecoverWallet_Derived(t *testing.T) {
|
||||
localWalletDir := setupWalletDir(t)
|
||||
ctx := context.Background()
|
||||
s := &Server{
|
||||
walletInitializedFeed: new(event.Feed),
|
||||
walletDir: localWalletDir,
|
||||
}
|
||||
req := &pb.RecoverWalletRequest{
|
||||
request := &RecoverWalletRequest{
|
||||
WalletPassword: strongPass,
|
||||
NumAccounts: 0,
|
||||
}
|
||||
_, err := s.RecoverWallet(ctx, req)
|
||||
require.ErrorContains(t, "Must create at least 1 validator account", err)
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.RecoverWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "Must create at least 1 validator account", wr.Body.String())
|
||||
|
||||
req.NumAccounts = 2
|
||||
req.Language = "Swahili"
|
||||
_, err = s.RecoverWallet(ctx, req)
|
||||
require.ErrorContains(t, "input not in the list of supported languages", err)
|
||||
request.NumAccounts = 2
|
||||
request.Language = "Swahili"
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.RecoverWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "input not in the list of supported languages", wr.Body.String())
|
||||
|
||||
req.Language = "ENglish"
|
||||
_, err = s.RecoverWallet(ctx, req)
|
||||
require.ErrorContains(t, "invalid mnemonic in request", err)
|
||||
request.Language = "ENglish"
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.RecoverWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "invalid mnemonic in request", wr.Body.String())
|
||||
|
||||
mnemonicRandomness := make([]byte, 32)
|
||||
_, err = rand.NewGenerator().Read(mnemonicRandomness)
|
||||
require.NoError(t, err)
|
||||
mnemonic, err := bip39.NewMnemonic(mnemonicRandomness)
|
||||
require.NoError(t, err)
|
||||
req.Mnemonic = mnemonic
|
||||
request.Mnemonic = mnemonic
|
||||
request.Mnemonic25ThWord = " "
|
||||
|
||||
req.Mnemonic25ThWord = " "
|
||||
_, err = s.RecoverWallet(ctx, req)
|
||||
require.ErrorContains(t, "mnemonic 25th word cannot be empty", err)
|
||||
req.Mnemonic25ThWord = "outer"
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.RecoverWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "mnemonic 25th word cannot be empty", wr.Body.String())
|
||||
|
||||
request.Mnemonic25ThWord = "outer"
|
||||
// Test weak password.
|
||||
req.WalletPassword = "123qwe"
|
||||
_, err = s.RecoverWallet(ctx, req)
|
||||
require.ErrorContains(t, "password did not pass validation", err)
|
||||
request.WalletPassword = "123qwe"
|
||||
|
||||
req.WalletPassword = strongPass
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.RecoverWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "password did not pass validation", wr.Body.String())
|
||||
|
||||
request.WalletPassword = strongPass
|
||||
// Create(derived) should fail then test recover.
|
||||
reqCreate := &pb.CreateWalletRequest{
|
||||
Keymanager: pb.KeymanagerKind_DERIVED,
|
||||
reqCreate := &CreateWalletRequest{
|
||||
Keymanager: derivedKeymanagerKind,
|
||||
WalletPassword: strongPass,
|
||||
NumAccounts: 2,
|
||||
Mnemonic: mnemonic,
|
||||
}
|
||||
_, err = s.CreateWallet(ctx, reqCreate)
|
||||
require.ErrorContains(t, "create wallet not supported through web", err, "Create wallet for DERIVED or REMOTE types not supported through web, either import keystore or recover")
|
||||
var buff bytes.Buffer
|
||||
err = json.NewEncoder(&buff).Encode(reqCreate)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/create", &buff)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.CreateWallet(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "create wallet not supported through web", wr.Body.String())
|
||||
|
||||
// This defer will be the last to execute in this func.
|
||||
resetCfgFalse := features.InitWithReset(&features.Flags{
|
||||
@@ -203,8 +259,12 @@ func TestServer_RecoverWallet_Derived(t *testing.T) {
|
||||
defer resetCfgTrue()
|
||||
|
||||
// Finally test recover.
|
||||
_, err = s.RecoverWallet(ctx, req)
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.RecoverWallet(wr, req)
|
||||
|
||||
// Password File should have been written.
|
||||
passwordFilePath := filepath.Join(localWalletDir, wallet.DefaultWalletPasswordFile)
|
||||
@@ -217,24 +277,46 @@ func TestServer_RecoverWallet_Derived(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_ValidateKeystores_FailedPreconditions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
strongPass := "29384283xasjasd32%%&*@*#*"
|
||||
ss := &Server{}
|
||||
_, err := ss.ValidateKeystores(ctx, &pb.ValidateKeystoresRequest{})
|
||||
assert.ErrorContains(t, "Password required for keystores", err)
|
||||
_, err = ss.ValidateKeystores(ctx, &pb.ValidateKeystoresRequest{
|
||||
request := &ValidateKeystoresRequest{}
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
ss.ValidateKeystores(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
assert.StringContains(t, "Password required for keystores", wr.Body.String())
|
||||
|
||||
request = &ValidateKeystoresRequest{
|
||||
KeystoresPassword: strongPass,
|
||||
})
|
||||
assert.ErrorContains(t, "No keystores included in request", err)
|
||||
_, err = ss.ValidateKeystores(ctx, &pb.ValidateKeystoresRequest{
|
||||
}
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
ss.ValidateKeystores(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
assert.StringContains(t, "No keystores included in request", wr.Body.String())
|
||||
|
||||
request = &ValidateKeystoresRequest{
|
||||
KeystoresPassword: strongPass,
|
||||
Keystores: []string{"badjson"},
|
||||
})
|
||||
assert.ErrorContains(t, "Not a valid EIP-2335 keystore", err)
|
||||
}
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
ss.ValidateKeystores(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
assert.StringContains(t, "Not a valid EIP-2335 keystore", wr.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_ValidateKeystores_OK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
strongPass := "29384283xasjasd32%%&*@*#*"
|
||||
ss := &Server{}
|
||||
|
||||
@@ -264,18 +346,32 @@ func TestServer_ValidateKeystores_OK(t *testing.T) {
|
||||
}
|
||||
|
||||
// Validate the keystores and ensure no error.
|
||||
_, err := ss.ValidateKeystores(ctx, &pb.ValidateKeystoresRequest{
|
||||
request := &ValidateKeystoresRequest{
|
||||
KeystoresPassword: strongPass,
|
||||
Keystores: keystores,
|
||||
})
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
ss.ValidateKeystores(wr, req)
|
||||
require.Equal(t, http.StatusOK, wr.Code)
|
||||
|
||||
// Check that using a different password will return an error.
|
||||
_, err = ss.ValidateKeystores(ctx, &pb.ValidateKeystoresRequest{
|
||||
request = &ValidateKeystoresRequest{
|
||||
KeystoresPassword: "badpassword",
|
||||
Keystores: keystores,
|
||||
})
|
||||
require.ErrorContains(t, "is incorrect", err)
|
||||
}
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
ss.ValidateKeystores(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "is incorrect", wr.Body.String())
|
||||
|
||||
// Add a new keystore that was encrypted with a different password and expect
|
||||
// a failure from the function.
|
||||
@@ -297,18 +393,30 @@ func TestServer_ValidateKeystores_OK(t *testing.T) {
|
||||
encodedFile, err := json.MarshalIndent(item, "", "\t")
|
||||
keystores = append(keystores, string(encodedFile))
|
||||
require.NoError(t, err)
|
||||
_, err = ss.ValidateKeystores(ctx, &pb.ValidateKeystoresRequest{
|
||||
request = &ValidateKeystoresRequest{
|
||||
KeystoresPassword: strongPass,
|
||||
Keystores: keystores,
|
||||
})
|
||||
require.ErrorContains(t, "Password for keystore with public key somepubkey is incorrect", err)
|
||||
}
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
req = httptest.NewRequest(http.MethodPost, "/v2/validator/wallet/recover", &buf)
|
||||
wr = httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
ss.ValidateKeystores(wr, req)
|
||||
require.NotEqual(t, http.StatusOK, wr.Code)
|
||||
require.StringContains(t, "Password for keystore with public key somepubkey is incorrect", wr.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_WalletConfig_NoWalletFound(t *testing.T) {
|
||||
s := &Server{}
|
||||
resp, err := s.WalletConfig(context.Background(), &empty.Empty{})
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, resp, &pb.WalletResponse{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/v2/validator/wallet/keystores/validate", nil)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.WalletConfig(wr, req)
|
||||
require.Equal(t, http.StatusOK, wr.Code)
|
||||
var resp WalletResponse
|
||||
require.NoError(t, json.Unmarshal(wr.Body.Bytes(), &resp))
|
||||
require.DeepEqual(t, resp, WalletResponse{})
|
||||
}
|
||||
|
||||
func TestServer_WalletConfig(t *testing.T) {
|
||||
@@ -341,12 +449,17 @@ func TestServer_WalletConfig(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
s.validatorService = vs
|
||||
resp, err := s.WalletConfig(ctx, &empty.Empty{})
|
||||
require.NoError(t, err)
|
||||
req := httptest.NewRequest(http.MethodGet, "/v2/validator/wallet/keystores/validate", nil)
|
||||
wr := httptest.NewRecorder()
|
||||
wr.Body = &bytes.Buffer{}
|
||||
s.WalletConfig(wr, req)
|
||||
require.Equal(t, http.StatusOK, wr.Code)
|
||||
var resp WalletResponse
|
||||
require.NoError(t, json.Unmarshal(wr.Body.Bytes(), &resp))
|
||||
|
||||
assert.DeepEqual(t, resp, &pb.WalletResponse{
|
||||
assert.DeepEqual(t, resp, WalletResponse{
|
||||
WalletPath: localWalletDir,
|
||||
KeymanagerKind: pb.KeymanagerKind_IMPORTED,
|
||||
KeymanagerKind: importedKeymanagerKind,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
|
||||
httputil "github.com/prysmaticlabs/prysm/v4/network/http"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/client"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/keymanager/derived"
|
||||
@@ -34,25 +34,25 @@ func (s *Server) ListKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if s.wallet.KeymanagerKind() != keymanager.Derived && s.wallet.KeymanagerKind() != keymanager.Local {
|
||||
http2.HandleError(w, errors.Wrap(err, "Prysm validator keys are not stored locally with this keymanager type").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Prysm validator keys are not stored locally with this keymanager type").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
pubKeys, err := km.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Could not retrieve keystores").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Could not retrieve keystores").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
keystoreResponse := make([]*Keystore, len(pubKeys))
|
||||
@@ -67,7 +67,7 @@ func (s *Server) ListKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
response := &ListKeystoresResponse{
|
||||
Data: keystoreResponse,
|
||||
}
|
||||
http2.WriteJson(w, response)
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// ImportKeystores allows for importing keystores into Prysm with their slashing protection history.
|
||||
@@ -76,22 +76,22 @@ func (s *Server) ImportKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var req ImportKeystoresRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -104,11 +104,11 @@ func (s *Server) ImportKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
Message: fmt.Sprintf("Keymanager kind %T cannot import local keys", km),
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, &ImportKeystoresResponse{Data: statuses})
|
||||
httputil.WriteJson(w, &ImportKeystoresResponse{Data: statuses})
|
||||
return
|
||||
}
|
||||
if len(req.Keystores) == 0 {
|
||||
http2.WriteJson(w, &ImportKeystoresResponse{})
|
||||
httputil.WriteJson(w, &ImportKeystoresResponse{})
|
||||
return
|
||||
}
|
||||
keystores := make([]*keymanager.Keystore, len(req.Keystores))
|
||||
@@ -135,7 +135,7 @@ func (s *Server) ImportKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
Message: fmt.Sprintf("could not import slashing protection: %v", err),
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, &ImportKeystoresResponse{Data: statuses})
|
||||
httputil.WriteJson(w, &ImportKeystoresResponse{Data: statuses})
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -154,13 +154,13 @@ func (s *Server) ImportKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
statuses, err := importer.ImportKeystores(ctx, keystores, req.Passwords)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Could not import keystores").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Could not import keystores").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// If any of the keys imported had a slashing protection history before, we
|
||||
// stop marking them as deleted from our validator database.
|
||||
http2.WriteJson(w, &ImportKeystoresResponse{Data: statuses})
|
||||
httputil.WriteJson(w, &ImportKeystoresResponse{Data: statuses})
|
||||
}
|
||||
|
||||
// DeleteKeystores allows for deleting specified public keys from Prysm.
|
||||
@@ -169,25 +169,25 @@ func (s *Server) DeleteKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var req DeleteKeystoresRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(req.Pubkeys) == 0 {
|
||||
http2.WriteJson(w, &DeleteKeystoresResponse{Data: make([]*keymanager.KeyStatus, 0)})
|
||||
httputil.WriteJson(w, &DeleteKeystoresResponse{Data: make([]*keymanager.KeyStatus, 0)})
|
||||
return
|
||||
}
|
||||
deleter, ok := km.(keymanager.Deleter)
|
||||
@@ -199,7 +199,7 @@ func (s *Server) DeleteKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
Message: fmt.Sprintf("Keymanager kind %T cannot delete local keys", km),
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, &DeleteKeystoresResponse{Data: sts})
|
||||
httputil.WriteJson(w, &DeleteKeystoresResponse{Data: sts})
|
||||
return
|
||||
}
|
||||
bytePubKeys := make([][]byte, len(req.Pubkeys))
|
||||
@@ -212,13 +212,13 @@ func (s *Server) DeleteKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
statuses, err := deleter.DeleteKeystores(ctx, bytePubKeys)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Could not delete keys").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Could not delete keys").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
statuses, err = s.transformDeletedKeysStatuses(ctx, bytePubKeys, statuses)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Could not transform deleted keys statuses").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Could not transform deleted keys statuses").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -232,12 +232,12 @@ func (s *Server) DeleteKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
Message: "Could not export slashing protection history as existing non duplicate keys were deleted",
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, &DeleteKeystoresResponse{Data: sts})
|
||||
httputil.WriteJson(w, &DeleteKeystoresResponse{Data: sts})
|
||||
return
|
||||
}
|
||||
jsonHist, err := json.Marshal(exportedHistory)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Could not JSON marshal slashing protection history").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Could not JSON marshal slashing protection history").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ func (s *Server) DeleteKeystores(w http.ResponseWriter, r *http.Request) {
|
||||
Data: statuses,
|
||||
SlashingProtection: string(jsonHist),
|
||||
}
|
||||
http2.WriteJson(w, response)
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// For a list of deleted keystore statuses, we check if any NOT_FOUND status actually
|
||||
@@ -310,24 +310,24 @@ func (s *Server) SetVoluntaryExit(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "No wallet found", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "No wallet found", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ func (s *Server) SetVoluntaryExit(w http.ResponseWriter, r *http.Request) {
|
||||
var epoch primitives.Epoch
|
||||
ok, _, e := shared.UintFromQuery(w, r, "epoch")
|
||||
if !ok {
|
||||
http2.HandleError(w, "Invalid epoch", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Invalid epoch", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
epoch = primitives.Epoch(e)
|
||||
@@ -347,12 +347,12 @@ func (s *Server) SetVoluntaryExit(w http.ResponseWriter, r *http.Request) {
|
||||
if epoch == 0 {
|
||||
genesisResponse, err := s.beaconNodeClient.GetGenesis(ctx, &emptypb.Empty{})
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Failed to get genesis time").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Failed to get genesis time").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
currentEpoch, err := client.CurrentEpoch(genesisResponse.GenesisTime)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Failed to get current epoch").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Failed to get current epoch").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
epoch = currentEpoch
|
||||
@@ -365,7 +365,7 @@ func (s *Server) SetVoluntaryExit(w http.ResponseWriter, r *http.Request) {
|
||||
epoch,
|
||||
)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Wrap(err, "Could not create voluntary exit").Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Wrap(err, "Could not create voluntary exit").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ func (s *Server) SetVoluntaryExit(w http.ResponseWriter, r *http.Request) {
|
||||
Signature: hexutil.Encode(sve.Signature),
|
||||
},
|
||||
}
|
||||
http2.WriteJson(w, response)
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// ListRemoteKeys returns a list of all public keys defined for web3signer keymanager type.
|
||||
@@ -387,25 +387,25 @@ func (s *Server) ListRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if s.wallet.KeymanagerKind() != keymanager.Web3Signer {
|
||||
http2.HandleError(w, "Prysm Wallet is not of type Web3Signer. Please execute validator client with web3signer flags.", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Prysm Wallet is not of type Web3Signer. Please execute validator client with web3signer flags.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
pubKeys, err := km.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
http2.HandleError(w, errors.Errorf("Could not retrieve public keys: %v", err).Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, errors.Errorf("Could not retrieve public keys: %v", err).Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
keystoreResponse := make([]*RemoteKey, len(pubKeys))
|
||||
@@ -420,7 +420,7 @@ func (s *Server) ListRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
response := &ListRemoteKeysResponse{
|
||||
Data: keystoreResponse,
|
||||
}
|
||||
http2.WriteJson(w, response)
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// ImportRemoteKeys imports a list of public keys defined for web3signer keymanager type.
|
||||
@@ -429,26 +429,26 @@ func (s *Server) ImportRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if s.wallet.KeymanagerKind() != keymanager.Web3Signer {
|
||||
http2.HandleError(w, "Prysm Wallet is not of type Web3Signer. Please execute validator client with web3signer flags.", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Prysm Wallet is not of type Web3Signer. Please execute validator client with web3signer flags.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var req ImportRemoteKeysRequest
|
||||
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
adder, ok := km.(keymanager.PublicKeyAdder)
|
||||
@@ -460,7 +460,7 @@ func (s *Server) ImportRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
Message: "Keymanager kind cannot import public keys for web3signer keymanager type.",
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, &RemoteKeysResponse{Data: statuses})
|
||||
httputil.WriteJson(w, &RemoteKeysResponse{Data: statuses})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -473,10 +473,10 @@ func (s *Server) ImportRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
if isUrlUsed {
|
||||
log.Warnf("Setting web3signer base url for imported keys is not supported. Prysm only uses the url from --validators-external-signer-url flag for web3signer.")
|
||||
log.Warnf("Setting web3signer base url for IMPORTED keys is not supported. Prysm only uses the url from --validators-external-signer-url flag for web3signerKeymanagerKind.")
|
||||
}
|
||||
|
||||
http2.WriteJson(w, &RemoteKeysResponse{Data: adder.AddPublicKeys(remoteKeys)})
|
||||
httputil.WriteJson(w, &RemoteKeysResponse{Data: adder.AddPublicKeys(remoteKeys)})
|
||||
}
|
||||
|
||||
// DeleteRemoteKeys deletes a list of public keys defined for web3signer keymanager type.
|
||||
@@ -485,25 +485,25 @@ func (s *Server) DeleteRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
if !s.walletInitialized {
|
||||
http2.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Prysm Wallet not initialized. Please create a new wallet.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
km, err := s.validatorService.Keymanager()
|
||||
if err != nil {
|
||||
http2.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if s.wallet.KeymanagerKind() != keymanager.Web3Signer {
|
||||
http2.HandleError(w, "Prysm Wallet is not of type Web3Signer. Please execute validator client with web3signer flags.", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Prysm Wallet is not of type Web3Signer. Please execute validator client with web3signer flags.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var req DeleteRemoteKeysRequest
|
||||
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -516,11 +516,11 @@ func (s *Server) DeleteRemoteKeys(w http.ResponseWriter, r *http.Request) {
|
||||
Message: "Keymanager kind cannot delete public keys for web3signer keymanager type.",
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, &RemoteKeysResponse{Data: statuses})
|
||||
httputil.WriteJson(w, &RemoteKeysResponse{Data: statuses})
|
||||
return
|
||||
}
|
||||
|
||||
http2.WriteJson(w, RemoteKeysResponse{Data: deleter.DeletePublicKeys(req.Pubkeys)})
|
||||
httputil.WriteJson(w, RemoteKeysResponse{Data: deleter.DeletePublicKeys(req.Pubkeys)})
|
||||
}
|
||||
|
||||
// ListFeeRecipientByPubkey returns the public key to eth address mapping object to the end user.
|
||||
@@ -529,13 +529,13 @@ func (s *Server) ListFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ func (s *Server) ListFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request
|
||||
|
||||
if found && proposerOption.FeeRecipientConfig != nil {
|
||||
finalResp.Data.Ethaddress = proposerOption.FeeRecipientConfig.FeeRecipient.String()
|
||||
http2.WriteJson(w, finalResp)
|
||||
httputil.WriteJson(w, finalResp)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -565,11 +565,11 @@ func (s *Server) ListFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request
|
||||
// If fee recipient is defined in default configuration, use it
|
||||
if proposerSettings != nil && proposerSettings.DefaultConfig != nil && proposerSettings.DefaultConfig.FeeRecipientConfig != nil {
|
||||
finalResp.Data.Ethaddress = proposerSettings.DefaultConfig.FeeRecipientConfig.FeeRecipient.String()
|
||||
http2.WriteJson(w, finalResp)
|
||||
httputil.WriteJson(w, finalResp)
|
||||
return
|
||||
}
|
||||
|
||||
http2.HandleError(w, "No fee recipient set", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "No fee recipient set", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// SetFeeRecipientByPubkey updates the eth address mapped to the public key.
|
||||
@@ -578,13 +578,13 @@ func (s *Server) SetFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request)
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -594,7 +594,7 @@ func (s *Server) SetFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
var req SetFeeRecipientByPubkeyRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
ethAddress, valid := shared.ValidateHex(w, "Ethereum Address", req.Ethaddress, fieldparams.FeeRecipientLength)
|
||||
@@ -650,7 +650,7 @@ func (s *Server) SetFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
// save the settings
|
||||
if err := s.validatorService.SetProposerSettings(ctx, settings); err != nil {
|
||||
http2.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// override the 200 success with 202 according to the specs
|
||||
@@ -663,12 +663,12 @@ func (s *Server) DeleteFeeRecipientByPubkey(w http.ResponseWriter, r *http.Reque
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready.", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -687,7 +687,7 @@ func (s *Server) DeleteFeeRecipientByPubkey(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
// save the settings
|
||||
if err := s.validatorService.SetProposerSettings(ctx, settings); err != nil {
|
||||
http2.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -701,13 +701,13 @@ func (s *Server) GetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -733,7 +733,7 @@ func (s *Server) GetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
resp.Data.GasLimit = fmt.Sprintf("%d", s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig.GasLimit)
|
||||
}
|
||||
}
|
||||
http2.WriteJson(w, resp)
|
||||
httputil.WriteJson(w, resp)
|
||||
}
|
||||
|
||||
// SetGasLimit updates the gas limit by public key
|
||||
@@ -742,12 +742,12 @@ func (s *Server) SetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -758,7 +758,7 @@ func (s *Server) SetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var req SetGasLimitRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -769,11 +769,11 @@ func (s *Server) SetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
settings := s.validatorService.ProposerSettings()
|
||||
if settings == nil {
|
||||
http2.HandleError(w, "No proposer settings were found to update", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "No proposer settings were found to update", http.StatusInternalServerError)
|
||||
return
|
||||
} else if settings.ProposeConfig == nil {
|
||||
if settings.DefaultConfig == nil || settings.DefaultConfig.BuilderConfig == nil || !settings.DefaultConfig.BuilderConfig.Enabled {
|
||||
http2.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
|
||||
@@ -784,14 +784,14 @@ func (s *Server) SetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
proposerOption, found := settings.ProposeConfig[bytesutil.ToBytes48(pubkey)]
|
||||
if found {
|
||||
if proposerOption.BuilderConfig == nil || !proposerOption.BuilderConfig.Enabled {
|
||||
http2.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
|
||||
return
|
||||
} else {
|
||||
proposerOption.BuilderConfig.GasLimit = validator.Uint64(gasLimit)
|
||||
}
|
||||
} else {
|
||||
if settings.DefaultConfig == nil {
|
||||
http2.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
option := settings.DefaultConfig.Clone()
|
||||
@@ -801,7 +801,7 @@ func (s *Server) SetGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// save the settings
|
||||
if err := s.validatorService.SetProposerSettings(ctx, settings); err != nil {
|
||||
http2.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusInternalServerError)
|
||||
httputil.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
@@ -813,12 +813,12 @@ func (s *Server) DeleteGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
defer span.End()
|
||||
|
||||
if s.validatorService == nil {
|
||||
http2.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
httputil.HandleError(w, "Validator service not ready", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
rawPubkey := mux.Vars(r)["pubkey"]
|
||||
if rawPubkey == "" {
|
||||
http2.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
httputil.HandleError(w, "pubkey is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -840,7 +840,7 @@ func (s *Server) DeleteGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// save the settings
|
||||
if err := s.validatorService.SetProposerSettings(ctx, proposerSettings); err != nil {
|
||||
http2.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusBadRequest)
|
||||
httputil.HandleError(w, "Could not set proposer settings: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Successfully deleted gas limit (reset to proposer config default or global default).
|
||||
@@ -851,5 +851,5 @@ func (s *Server) DeleteGasLimit(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// Otherwise, either no proposerOption is found for the pubkey or proposerOption.BuilderConfig is not enabled at all,
|
||||
// we respond "not found".
|
||||
http2.HandleError(w, fmt.Sprintf("No gas limit found for pubkey: %q", rawPubkey), http.StatusNotFound)
|
||||
httputil.HandleError(w, fmt.Sprintf("No gas limit found for pubkey: %q", rawPubkey), http.StatusNotFound)
|
||||
}
|
||||
|
||||
@@ -184,7 +184,6 @@ func (s *Server) Start() {
|
||||
// Register services available for the gRPC server.
|
||||
reflection.Register(s.grpcServer)
|
||||
validatorpb.RegisterAuthServer(s.grpcServer, s)
|
||||
validatorpb.RegisterWalletServer(s.grpcServer, s)
|
||||
validatorpb.RegisterBeaconServer(s.grpcServer, s)
|
||||
validatorpb.RegisterAccountsServer(s.grpcServer, s)
|
||||
|
||||
@@ -236,6 +235,11 @@ func (s *Server) InitializeRoutes() error {
|
||||
s.router.HandleFunc("/v2/validator/health/version", s.GetVersion).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/v2/validator/health/logs/validator/stream", s.StreamValidatorLogs).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/v2/validator/health/logs/beacon/stream", s.StreamBeaconLogs).Methods(http.MethodGet)
|
||||
// web wallet endpoints
|
||||
s.router.HandleFunc("/v2/validator/wallet", s.WalletConfig).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/v2/validator/wallet/create", s.CreateWallet).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/v2/validator/wallet/keystores/validate", s.ValidateKeystores).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/v2/validator/wallet/recover", s.RecoverWallet).Methods(http.MethodPost)
|
||||
// slashing protection endpoints
|
||||
s.router.HandleFunc("/v2/validator/slashing-protection/export", s.ExportSlashingProtection).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/v2/validator/slashing-protection/import", s.ImportSlashingProtection).Methods(http.MethodPost)
|
||||
|
||||
@@ -27,6 +27,10 @@ func TestServer_InitializeRoutes(t *testing.T) {
|
||||
"/v2/validator/health/version": {http.MethodGet},
|
||||
"/v2/validator/health/logs/validator/stream": {http.MethodGet},
|
||||
"/v2/validator/health/logs/beacon/stream": {http.MethodGet},
|
||||
"/v2/validator/wallet": {http.MethodGet},
|
||||
"/v2/validator/wallet/create": {http.MethodPost},
|
||||
"/v2/validator/wallet/keystores/validate": {http.MethodPost},
|
||||
"/v2/validator/wallet/recover": {http.MethodPost},
|
||||
"/v2/validator/slashing-protection/export": {http.MethodGet},
|
||||
"/v2/validator/slashing-protection/import": {http.MethodPost},
|
||||
}
|
||||
|
||||
@@ -90,9 +90,53 @@ type SetFeeRecipientByPubkeyRequest struct {
|
||||
Ethaddress string `json:"ethaddress"`
|
||||
}
|
||||
|
||||
// KeymanagerKind is a type of key manager for the wallet
|
||||
type KeymanagerKind string
|
||||
|
||||
const (
|
||||
derivedKeymanagerKind KeymanagerKind = "DERIVED"
|
||||
importedKeymanagerKind KeymanagerKind = "IMPORTED"
|
||||
web3signerKeymanagerKind KeymanagerKind = "WEB3SIGNER"
|
||||
)
|
||||
|
||||
type CreateWalletRequest struct {
|
||||
Keymanager KeymanagerKind `json:"keymanager"`
|
||||
WalletPassword string `json:"wallet_password"`
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
NumAccounts uint64 `json:"num_accounts"`
|
||||
MnemonicLanguage string `json:"mnemonic_language"`
|
||||
}
|
||||
|
||||
type CreateWalletResponse struct {
|
||||
Wallet *WalletResponse `json:"wallet"`
|
||||
}
|
||||
|
||||
type GenerateMnemonicResponse struct {
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
}
|
||||
|
||||
type WalletResponse struct {
|
||||
WalletPath string `json:"wallet_path"`
|
||||
KeymanagerKind KeymanagerKind `json:"keymanager_kind"`
|
||||
}
|
||||
|
||||
type ValidateKeystoresRequest struct {
|
||||
Keystores []string `json:"keystores"`
|
||||
KeystoresPassword string `json:"keystores_password"`
|
||||
}
|
||||
|
||||
type RecoverWalletRequest struct {
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
NumAccounts uint64 `json:"num_accounts"`
|
||||
WalletPassword string `json:"wallet_password"`
|
||||
Language string `json:"language"`
|
||||
Mnemonic25ThWord string `json:"mnemonic25th_word"`
|
||||
}
|
||||
|
||||
type ImportSlashingProtectionRequest struct {
|
||||
SlashingProtectionJson string `json:"slashing_protection_json"`
|
||||
}
|
||||
|
||||
type ExportSlashingProtectionResponse struct {
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user