github.com/mavryk-network/mvgo@v1.19.9/signer/remote/client.go (about)

     1  // Copyright (c) 2020-2022 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc
     3  
     4  package remote
     5  
     6  import (
     7  	"context"
     8  	"net/http"
     9  
    10  	"github.com/mavryk-network/mvgo/codec"
    11  	"github.com/mavryk-network/mvgo/mavryk"
    12  	"github.com/mavryk-network/mvgo/rpc"
    13  	"github.com/mavryk-network/mvgo/signer"
    14  )
    15  
    16  var _ signer.Signer = (*RemoteSigner)(nil)
    17  
    18  type RemoteSigner struct {
    19  	c     *rpc.Client
    20  	addrs []mavryk.Address
    21  	auth  mavryk.PrivateKey
    22  }
    23  
    24  // New creates a new remote signer client and initializes it with the remote url.
    25  // Users may pass an optional http client with a custom configuration, otherwise
    26  // the http.DefaultClient is used.
    27  func New(url string, client *http.Client) (*RemoteSigner, error) {
    28  	c, err := rpc.NewClient(url, client)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  	return &RemoteSigner{c: c}, nil
    33  }
    34  
    35  func (s *RemoteSigner) WithAddress(addr mavryk.Address) *RemoteSigner {
    36  	s.addrs = append(s.addrs, addr)
    37  	return s
    38  }
    39  
    40  func (s *RemoteSigner) WithAuthKey(sk mavryk.PrivateKey) *RemoteSigner {
    41  	s.auth = sk
    42  	return s
    43  }
    44  
    45  // AuthorizedKeys returns a list of addresses the remote signer accepts for
    46  // authenticating requests.
    47  func (s RemoteSigner) AuthorizedKeys(ctx context.Context) ([]mavryk.Address, error) {
    48  	type response struct {
    49  		Addrs []mavryk.Address `json:"authorized_keys"`
    50  	}
    51  	var resp response
    52  	err := s.c.Get(ctx, "/authorized_keys", &resp)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	return resp.Addrs, nil
    57  }
    58  
    59  // ListAddresses returns a list of addresses the remote signer can produce signatures for.
    60  func (s RemoteSigner) ListAddresses(ctx context.Context) ([]mavryk.Address, error) {
    61  	return s.addrs, nil
    62  }
    63  
    64  // GetKey returns the public key associated with address.
    65  func (s RemoteSigner) GetKey(ctx context.Context, address mavryk.Address) (mavryk.Key, error) {
    66  	type response struct {
    67  		Pk mavryk.Key `json:"public_key"`
    68  	}
    69  	var resp response
    70  	err := s.c.Get(ctx, "/keys/"+address.String(), &resp)
    71  	return resp.Pk, err
    72  }
    73  
    74  // SignMessage signs msg for address by wrapping it into a failing noop operation
    75  // with zero branch hash. This prevents unintended signature of message bytes that
    76  // represent a valid transaction.
    77  //
    78  // Note that most remote signers for Tezos do not support signing of operation kinds other
    79  // than baking related operations.
    80  func (s RemoteSigner) SignMessage(ctx context.Context, address mavryk.Address, msg string) (mavryk.Signature, error) {
    81  	op := codec.NewOp().
    82  		WithBranch(mavryk.ZeroBlockHash).
    83  		WithContents(&codec.FailingNoop{
    84  			Arbitrary: msg,
    85  		})
    86  	return s.SignOperation(ctx, address, op)
    87  }
    88  
    89  // SignOperation signs operation op for address using the configured remote signer's
    90  // REST API. For endorsements this call requires branch_id to be present.
    91  //
    92  // Note that most remote signers for Tezos do not support signing of operation kinds other
    93  // than baking related operations.
    94  func (s RemoteSigner) SignOperation(ctx context.Context, address mavryk.Address, op *codec.Op) (mavryk.Signature, error) {
    95  	type response struct {
    96  		Sig mavryk.Signature `json:"signature"`
    97  	}
    98  	var resp response
    99  	err := s.c.Post(ctx, "/keys/"+address.String(), mavryk.HexBytes(op.WatermarkedBytes()), &resp)
   100  	return resp.Sig, err
   101  }
   102  
   103  // SignOperation signs a block header for address using the configured remote signer's
   104  // REST API. This call requires branch_id to be present.
   105  func (s RemoteSigner) SignBlock(ctx context.Context, address mavryk.Address, head *codec.BlockHeader) (mavryk.Signature, error) {
   106  	type response struct {
   107  		Sig mavryk.Signature `json:"signature"`
   108  	}
   109  	var resp response
   110  	err := s.c.Post(ctx, "/keys/"+address.String(), mavryk.HexBytes(head.WatermarkedBytes()), &resp)
   111  	return resp.Sig, err
   112  }