diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f4df32..d4458e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) signer sub module * [#31](https://github.com/babylonlabs-io/covenant-emulator/pull/31/) Bump docker workflow version, fix some Dockerfile issue +* [#36](https://github.com/babylonlabs-io/covenant-emulator/pull/36) Add public key +endpoint to the remote signer ## v0.8.0 diff --git a/covenant-signer/itest/e2etest.go b/covenant-signer/itest/e2e_test.go similarity index 93% rename from covenant-signer/itest/e2etest.go rename to covenant-signer/itest/e2e_test.go index 39fb952..99c1f89 100644 --- a/covenant-signer/itest/e2etest.go +++ b/covenant-signer/itest/e2e_test.go @@ -129,6 +129,17 @@ func buildDataToSign(t *testing.T, covnenantPublicKey *btcec.PublicKey) signerap } } +func TestGetPublicKey(t *testing.T) { + tm := StartManager(t, 100) + + pubKey, err := signerservice.GetPublicKey(context.Background(), tm.SigningServerUrl(), 10*time.Second) + require.NoError(t, err) + require.NotNil(t, pubKey) + + pubKeyBytes := pubKey.SerializeCompressed() + require.Equal(t, hex.EncodeToString(pubKeyBytes), hex.EncodeToString(tm.covenantPrivKey.PubKey().SerializeCompressed())) +} + func TestSigningTransactions(t *testing.T) { tm := StartManager(t, 100) diff --git a/covenant-signer/signerapp/signer.go b/covenant-signer/signerapp/signer.go index bcf3138..b83c60a 100644 --- a/covenant-signer/signerapp/signer.go +++ b/covenant-signer/signerapp/signer.go @@ -44,7 +44,6 @@ func (s *SignerApp) SignTransactions( ctx context.Context, req *ParsedSigningRequest, ) (*ParsedSigningResponse, error) { - privKey, err := s.pkr.PrivKey(ctx) defer func() { @@ -77,7 +76,16 @@ func (s *SignerApp) SignTransactions( UnbondingSig: unbondingSig, SlashUnbondingAdaptorSigs: slashUnbondingSigs, }, nil +} + +func (s *SignerApp) PubKey(ctx context.Context) (*btcec.PublicKey, error) { + privKey, err := s.pkr.PrivKey(ctx) + if err != nil { + return nil, err + } + defer privKey.Zero() + return privKey.PubKey(), nil } func slashUnbondSig( diff --git a/covenant-signer/signerservice/client.go b/covenant-signer/signerservice/client.go index 51fb2a4..5ded44f 100644 --- a/covenant-signer/signerservice/client.go +++ b/covenant-signer/signerservice/client.go @@ -3,6 +3,7 @@ package signerservice import ( "bytes" "context" + "encoding/hex" "encoding/json" "fmt" "io" @@ -12,6 +13,7 @@ import ( "github.com/babylonlabs-io/covenant-emulator/covenant-signer/signerapp" "github.com/babylonlabs-io/covenant-emulator/covenant-signer/signerservice/handlers" "github.com/babylonlabs-io/covenant-emulator/covenant-signer/signerservice/types" + "github.com/btcsuite/btcd/btcec/v2" ) const ( @@ -79,3 +81,46 @@ func RequestCovenantSignaure( return types.ToParsedSigningResponse(&response.Data) } + +func GetPublicKey(ctx context.Context, signerUrl string, timeout time.Duration) (*btcec.PublicKey, error) { + route := fmt.Sprintf("%s/v1/public-key", signerUrl) + + httpRequest, err := http.NewRequestWithContext(ctx, "GET", route, nil) + + if err != nil { + return nil, err + } + + client := http.Client{Timeout: timeout} + res, err := client.Do(httpRequest) + + if err != nil { + return nil, err + } + + defer res.Body.Close() + + maxSizeReader := http.MaxBytesReader(nil, res.Body, maxResponseSize) + + resBody, err := io.ReadAll(maxSizeReader) + + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("public key request failed. status code: %d, message: %s", res.StatusCode, string(resBody)) + } + + var response handlers.PublicResponse[types.GetPublicKeyResponse] + if err := json.Unmarshal(resBody, &response); err != nil { + return nil, err + } + + pubKey, err := hex.DecodeString(response.Data.PublicKey) + if err != nil { + return nil, err + } + + return btcec.ParsePubKey(pubKey) +} diff --git a/covenant-signer/signerservice/handlers/signtransactions.go b/covenant-signer/signerservice/handlers/signtransactions.go index 2237926..0c43ee3 100644 --- a/covenant-signer/signerservice/handlers/signtransactions.go +++ b/covenant-signer/signerservice/handlers/signtransactions.go @@ -1,6 +1,7 @@ package handlers import ( + "encoding/hex" "encoding/json" "net/http" @@ -40,3 +41,16 @@ func (h *Handler) SignTransactions(request *http.Request) (*Result, *types.Error return NewResult(resp), nil } + +func (h *Handler) GetPublicKey(request *http.Request) (*Result, *types.Error) { + pubKey, err := h.s.PubKey(request.Context()) + if err != nil { + return nil, types.NewErrorWithMsg(http.StatusInternalServerError, types.InternalServiceError, err.Error()) + } + + resp := &types.GetPublicKeyResponse{ + PublicKey: hex.EncodeToString(pubKey.SerializeCompressed()), + } + + return NewResult(resp), nil +} diff --git a/covenant-signer/signerservice/server.go b/covenant-signer/signerservice/server.go index 289123e..83dadc4 100644 --- a/covenant-signer/signerservice/server.go +++ b/covenant-signer/signerservice/server.go @@ -23,6 +23,7 @@ type SigningServer struct { func (a *SigningServer) SetupRoutes(r *chi.Mux) { handler := a.handler r.Post("/v1/sign-transactions", registerHandler(handler.SignTransactions)) + r.Get("/v1/public-key", registerHandler(handler.GetPublicKey)) } func New( diff --git a/covenant-signer/signerservice/types/publickey.go b/covenant-signer/signerservice/types/publickey.go new file mode 100644 index 0000000..1606e77 --- /dev/null +++ b/covenant-signer/signerservice/types/publickey.go @@ -0,0 +1,6 @@ +package types + +type GetPublicKeyResponse struct { + // hex encoded 33 byte public key + PublicKey string `json:"public_key_hex"` +} diff --git a/covenant-signer/signerservice/types/sign_transactions.go b/covenant-signer/signerservice/types/signtransactions.go similarity index 100% rename from covenant-signer/signerservice/types/sign_transactions.go rename to covenant-signer/signerservice/types/signtransactions.go