decred.org/dcrdex@v1.0.5/tatanka/mj/types.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 mj
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"encoding/json"
     9  	"sync/atomic"
    10  	"time"
    11  
    12  	"decred.org/dcrdex/dex"
    13  	"decred.org/dcrdex/dex/encode"
    14  	"decred.org/dcrdex/dex/fiatrates"
    15  	"decred.org/dcrdex/dex/msgjson"
    16  	"decred.org/dcrdex/tatanka/tanka"
    17  	"github.com/btcsuite/btcd/btcec/v2/ecdsa"
    18  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    19  )
    20  
    21  const (
    22  	ErrNone = iota
    23  	ErrTimeout
    24  	ErrInternal
    25  	ErrBadRequest
    26  	ErrAuth
    27  	ErrSig
    28  	ErrNoConfig
    29  	ErrBanned
    30  	ErrFailedRelay
    31  )
    32  
    33  const (
    34  	// tatanka <=> tatanka
    35  	RouteTatankaConfig    = "tatanka_config"
    36  	RouteTatankaConnect   = "tatanka_connect"
    37  	RouteNewClient        = "new_client"
    38  	RouteClientDisconnect = "client_disconnect"
    39  	RouteGetReputation    = "get_reputation"
    40  	RouteRelayBroadcast   = "relay_broadcast"
    41  	RouteRelayTankagram   = "relay_tankagram"
    42  	RoutePathInquiry      = "path_inquiry"
    43  
    44  	// tatanka <=> client
    45  	RouteConnect     = "connect"
    46  	RouteConfig      = "config"
    47  	RoutePostBond    = "post_bond"
    48  	RouteSubscribe   = "subscribe"
    49  	RouteUnsubscribe = "unsubscribe"
    50  	RouteRates       = "rates"
    51  
    52  	// client1 <=> tatankanode <=> client2
    53  	RouteTankagram     = "tankagram"
    54  	RouteEncryptionKey = "encryption_key"
    55  	RouteBroadcast     = "broadcast"
    56  	RouteNewSubscriber = "new_subscriber"
    57  )
    58  
    59  const (
    60  	TopicMarket   = "market"
    61  	TopicFiatRate = "fiat_rate"
    62  )
    63  
    64  type BroadcastMessageType string
    65  
    66  const (
    67  	MessageTypeTrollBox      BroadcastMessageType = "troll_box"
    68  	MessageTypeNewOrder      BroadcastMessageType = "new_order"
    69  	MessageTypeProposeMatch  BroadcastMessageType = "propose_match"
    70  	MessageTypeAcceptMatch   BroadcastMessageType = "accept_match"
    71  	MessageTypeNewSubscriber BroadcastMessageType = "new_subscriber"
    72  	MessageTypeUnsubTopic    BroadcastMessageType = "unsub_topic"
    73  	MessageTypeUnsubSubject  BroadcastMessageType = "unsub_subject"
    74  )
    75  
    76  var msgIDCounter atomic.Uint64
    77  
    78  func NewMessageID() uint64 {
    79  	return msgIDCounter.Add(1)
    80  }
    81  
    82  type TatankaConfig struct {
    83  	ID      tanka.PeerID `json:"id"`
    84  	Version uint32       `json:"version"`
    85  	Chains  []uint32     `json:"chains"`
    86  	// BondTier is the senders current view of the receiver's tier.
    87  	BondTier uint64 `json:"bondTier"`
    88  }
    89  
    90  type Connect struct {
    91  	ID tanka.PeerID `json:"id"`
    92  }
    93  
    94  type Disconnect = Connect
    95  
    96  type RemoteReputation struct {
    97  	Score  int16
    98  	NumPts uint8
    99  }
   100  
   101  type Tankagram struct {
   102  	To           tanka.PeerID     `json:"to"`
   103  	From         tanka.PeerID     `json:"from"`
   104  	Message      *msgjson.Message `json:"message,omitempty"`
   105  	EncryptedMsg dex.Bytes        `json:"encryptedMessage,omitempty"`
   106  }
   107  
   108  // TankagramResultType is a critical component of the mesh network's reputation
   109  // system. The outcome of self-reported audits of counterparty failures will
   110  // depend heavily on what signed TankagramResult.Result is submitted.
   111  type TankagramResultType string
   112  
   113  const (
   114  	TRTTransmitted  TankagramResultType = "transmitted"
   115  	TRTNoPath       TankagramResultType = "nopath"
   116  	TRTErrFromPeer  TankagramResultType = "errorfrompeer"
   117  	TRTErrFromTanka TankagramResultType = "errorfromtanka"
   118  	TRTErrBadClient TankagramResultType = "badclient"
   119  )
   120  
   121  type TankagramResult struct {
   122  	Result   TankagramResultType `json:"result"`
   123  	Response dex.Bytes           `json:"response"`
   124  	// If the tankagram is not transmitted, the server will stamp and sign the
   125  	// tankagram separately.
   126  	Stamp uint64    `json:"stamp"`
   127  	Sig   dex.Bytes `json:"sig"`
   128  }
   129  
   130  func (r *TankagramResult) Sign(priv *secp256k1.PrivateKey) {
   131  	r.Stamp = uint64(time.Now().UnixMilli())
   132  	resultB := []byte(r.Result)
   133  	preimage := make([]byte, len(resultB)+len(r.Response)+4)
   134  	copy(preimage[:len(resultB)], resultB)
   135  	copy(preimage[len(resultB):len(resultB)+len(r.Response)], r.Response)
   136  	copy(preimage[len(resultB)+len(r.Response):], encode.Uint64Bytes(r.Stamp))
   137  	digest := sha256.Sum256(preimage)
   138  	r.Sig = ecdsa.Sign(priv, digest[:]).Serialize()
   139  }
   140  
   141  type Broadcast struct {
   142  	PeerID      tanka.PeerID         `json:"peerID"`
   143  	Topic       tanka.Topic          `json:"topic"`
   144  	Subject     tanka.Subject        `json:"subject"`
   145  	MessageType BroadcastMessageType `json:"messageType"`
   146  	Payload     dex.Bytes            `json:"payload,omitempty"`
   147  	Stamp       time.Time            `json:"stamp"`
   148  }
   149  
   150  type Subscription struct {
   151  	Topic   tanka.Topic   `json:"topic"`
   152  	Subject tanka.Subject `json:"subject"`
   153  	// ChannelParameters json.RawMessage `json:"channelParameters,omitempty"`
   154  }
   155  
   156  type Unsubscription struct {
   157  	Topic  tanka.Topic  `json:"topic"`
   158  	PeerID tanka.PeerID `json:"peerID"`
   159  }
   160  
   161  type FundedMessage struct {
   162  	AssetID uint32          `json:"assetID"`
   163  	Funding json.RawMessage `json:"funding"`
   164  	Msg     msgjson.Message `json:"msg"`
   165  }
   166  
   167  type RateMessage struct {
   168  	Topic tanka.Topic                        `json:"topic"`
   169  	Rates map[string]*fiatrates.FiatRateInfo `json:"rates"`
   170  }
   171  
   172  type Troll struct {
   173  	Msg string `json:"msg"`
   174  }
   175  
   176  var ellipsis = []byte("...")
   177  
   178  func Truncate(b []byte) string {
   179  	const truncationLength = 300
   180  	if len(b) <= truncationLength {
   181  		return string(b)
   182  	}
   183  	truncated := make([]byte, truncationLength+len(ellipsis))
   184  	copy(truncated[:truncationLength], b[:truncationLength])
   185  	copy(truncated[truncationLength:], ellipsis)
   186  	return string(truncated)
   187  }
   188  
   189  type PathInquiry = Connect
   190  
   191  type NewSubscriber struct {
   192  	PeerID  tanka.PeerID  `json:"peerID"`
   193  	Topic   tanka.Topic   `json:"topic"`
   194  	Subject tanka.Subject `json:"subject"`
   195  }
   196  
   197  func MustRequest(route string, payload any) *msgjson.Message {
   198  	msg, err := msgjson.NewRequest(NewMessageID(), route, payload)
   199  	if err != nil {
   200  		panic("MustRequest error: " + err.Error())
   201  	}
   202  	return msg
   203  }
   204  
   205  func MustNotification(route string, payload any) *msgjson.Message {
   206  	msg, err := msgjson.NewNotification(route, payload)
   207  	if err != nil {
   208  		panic("MustNotification error: " + err.Error())
   209  	}
   210  	return msg
   211  }
   212  
   213  func MustResponse(id uint64, payload any, rpcErr *msgjson.Error) *msgjson.Message {
   214  	msg, err := msgjson.NewResponse(id, payload, rpcErr)
   215  	if err != nil {
   216  		panic("MustResponse error: " + err.Error())
   217  	}
   218  	return msg
   219  }