-
Notifications
You must be signed in to change notification settings - Fork 704
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b731e7e
commit 435d116
Showing
4 changed files
with
371 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package jsonrpc | ||
|
||
import ( | ||
"bytes" | ||
"net/http" | ||
"net/url" | ||
|
||
"github.com/ava-labs/avalanchego/utils/crypto/bls" | ||
"github.com/gorilla/rpc/v2/json2" | ||
) | ||
|
||
type Client struct { | ||
// http client | ||
http *http.Client | ||
url url.URL | ||
} | ||
|
||
func NewClient(url url.URL) *Client { | ||
return &Client{ | ||
http: &http.Client{}, | ||
url: url, | ||
} | ||
} | ||
|
||
func (client *Client) call(method string, params []interface{}, result interface{}) error { | ||
requestBody, err := json2.EncodeClientRequest(method, params) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
resp, err := client.http.Post(client.url.String(), "application/json", bytes.NewBuffer(requestBody)) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
return json2.DecodeClientResponse(resp.Body, result) | ||
} | ||
|
||
func (c *Client) PublicKey() *bls.PublicKey { | ||
reply := new(PublicKeyReply) | ||
|
||
err := c.call("Signer.PublicKey", []interface{}{PublicKeyArgs{}}, reply) | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
pk := new(bls.PublicKey) | ||
pk = pk.Deserialize(reply.PublicKey) | ||
|
||
return pk | ||
} | ||
|
||
// Sign [msg] to authorize this message | ||
func (c *Client) Sign(msg []byte) *bls.Signature { | ||
// request the public key from the json-rpc server | ||
reply := new(SignReply) | ||
err := c.call("Signer.Sign", []interface{}{SignArgs{msg}}, reply) | ||
|
||
// TODO: handle this | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// deserialize the public key | ||
sig := new(bls.Signature) | ||
sig = sig.Deserialize(reply.Signature) | ||
|
||
// can be nil if the public key is invalid | ||
return sig | ||
} | ||
|
||
// Sign [msg] to prove the ownership | ||
func (c *Client) SignProofOfPossession(msg []byte) *bls.Signature { | ||
// request the public key from the json-rpc server | ||
reply := new(SignReply) | ||
err := c.call("Signer.SignProofOfPossession", []interface{}{SignArgs{msg}}, reply) | ||
|
||
// TODO: handle this | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// deserialize the public key | ||
sig := new(bls.Signature) | ||
sig = sig.Deserialize(reply.Signature) | ||
|
||
// can be nil if the public key is invalid | ||
return sig | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package jsonrpc | ||
|
||
type PublicKeyArgs struct{} | ||
|
||
type SignArgs struct { | ||
Msg []byte | ||
} | ||
|
||
type SignProofOfPossessionArgs struct { | ||
Msg []byte | ||
} | ||
|
||
type PublicKeyReply struct { | ||
PublicKey []byte | ||
} | ||
|
||
type SignReply struct { | ||
Signature []byte | ||
} | ||
|
||
type SignProofOfPossessionReply struct { | ||
Signature []byte | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package jsonrpc | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"net" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/ava-labs/avalanchego/utils/crypto/bls" | ||
"github.com/ava-labs/avalanchego/utils/crypto/bls/signers/local" | ||
"github.com/gorilla/rpc/v2" | ||
"github.com/gorilla/rpc/v2/json" | ||
) | ||
|
||
type signerService struct { | ||
signer *local.LocalSigner | ||
} | ||
|
||
type Server struct { | ||
httpServer *http.Server | ||
listener net.Listener | ||
} | ||
|
||
func NewSignerService() *signerService { | ||
signer, err := local.NewSigner() | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
return &signerService{signer: signer} | ||
} | ||
|
||
func Serve(service *signerService) (*Server, error) { | ||
server := rpc.NewServer() | ||
server.RegisterCodec(json.NewCodec(), "application/json") | ||
|
||
err := server.RegisterService(service, "Signer") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
httpServer := &http.Server{ | ||
Handler: server, | ||
} | ||
|
||
listener, err := net.Listen("tcp", "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
go func() { | ||
if err := httpServer.Serve(listener); err != nil && err != http.ErrServerClosed { | ||
log.Fatal(err) | ||
} | ||
}() | ||
|
||
return &Server{ | ||
httpServer: httpServer, | ||
listener: listener, | ||
}, nil | ||
} | ||
|
||
func (s *Server) Addr() net.Addr { | ||
return s.listener.Addr() | ||
} | ||
|
||
func (s *Server) Close() error { | ||
// Create a context with a timeout to allow for graceful shutdown | ||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | ||
defer cancel() | ||
|
||
// Shutdown the HTTP server | ||
if err := s.httpServer.Shutdown(ctx); err != nil { | ||
return err | ||
} | ||
|
||
// Close the listener | ||
return s.listener.Close() | ||
} | ||
|
||
func (s *signerService) PublicKey(r *http.Request, args *PublicKeyArgs, reply *PublicKeyReply) error { | ||
*reply = toPkReply(s.signer.PublicKey()) | ||
return nil | ||
} | ||
|
||
func (s *signerService) Sign(r *http.Request, args *struct{ Msg []byte }, reply *SignReply) error { | ||
*reply = toSignReply(s.signer.Sign(args.Msg)) | ||
return nil | ||
} | ||
|
||
func (s *signerService) SignProofOfPossession(r *http.Request, args *struct{ Msg []byte }, reply *SignProofOfPossessionReply) error { | ||
*reply = toSignProofOfPossessionReply(s.signer.SignProofOfPossession(args.Msg)) | ||
return nil | ||
} | ||
|
||
func toPkReply(pk *bls.PublicKey) PublicKeyReply { | ||
return PublicKeyReply{PublicKey: pk.Serialize()} | ||
} | ||
|
||
func toSignReply(sig *bls.Signature) SignReply { | ||
return SignReply{Signature: sig.Serialize()} | ||
} | ||
|
||
func toSignProofOfPossessionReply(sig *bls.Signature) SignProofOfPossessionReply { | ||
return SignProofOfPossessionReply{Signature: sig.Serialize()} | ||
} |
Oops, something went wrong.