decred.org/dcrdex@v1.0.5/tatanka/client/client.go (about)

     1  // This code is available on the terms of the project LICENSE.md file,
     2  // also available online at https://blueoakcouncil.org/license/1.0.0.
     3  
     4  package client
     5  
     6  import (
     7  	"context"
     8  	"crypto/rand"
     9  	"crypto/rsa"
    10  	"encoding/binary"
    11  	"encoding/json"
    12  	"errors"
    13  	"fmt"
    14  	"math/big"
    15  	"strings"
    16  	"sync"
    17  	"sync/atomic"
    18  	"time"
    19  
    20  	"decred.org/dcrdex/dex"
    21  	"decred.org/dcrdex/dex/fiatrates"
    22  	"decred.org/dcrdex/dex/msgjson"
    23  	"decred.org/dcrdex/tatanka/mj"
    24  	"decred.org/dcrdex/tatanka/tanka"
    25  	tcpclient "decred.org/dcrdex/tatanka/tcp/client"
    26  	"github.com/decred/dcrd/crypto/blake256"
    27  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    28  )
    29  
    30  const rsaPrivateKeyLength = 2048
    31  
    32  // NetworkBackend represents a peer's communication protocol.
    33  type NetworkBackend interface {
    34  	Send(*msgjson.Message) error
    35  	Request(msg *msgjson.Message, respHandler func(*msgjson.Message)) error
    36  }
    37  
    38  // tatanka is a Tatanka mesh server node.
    39  type tatanka struct {
    40  	NetworkBackend
    41  	cm     *dex.ConnectionMaster
    42  	peerID tanka.PeerID
    43  	pub    *secp256k1.PublicKey
    44  	config atomic.Value // *mj.TatankaConfig
    45  }
    46  
    47  type order struct {
    48  	*tanka.Order
    49  	oid      tanka.ID32
    50  	proposed map[tanka.ID32]*tanka.Match
    51  	accepted map[tanka.ID32]*tanka.Match
    52  }
    53  
    54  type market struct {
    55  	log dex.Logger
    56  
    57  	ordsMtx sync.RWMutex
    58  	ords    map[tanka.ID32]*order
    59  }
    60  
    61  func (m *market) addOrder(ord *tanka.Order) {
    62  	m.ordsMtx.Lock()
    63  	defer m.ordsMtx.Unlock()
    64  	oid := ord.ID()
    65  	if _, exists := m.ords[oid]; exists {
    66  		// ignore it then
    67  		return
    68  	}
    69  	m.ords[oid] = &order{
    70  		Order:    ord,
    71  		oid:      oid,
    72  		proposed: make(map[tanka.ID32]*tanka.Match),
    73  		accepted: make(map[tanka.ID32]*tanka.Match),
    74  	}
    75  }
    76  
    77  func (m *market) addMatchProposal(match *tanka.Match) {
    78  	m.ordsMtx.Lock()
    79  	defer m.ordsMtx.Unlock()
    80  	ord, found := m.ords[match.OrderID]
    81  	if !found {
    82  		m.log.Debugf("ignoring match proposal for unknown order %s", match.OrderID)
    83  	}
    84  	// Make sure it's not already known or accepted
    85  	mid := match.ID()
    86  	if ord.proposed[mid] != nil {
    87  		// Already known
    88  		return
    89  	}
    90  	if ord.accepted[mid] != nil {
    91  		// Already accepted
    92  		return
    93  	}
    94  	ord.proposed[mid] = match
    95  }
    96  
    97  func (m *market) addMatchAcceptance(match *tanka.Match) {
    98  	m.ordsMtx.Lock()
    99  	defer m.ordsMtx.Unlock()
   100  	ord, found := m.ords[match.OrderID]
   101  	if !found {
   102  		m.log.Debugf("ignoring match proposal for unknown order %s", match.OrderID)
   103  	}
   104  	// Make sure it's not already known or accepted
   105  	mid := match.ID()
   106  	if ord.proposed[mid] != nil {
   107  		delete(ord.proposed, mid)
   108  	}
   109  	if ord.accepted[mid] != nil {
   110  		// Already accepted
   111  		return
   112  	}
   113  	ord.accepted[mid] = match
   114  }
   115  
   116  // peer is a network peer with which we have established encrypted
   117  // communication.
   118  type peer struct {
   119  	id            tanka.PeerID
   120  	pub           *secp256k1.PublicKey
   121  	decryptionKey *rsa.PrivateKey // ours
   122  	encryptionKey *rsa.PublicKey
   123  }
   124  
   125  // wireKey encrypts our RSA public key for transmission.
   126  func (p *peer) wireKey() []byte {
   127  	modulusB := p.decryptionKey.PublicKey.N.Bytes()
   128  	encryptionKey := make([]byte, 8+len(modulusB))
   129  	binary.BigEndian.PutUint64(encryptionKey[:8], uint64(p.decryptionKey.PublicKey.E))
   130  	copy(encryptionKey[8:], modulusB)
   131  	return encryptionKey
   132  }
   133  
   134  // https://stackoverflow.com/a/67035019
   135  func (p *peer) decryptRSA(enc []byte) ([]byte, error) {
   136  	msgLen := len(enc)
   137  	hasher := blake256.New()
   138  	step := p.decryptionKey.PublicKey.Size()
   139  	var b []byte
   140  	for start := 0; start < msgLen; start += step {
   141  		finish := start + step
   142  		if finish > msgLen {
   143  			finish = msgLen
   144  		}
   145  		block, err := rsa.DecryptOAEP(hasher, rand.Reader, p.decryptionKey, enc[start:finish], []byte{})
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  		b = append(b, block...)
   150  	}
   151  	return b, nil
   152  }
   153  
   154  func (p *peer) encryptRSA(b []byte) ([]byte, error) {
   155  	msgLen := len(b)
   156  	hasher := blake256.New()
   157  	step := p.encryptionKey.Size() - 2*hasher.Size() - 2
   158  	var enc []byte
   159  	for start := 0; start < msgLen; start += step {
   160  		finish := start + step
   161  		if finish > msgLen {
   162  			finish = msgLen
   163  		}
   164  		block, err := rsa.EncryptOAEP(hasher, rand.Reader, p.encryptionKey, b[start:finish], []byte{})
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  		enc = append(enc, block...)
   169  	}
   170  	return enc, nil
   171  }
   172  
   173  // IncomingPeerConnect will be emitted when a peer requests a connection for
   174  // the transmission of tankagrams.
   175  type IncomingPeerConnect struct {
   176  	PeerID tanka.PeerID
   177  	Reject func()
   178  }
   179  
   180  // IncomingTankagram will be emitted when we receive a tankagram from a
   181  // connected peer.
   182  type IncomingTankagram struct {
   183  	Msg     *msgjson.Message
   184  	Respond func(thing interface{}) error
   185  }
   186  
   187  // NewMarketSubscriber will be emitted when a new client subscribes to a market.
   188  type NewMarketSubscriber struct {
   189  	MarketName string
   190  	PeerID     tanka.PeerID
   191  }
   192  
   193  // Config is the configuration for the TankaClient.
   194  type Config struct {
   195  	Logger     dex.Logger
   196  	PrivateKey *secp256k1.PrivateKey
   197  }
   198  
   199  type TankaClient struct {
   200  	wg                   *sync.WaitGroup
   201  	peerID               tanka.PeerID
   202  	priv                 *secp256k1.PrivateKey
   203  	log                  dex.Logger
   204  	requestHandlers      map[string]func(*tatanka, *msgjson.Message) *msgjson.Error
   205  	notificationHandlers map[string]func(*tatanka, *msgjson.Message)
   206  	payloads             chan interface{}
   207  
   208  	tankaMtx sync.RWMutex
   209  	tankas   map[tanka.PeerID]*tatanka
   210  
   211  	peersMtx sync.RWMutex
   212  	peers    map[tanka.PeerID]*peer
   213  
   214  	marketsMtx sync.RWMutex
   215  	markets    map[string]*market
   216  
   217  	fiatRatesMtx sync.RWMutex
   218  	fiatRates    map[string]*fiatrates.FiatRateInfo
   219  }
   220  
   221  func New(cfg *Config) *TankaClient {
   222  	var peerID tanka.PeerID
   223  	copy(peerID[:], cfg.PrivateKey.PubKey().SerializeCompressed())
   224  
   225  	c := &TankaClient{
   226  		log:       cfg.Logger,
   227  		peerID:    peerID,
   228  		priv:      cfg.PrivateKey,
   229  		tankas:    make(map[tanka.PeerID]*tatanka),
   230  		peers:     make(map[tanka.PeerID]*peer),
   231  		markets:   make(map[string]*market),
   232  		payloads:  make(chan interface{}, 128),
   233  		fiatRates: make(map[string]*fiatrates.FiatRateInfo),
   234  	}
   235  	c.prepareHandlers()
   236  	return c
   237  }
   238  
   239  func (c *TankaClient) ID() tanka.PeerID {
   240  	return c.peerID
   241  }
   242  
   243  func (c *TankaClient) prepareHandlers() {
   244  	c.requestHandlers = map[string]func(*tatanka, *msgjson.Message) *msgjson.Error{
   245  		mj.RouteTankagram: c.handleTankagram,
   246  	}
   247  
   248  	c.notificationHandlers = map[string]func(*tatanka, *msgjson.Message){
   249  		mj.RouteBroadcast: c.handleBroadcast,
   250  		mj.RouteRates:     c.handleRates,
   251  	}
   252  }
   253  
   254  func (c *TankaClient) Next() <-chan interface{} {
   255  	return c.payloads
   256  }
   257  
   258  func (c *TankaClient) handleTankagram(tt *tatanka, tankagram *msgjson.Message) *msgjson.Error {
   259  	var gram mj.Tankagram
   260  	if err := tankagram.Unmarshal(&gram); err != nil {
   261  		return msgjson.NewError(mj.ErrBadRequest, "unmarshal error")
   262  	}
   263  
   264  	c.peersMtx.Lock()
   265  	defer c.peersMtx.Unlock()
   266  	p, peerExisted := c.peers[gram.From]
   267  	if !peerExisted {
   268  		// TODO: We should do a little message verification before accepting
   269  		// new peers.
   270  		if gram.Message == nil || gram.Message.Route != mj.RouteEncryptionKey {
   271  			return msgjson.NewError(mj.ErrBadRequest, "where's your key?")
   272  		}
   273  		pub, err := secp256k1.ParsePubKey(gram.From[:])
   274  		if err != nil {
   275  			c.log.Errorf("could not parse pubkey for tankagram from %s: %w", gram.From, err)
   276  			return msgjson.NewError(mj.ErrBadRequest, "bad pubkey")
   277  		}
   278  		priv, err := rsa.GenerateKey(rand.Reader, rsaPrivateKeyLength)
   279  		if err != nil {
   280  			return msgjson.NewError(mj.ErrInternal, "error generating rsa key: %v", err)
   281  		}
   282  		p = &peer{
   283  			id:            gram.From,
   284  			pub:           pub,
   285  			decryptionKey: priv,
   286  		}
   287  
   288  		msg := gram.Message
   289  		if err := mj.CheckSig(msg, p.pub); err != nil {
   290  			c.log.Errorf("%s sent a unencrypted message with a bad signature: %w", p.id, err)
   291  			return msgjson.NewError(mj.ErrBadRequest, "bad gram sig")
   292  		}
   293  
   294  		var b dex.Bytes
   295  		if err := msg.Unmarshal(&b); err != nil {
   296  			c.log.Errorf("%s tankagram unmarshal error: %w", err)
   297  			return msgjson.NewError(mj.ErrBadRequest, "unmarshal key error")
   298  		}
   299  
   300  		p.encryptionKey, err = decodePubkeyRSA(b)
   301  		if err != nil {
   302  			c.log.Errorf("error decoding RSA pub key from %s: %v", p.id, err)
   303  			return msgjson.NewError(mj.ErrBadRequest, "bad key encoding")
   304  		}
   305  
   306  		if err := c.sendResult(tt, tankagram.ID, dex.Bytes(p.wireKey())); err != nil {
   307  			c.log.Errorf("error responding to encryption key message from peer %s", p.id)
   308  		} else {
   309  			c.peers[p.id] = p
   310  			c.emit(&IncomingPeerConnect{
   311  				PeerID: p.id,
   312  				Reject: func() {
   313  					c.peersMtx.Lock()
   314  					delete(c.peers, p.id)
   315  					c.peersMtx.Unlock()
   316  				},
   317  			})
   318  		}
   319  		return nil
   320  	}
   321  
   322  	// If this isn't the encryption key, this gram.Message is ignored and this
   323  	// is assumed to be encrypted.
   324  	if len(gram.EncryptedMsg) == 0 {
   325  		c.log.Errorf("%s sent a tankagram with no message or data", p.id)
   326  		return msgjson.NewError(mj.ErrBadRequest, "bad gram")
   327  	}
   328  
   329  	b, err := p.decryptRSA(gram.EncryptedMsg)
   330  	if err != nil {
   331  		c.log.Errorf("%s sent an enrypted message that didn't decrypt: %v", p.id, err)
   332  		return msgjson.NewError(mj.ErrBadRequest, "bad encryption")
   333  	}
   334  	msg, err := msgjson.DecodeMessage(b)
   335  	if err != nil {
   336  		c.log.Errorf("%s sent a tankagram that didn't encode a message: %v", p.id, err)
   337  		return msgjson.NewError(mj.ErrBadRequest, "where's the message?")
   338  	}
   339  
   340  	c.emit(&IncomingTankagram{
   341  		Msg: msg,
   342  		Respond: func(thing interface{}) error {
   343  			b, err := json.Marshal(thing)
   344  			if err != nil {
   345  				return err
   346  			}
   347  			enc, err := p.encryptRSA(b)
   348  			if err != nil {
   349  				return err
   350  			}
   351  			return c.sendResult(tt, tankagram.ID, dex.Bytes(enc))
   352  		},
   353  	})
   354  
   355  	return nil
   356  }
   357  
   358  func (c *TankaClient) handleBroadcast(tt *tatanka, msg *msgjson.Message) {
   359  	var bcast mj.Broadcast
   360  	if err := msg.Unmarshal(&bcast); err != nil {
   361  		c.log.Errorf("%s broadcast unmarshal error: %w", err)
   362  		return
   363  	}
   364  	switch bcast.Topic {
   365  	case mj.TopicMarket:
   366  		c.handleMarketBroadcast(tt, &bcast)
   367  	}
   368  	c.emit(bcast)
   369  }
   370  
   371  func (c *TankaClient) handleRates(tt *tatanka, msg *msgjson.Message) {
   372  	var rm mj.RateMessage
   373  	if err := msg.Unmarshal(&rm); err != nil {
   374  		c.log.Errorf("%s rate message unmarshal error: %w", err)
   375  		return
   376  	}
   377  	switch rm.Topic {
   378  	case mj.TopicFiatRate:
   379  		c.fiatRatesMtx.Lock()
   380  		for ticker, rateInfo := range rm.Rates {
   381  			c.fiatRates[strings.ToLower(ticker)] = &fiatrates.FiatRateInfo{
   382  				Value:      rateInfo.Value,
   383  				LastUpdate: time.Now(),
   384  			}
   385  		}
   386  		c.fiatRatesMtx.Unlock()
   387  	}
   388  	c.emit(rm)
   389  }
   390  
   391  func (c *TankaClient) SubscribeToFiatRates() error {
   392  	msg := mj.MustRequest(mj.RouteSubscribe, &mj.Subscription{
   393  		Topic: mj.TopicFiatRate,
   394  	})
   395  
   396  	var nSuccessful int
   397  	for _, tt := range c.tankaNodes() {
   398  		var ok bool // true is only possible non-error payload.
   399  		if err := c.request(tt, msg, &ok); err != nil {
   400  			c.log.Errorf("Error subscribing to fiat rates with %s: %v", tt.peerID, err)
   401  			continue
   402  		}
   403  		nSuccessful++
   404  	}
   405  
   406  	if nSuccessful == 0 {
   407  		return errors.New("failed to subscribe to fiat rates on any servers")
   408  	}
   409  
   410  	return nil
   411  }
   412  
   413  func (c *TankaClient) FiatRate(assetID uint32) float64 {
   414  	c.fiatRatesMtx.RLock()
   415  	defer c.fiatRatesMtx.RUnlock()
   416  	sym := dex.BipIDSymbol(assetID)
   417  	rateInfo := c.fiatRates[sym]
   418  	if rateInfo != nil && time.Since(rateInfo.LastUpdate) < fiatrates.FiatRateDataExpiry && rateInfo.Value > 0 {
   419  		return rateInfo.Value
   420  	}
   421  	return 0
   422  }
   423  
   424  func (c *TankaClient) emit(thing interface{}) {
   425  	select {
   426  	case c.payloads <- thing:
   427  	default:
   428  		c.log.Errorf("payload channel is blocking")
   429  	}
   430  }
   431  
   432  func (c *TankaClient) handleMarketBroadcast(_ *tatanka, bcast *mj.Broadcast) {
   433  	mktName := string(bcast.Subject)
   434  	c.marketsMtx.RLock()
   435  	mkt, found := c.markets[mktName]
   436  	c.marketsMtx.RUnlock()
   437  	if !found {
   438  		c.log.Debugf("received order notification for unknown market %q", mktName)
   439  		return
   440  	}
   441  	switch bcast.MessageType {
   442  	case mj.MessageTypeTrollBox:
   443  		var troll mj.Troll
   444  		if err := json.Unmarshal(bcast.Payload, &troll); err != nil {
   445  			c.log.Errorf("error unmarshaling trollbox message: %v", err)
   446  			return
   447  		}
   448  		fmt.Printf("trollbox message for market %s: %s\n", mktName, troll.Msg)
   449  	case mj.MessageTypeNewOrder:
   450  		var ord tanka.Order
   451  		if err := json.Unmarshal(bcast.Payload, &ord); err != nil {
   452  			c.log.Errorf("error unmarshaling new order: %v", err)
   453  			return
   454  		}
   455  		mkt.addOrder(&ord)
   456  	case mj.MessageTypeProposeMatch:
   457  		var match tanka.Match
   458  		if err := json.Unmarshal(bcast.Payload, &match); err != nil {
   459  			c.log.Errorf("error unmarshaling match proposal: %v", err)
   460  			return
   461  		}
   462  		mkt.addMatchProposal(&match)
   463  	case mj.MessageTypeAcceptMatch:
   464  		var match tanka.Match
   465  		if err := json.Unmarshal(bcast.Payload, &match); err != nil {
   466  			c.log.Errorf("error unmarshaling match proposal: %v", err)
   467  			return
   468  		}
   469  		mkt.addMatchAcceptance(&match)
   470  	case mj.MessageTypeNewSubscriber:
   471  		var ns mj.NewSubscriber
   472  		if err := json.Unmarshal(bcast.Payload, &ns); err != nil {
   473  			c.log.Errorf("error decoding new_subscriber payload: %v", err)
   474  		}
   475  		// c.emit(&NewMarketSubscriber{
   476  		// 	MarketName: mktName,
   477  		// 	PeerID:     bcast.PeerID,
   478  		// })
   479  	default:
   480  		c.log.Errorf("received broadcast on %s -> %s with unknown message type %s", bcast.Topic, bcast.Subject)
   481  	}
   482  }
   483  
   484  func (c *TankaClient) Broadcast(topic tanka.Topic, subject tanka.Subject, msgType mj.BroadcastMessageType, thing interface{}) error {
   485  	payload, err := json.Marshal(thing)
   486  	if err != nil {
   487  		return fmt.Errorf("error marshaling broadcast payload: %v", err)
   488  	}
   489  	note := mj.MustRequest(mj.RouteBroadcast, &mj.Broadcast{
   490  		PeerID:      c.peerID,
   491  		Topic:       topic,
   492  		Subject:     subject,
   493  		MessageType: msgType,
   494  		Payload:     payload,
   495  		Stamp:       time.Now(),
   496  	})
   497  	var oks int
   498  	for _, tt := range c.tankas {
   499  		var ok bool
   500  		if err := c.request(tt, note, &ok); err != nil || !ok {
   501  			c.log.Errorf("error sending to %s: ok = %t, err = %v", tt.peerID, ok, err)
   502  		} else {
   503  			oks++
   504  		}
   505  	}
   506  	if oks == 0 {
   507  		return errors.New("broadcast failed for all servers")
   508  	}
   509  	return nil
   510  }
   511  
   512  func (c *TankaClient) Connect(ctx context.Context) (*sync.WaitGroup, error) {
   513  	var wg sync.WaitGroup
   514  	c.wg = &wg
   515  
   516  	c.log.Infof("Starting TankaClient with peer ID %s", c.peerID)
   517  
   518  	wg.Add(1)
   519  	go func() {
   520  		defer wg.Done()
   521  		<-ctx.Done()
   522  		c.tankaMtx.Lock()
   523  		for _, tt := range c.tankas {
   524  			tt.cm.Disconnect()
   525  		}
   526  		c.tankas = make(map[tanka.PeerID]*tatanka)
   527  		c.tankaMtx.Unlock()
   528  	}()
   529  
   530  	return c.wg, nil
   531  }
   532  
   533  func (c *TankaClient) AddTatankaNode(ctx context.Context, peerID tanka.PeerID, uri string, cert []byte) error {
   534  	pub, err := secp256k1.ParsePubKey(peerID[:])
   535  	if err != nil {
   536  		return fmt.Errorf("error parsing pubkey from peer ID: %w", err)
   537  	}
   538  
   539  	log := c.log.SubLogger("TCP")
   540  	cl, err := tcpclient.New(&tcpclient.Config{
   541  		Logger: log,
   542  		URL:    uri + "/ws",
   543  		Cert:   cert,
   544  		HandleMessage: func(msg *msgjson.Message) *msgjson.Error {
   545  			return c.handleTatankaMessage(peerID, msg)
   546  		},
   547  	})
   548  
   549  	if err != nil {
   550  		return fmt.Errorf("error creating connection: %w", err)
   551  	}
   552  
   553  	cm := dex.NewConnectionMaster(cl)
   554  	if err := cm.ConnectOnce(ctx); err != nil {
   555  		return fmt.Errorf("error connecting: %w", err)
   556  	}
   557  
   558  	c.tankaMtx.Lock()
   559  	defer c.tankaMtx.Unlock()
   560  
   561  	if oldTanka, exists := c.tankas[peerID]; exists {
   562  		oldTanka.cm.Disconnect()
   563  		log.Infof("replacing existing connection")
   564  	}
   565  
   566  	c.tankas[peerID] = &tatanka{
   567  		NetworkBackend: cl,
   568  		cm:             cm,
   569  		peerID:         peerID,
   570  		pub:            pub,
   571  	}
   572  
   573  	return nil
   574  }
   575  
   576  func (c *TankaClient) handleTatankaMessage(peerID tanka.PeerID, msg *msgjson.Message) *msgjson.Error {
   577  	if c.log.Level() == dex.LevelTrace {
   578  		c.log.Tracef("Client handling message from tatanka node: route = %s, payload = %s", msg.Route, mj.Truncate(msg.Payload))
   579  	}
   580  
   581  	c.tankaMtx.RLock()
   582  	tt, exists := c.tankas[peerID]
   583  	c.tankaMtx.RUnlock()
   584  	if !exists {
   585  		c.log.Errorf("%q message received from unknown peer %s", msg.Route, peerID)
   586  		return msgjson.NewError(mj.ErrAuth, "who the heck are you?")
   587  	}
   588  
   589  	if err := mj.CheckSig(msg, tt.pub); err != nil {
   590  		// DRAFT TODO: Record for reputation somehow, no?
   591  		c.log.Errorf("tatanka node %s sent a bad signature. disconnecting", tt.peerID)
   592  		return msgjson.NewError(mj.ErrAuth, "bad sig")
   593  	}
   594  
   595  	switch msg.Type {
   596  	case msgjson.Request:
   597  		handle, found := c.requestHandlers[msg.Route]
   598  		if !found {
   599  			// DRAFT NOTE: We should pontentially be more permissive of unknown
   600  			// routes in order to support minor network upgrades that add new
   601  			// routes.
   602  			c.log.Errorf("tatanka node %s sent a request to an unknown route %q", peerID, msg.Route)
   603  			return msgjson.NewError(mj.ErrBadRequest, "what is route %q?", msg.Route)
   604  		}
   605  		c.handleRequest(tt, msg, handle)
   606  	case msgjson.Notification:
   607  		handle, found := c.notificationHandlers[msg.Route]
   608  		if !found {
   609  			// DRAFT NOTE: We should pontentially be more permissive of unknown
   610  			// routes in order to support minor network upgrades that add new
   611  			// routes.
   612  			c.log.Errorf("tatanka node %s sent a notification to an unknown route %q", peerID, msg.Route)
   613  			return msgjson.NewError(mj.ErrBadRequest, "what is route %q?", msg.Route)
   614  		}
   615  		handle(tt, msg)
   616  	default:
   617  		c.log.Errorf("tatanka node %s send a message with an unhandleable type %d", msg.Type)
   618  		return msgjson.NewError(mj.ErrBadRequest, "message type %d doesn't work for me", msg.Type)
   619  	}
   620  
   621  	return nil
   622  }
   623  
   624  func (c *TankaClient) sendResult(tt *tatanka, msgID uint64, result interface{}) error {
   625  	resp, err := msgjson.NewResponse(msgID, result, nil)
   626  	if err != nil {
   627  		return err
   628  	}
   629  	if err := c.send(tt, resp); err != nil {
   630  		return err
   631  	}
   632  	return nil
   633  }
   634  
   635  func (c *TankaClient) handleRequest(tt *tatanka, msg *msgjson.Message, handle func(*tatanka, *msgjson.Message) *msgjson.Error) {
   636  	if msgErr := handle(tt, msg); msgErr != nil {
   637  		respMsg := mj.MustResponse(msg.ID, nil, msgErr)
   638  		if err := c.send(tt, respMsg); err != nil {
   639  			c.log.Errorf("Send error: %v", err)
   640  		}
   641  	}
   642  }
   643  
   644  func (c *TankaClient) Auth(peerID tanka.PeerID) error {
   645  	c.tankaMtx.RLock()
   646  	tt, found := c.tankas[peerID]
   647  	c.tankaMtx.RUnlock()
   648  	if !found {
   649  		return fmt.Errorf("cannot auth with unknown server %s", peerID)
   650  	}
   651  	return c.auth(tt)
   652  }
   653  
   654  func (c *TankaClient) auth(tt *tatanka) error {
   655  	connectMsg := mj.MustRequest(mj.RouteConnect, &mj.Connect{ID: c.peerID})
   656  	var cfg *mj.TatankaConfig
   657  	if err := c.request(tt, connectMsg, &cfg); err != nil {
   658  		return err
   659  	}
   660  	tt.config.Store(cfg)
   661  	return nil
   662  }
   663  
   664  func (c *TankaClient) tankaNodes() []*tatanka {
   665  	c.tankaMtx.RLock()
   666  	defer c.tankaMtx.RUnlock()
   667  	tankas := make([]*tatanka, 0, len(c.tankas))
   668  	for _, tanka := range c.tankas {
   669  		tankas = append(tankas, tanka)
   670  	}
   671  	return tankas
   672  }
   673  
   674  func (c *TankaClient) PostBond(bond *tanka.Bond) error {
   675  	msg := mj.MustRequest(mj.RoutePostBond, []*tanka.Bond{bond})
   676  	var success bool
   677  	for _, tt := range c.tankaNodes() {
   678  		var res bool
   679  		if err := c.request(tt, msg, &res); err != nil {
   680  			c.log.Errorf("error sending bond to tatanka node %s", tt.peerID)
   681  		} else {
   682  			success = true
   683  		}
   684  	}
   685  	if success {
   686  		return nil
   687  	}
   688  	return errors.New("failed to report bond to any tatanka nodes")
   689  }
   690  
   691  func (c *TankaClient) SubscribeMarket(baseID, quoteID uint32) error {
   692  	mktName, err := dex.MarketName(baseID, quoteID)
   693  	if err != nil {
   694  		return fmt.Errorf("error constructing market name: %w", err)
   695  	}
   696  
   697  	msg := mj.MustRequest(mj.RouteSubscribe, &mj.Subscription{
   698  		Topic:   mj.TopicMarket,
   699  		Subject: tanka.Subject(mktName),
   700  	})
   701  
   702  	c.marketsMtx.Lock()
   703  	defer c.marketsMtx.Unlock()
   704  
   705  	ttNodes := c.tankaNodes()
   706  	subscribed := make([]*tatanka, 0, len(ttNodes))
   707  	for _, tt := range ttNodes {
   708  		var ok bool // true is only possible non-error payload.
   709  		if err := c.request(tt, msg, &ok); err != nil {
   710  			c.log.Errorf("Error subscribing to %s market with %s: %w", mktName, tt.peerID, err)
   711  			continue
   712  		}
   713  		subscribed = append(subscribed, tt)
   714  	}
   715  
   716  	if len(subscribed) == 0 {
   717  		return fmt.Errorf("failed to subscribe to market %s on any servers", mktName)
   718  	} else {
   719  		c.markets[mktName] = &market{
   720  			log:  c.log.SubLogger(mktName),
   721  			ords: make(map[tanka.ID32]*order),
   722  		}
   723  	}
   724  
   725  	return nil
   726  }
   727  
   728  func (c *TankaClient) send(tt *tatanka, msg *msgjson.Message) error {
   729  	mj.SignMessage(c.priv, msg)
   730  	return tt.Send(msg)
   731  }
   732  
   733  func (c *TankaClient) request(tt *tatanka, msg *msgjson.Message, resp interface{}) error {
   734  	mj.SignMessage(c.priv, msg)
   735  	errChan := make(chan error)
   736  	if err := tt.Request(msg, func(msg *msgjson.Message) {
   737  		errChan <- msg.UnmarshalResult(&resp)
   738  	}); err != nil {
   739  		errChan <- fmt.Errorf("request error: %w", err)
   740  	}
   741  
   742  	select {
   743  	case err := <-errChan:
   744  		if err != nil {
   745  			return fmt.Errorf("tankagram error: %w", err)
   746  		}
   747  	case <-time.After(time.Second * 30):
   748  		return errors.New("timed out waiting for tankagram result")
   749  	}
   750  	return nil
   751  }
   752  
   753  func (c *TankaClient) ConnectPeer(peerID tanka.PeerID, hosts ...tanka.PeerID) (*mj.TankagramResult, error) {
   754  	c.peersMtx.Lock()
   755  	defer c.peersMtx.Unlock()
   756  	p, exists := c.peers[peerID]
   757  	if !exists {
   758  		priv, err := rsa.GenerateKey(rand.Reader, rsaPrivateKeyLength)
   759  		if err != nil {
   760  			return nil, fmt.Errorf("error generating rsa key: %v", err)
   761  		}
   762  		remotePub, err := secp256k1.ParsePubKey(peerID[:])
   763  		if err != nil {
   764  			return nil, fmt.Errorf("error parsing remote pubkey: %v", err)
   765  		}
   766  		p = &peer{
   767  			id:            peerID,
   768  			pub:           remotePub,
   769  			decryptionKey: priv,
   770  		}
   771  	}
   772  
   773  	msg := mj.MustNotification(mj.RouteEncryptionKey, dex.Bytes(p.wireKey()))
   774  	mj.SignMessage(c.priv, msg) // We sign the embedded message separately.
   775  
   776  	req := mj.MustRequest(mj.RouteTankagram, &mj.Tankagram{
   777  		To:      peerID,
   778  		From:    c.peerID,
   779  		Message: msg,
   780  	})
   781  
   782  	var tts []*tatanka
   783  	if len(hosts) == 0 {
   784  		tts = c.tankaNodes()
   785  	} else {
   786  		tts = make([]*tatanka, 0, len(hosts))
   787  		c.tankaMtx.RLock()
   788  		for _, host := range hosts {
   789  			tt, exists := c.tankas[host]
   790  			if !exists {
   791  				c.log.Warnf("Requested host %q is not known", host)
   792  				continue
   793  			}
   794  			tts = append(tts, tt)
   795  		}
   796  		c.tankaMtx.RUnlock()
   797  	}
   798  	if len(tts) == 0 {
   799  		return nil, errors.New("no hosts")
   800  	}
   801  
   802  	for _, tt := range tts {
   803  		var r mj.TankagramResult
   804  		if err := c.request(tt, req, &r); err != nil {
   805  			c.log.Errorf("error sending rsa key to %s: %v", peerID, err)
   806  			continue
   807  		}
   808  		if r.Result == mj.TRTTransmitted {
   809  			// We need to get this to the caller, as a Tankagram result can
   810  			// be used as part of an audit request for reporting penalties.
   811  			pub, err := decodePubkeyRSA(r.Response)
   812  			if err != nil {
   813  				return nil, fmt.Errorf("error decoding RSA pub key from %s: %v", p.id, err)
   814  			}
   815  			p.encryptionKey = pub
   816  			c.peers[peerID] = p
   817  			return &r, nil
   818  		}
   819  		return &r, nil
   820  	}
   821  	return nil, errors.New("no path")
   822  }
   823  
   824  func (c *TankaClient) SendTankagram(peerID tanka.PeerID, msg *msgjson.Message) (_ *mj.TankagramResult, _ json.RawMessage, err error) {
   825  	c.peersMtx.RLock()
   826  	p, known := c.peers[peerID]
   827  	c.peersMtx.RUnlock()
   828  
   829  	if !known {
   830  		return nil, nil, fmt.Errorf("not connected to peer %s", peerID)
   831  	}
   832  
   833  	mj.SignMessage(c.priv, msg)
   834  	tankaGram := &mj.Tankagram{
   835  		From: c.peerID,
   836  		To:   peerID,
   837  	}
   838  	tankaGram.EncryptedMsg, err = c.signAndEncryptTankagram(p, msg)
   839  	if err != nil {
   840  		return nil, nil, fmt.Errorf("error signing and encrypting tankagram for %s: %w", p.id, err)
   841  	}
   842  	wrappedMsg := mj.MustRequest(mj.RouteTankagram, tankaGram)
   843  	for _, tt := range c.tankaNodes() {
   844  		var r mj.TankagramResult
   845  		if err := c.request(tt, wrappedMsg, &r); err != nil {
   846  			c.log.Errorf("error sending tankagram to %s via %s: %v", p.id, tt.peerID, err)
   847  			continue
   848  		}
   849  		switch r.Result {
   850  		case mj.TRTTransmitted:
   851  			resB, err := p.decryptRSA(r.Response)
   852  			return &r, resB, err
   853  		case mj.TRTErrFromPeer, mj.TRTErrBadClient:
   854  			return &r, nil, nil
   855  		case mj.TRTNoPath, mj.TRTErrFromTanka:
   856  			continue
   857  		default:
   858  			return nil, nil, fmt.Errorf("unknown result %q", r.Result)
   859  		}
   860  
   861  	}
   862  	return nil, nil, fmt.Errorf("no path")
   863  }
   864  
   865  func (c *TankaClient) signAndEncryptTankagram(p *peer, msg *msgjson.Message) ([]byte, error) {
   866  	mj.SignMessage(c.priv, msg)
   867  	b, err := json.Marshal(msg)
   868  	if err != nil {
   869  		return nil, fmt.Errorf("error marshaling tankagram: %w", err)
   870  	}
   871  	return p.encryptRSA(b)
   872  }
   873  
   874  func decodePubkeyRSA(b []byte) (*rsa.PublicKey, error) {
   875  	if len(b) < 9 {
   876  		return nil, fmt.Errorf("invalid payload length of %d", len(b))
   877  	}
   878  	exponentB, modulusB := b[:8], b[8:]
   879  	exponent := int(binary.BigEndian.Uint64(exponentB))
   880  	modulus := new(big.Int).SetBytes(modulusB)
   881  	return &rsa.PublicKey{
   882  		E: exponent,
   883  		N: modulus,
   884  	}, nil
   885  }