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 }