You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

363 lines
9.3 KiB

  1. package p2p
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "sync"
  8. "github.com/tendermint/tendermint/crypto"
  9. "github.com/tendermint/tendermint/libs/log"
  10. tmsync "github.com/tendermint/tendermint/libs/sync"
  11. "github.com/tendermint/tendermint/p2p/conn"
  12. )
  13. const (
  14. MemoryProtocol Protocol = "memory"
  15. // bufferSize is the channel buffer size of MemoryConnection.
  16. bufferSize = 1
  17. )
  18. // MemoryNetwork is an in-memory "network" that uses buffered Go channels to
  19. // communicate between endpoints. It is primarily meant for testing.
  20. //
  21. // Network endpoints are allocated via CreateTransport(), which takes a node ID,
  22. // and the endpoint is then immediately accessible via the URL "memory:<nodeID>".
  23. type MemoryNetwork struct {
  24. logger log.Logger
  25. mtx sync.RWMutex
  26. transports map[NodeID]*MemoryTransport
  27. }
  28. // NewMemoryNetwork creates a new in-memory network.
  29. func NewMemoryNetwork(logger log.Logger) *MemoryNetwork {
  30. return &MemoryNetwork{
  31. logger: logger,
  32. transports: map[NodeID]*MemoryTransport{},
  33. }
  34. }
  35. // CreateTransport creates a new memory transport endpoint with the given node
  36. // ID and immediately begins listening on the address "memory:<id>". It panics
  37. // if the node ID is already in use (which is fine, since this is for tests).
  38. func (n *MemoryNetwork) CreateTransport(nodeID NodeID) *MemoryTransport {
  39. t := newMemoryTransport(n, nodeID)
  40. n.mtx.Lock()
  41. defer n.mtx.Unlock()
  42. if _, ok := n.transports[nodeID]; ok {
  43. panic(fmt.Sprintf("memory transport with node ID %q already exists", nodeID))
  44. }
  45. n.transports[nodeID] = t
  46. return t
  47. }
  48. // GetTransport looks up a transport in the network, returning nil if not found.
  49. func (n *MemoryNetwork) GetTransport(id NodeID) *MemoryTransport {
  50. n.mtx.RLock()
  51. defer n.mtx.RUnlock()
  52. return n.transports[id]
  53. }
  54. // RemoveTransport removes a transport from the network and closes it.
  55. func (n *MemoryNetwork) RemoveTransport(id NodeID) {
  56. n.mtx.Lock()
  57. t, ok := n.transports[id]
  58. delete(n.transports, id)
  59. n.mtx.Unlock()
  60. if ok {
  61. // Close may recursively call RemoveTransport() again, but this is safe
  62. // because we've already removed the transport from the map above.
  63. if err := t.Close(); err != nil {
  64. n.logger.Error("failed to close memory transport", "id", id, "err", err)
  65. }
  66. }
  67. }
  68. // Size returns the number of transports in the network.
  69. func (n *MemoryNetwork) Size() int {
  70. return len(n.transports)
  71. }
  72. // MemoryTransport is an in-memory transport that uses buffered Go channels to
  73. // communicate between endpoints. It is primarily meant for testing.
  74. //
  75. // New transports are allocated with MemoryNetwork.CreateTransport(). To contact
  76. // a different endpoint, both transports must be in the same MemoryNetwork.
  77. type MemoryTransport struct {
  78. logger log.Logger
  79. network *MemoryNetwork
  80. nodeID NodeID
  81. acceptCh chan *MemoryConnection
  82. closeCh chan struct{}
  83. closeOnce sync.Once
  84. }
  85. // newMemoryTransport creates a new MemoryTransport. This is for internal use by
  86. // MemoryNetwork, use MemoryNetwork.CreateTransport() instead.
  87. func newMemoryTransport(network *MemoryNetwork, nodeID NodeID) *MemoryTransport {
  88. return &MemoryTransport{
  89. logger: network.logger.With("local", nodeID),
  90. network: network,
  91. nodeID: nodeID,
  92. acceptCh: make(chan *MemoryConnection),
  93. closeCh: make(chan struct{}),
  94. }
  95. }
  96. // String implements Transport.
  97. func (t *MemoryTransport) String() string {
  98. return string(MemoryProtocol)
  99. }
  100. // Protocols implements Transport.
  101. func (t *MemoryTransport) Protocols() []Protocol {
  102. return []Protocol{MemoryProtocol}
  103. }
  104. // Endpoints implements Transport.
  105. func (t *MemoryTransport) Endpoints() []Endpoint {
  106. select {
  107. case <-t.closeCh:
  108. return []Endpoint{}
  109. default:
  110. return []Endpoint{{
  111. Protocol: MemoryProtocol,
  112. Path: string(t.nodeID),
  113. }}
  114. }
  115. }
  116. // Accept implements Transport.
  117. func (t *MemoryTransport) Accept() (Connection, error) {
  118. select {
  119. case conn := <-t.acceptCh:
  120. t.logger.Info("accepted connection", "remote", conn.RemoteEndpoint().Path)
  121. return conn, nil
  122. case <-t.closeCh:
  123. return nil, io.EOF
  124. }
  125. }
  126. // Dial implements Transport.
  127. func (t *MemoryTransport) Dial(ctx context.Context, endpoint Endpoint) (Connection, error) {
  128. if endpoint.Protocol != MemoryProtocol {
  129. return nil, fmt.Errorf("invalid protocol %q", endpoint.Protocol)
  130. }
  131. if endpoint.Path == "" {
  132. return nil, errors.New("no path")
  133. }
  134. nodeID, err := NewNodeID(endpoint.Path)
  135. if err != nil {
  136. return nil, err
  137. }
  138. t.logger.Info("dialing peer", "remote", nodeID)
  139. peer := t.network.GetTransport(nodeID)
  140. if peer == nil {
  141. return nil, fmt.Errorf("unknown peer %q", nodeID)
  142. }
  143. inCh := make(chan memoryMessage, bufferSize)
  144. outCh := make(chan memoryMessage, bufferSize)
  145. closer := tmsync.NewCloser()
  146. outConn := newMemoryConnection(t.logger, t.nodeID, peer.nodeID, inCh, outCh, closer)
  147. inConn := newMemoryConnection(peer.logger, peer.nodeID, t.nodeID, outCh, inCh, closer)
  148. select {
  149. case peer.acceptCh <- inConn:
  150. return outConn, nil
  151. case <-peer.closeCh:
  152. return nil, io.EOF
  153. case <-ctx.Done():
  154. return nil, ctx.Err()
  155. }
  156. }
  157. // Close implements Transport.
  158. func (t *MemoryTransport) Close() error {
  159. t.network.RemoveTransport(t.nodeID)
  160. t.closeOnce.Do(func() {
  161. close(t.closeCh)
  162. t.logger.Info("closed transport")
  163. })
  164. return nil
  165. }
  166. // MemoryConnection is an in-memory connection between two transport endpoints.
  167. type MemoryConnection struct {
  168. logger log.Logger
  169. localID NodeID
  170. remoteID NodeID
  171. receiveCh <-chan memoryMessage
  172. sendCh chan<- memoryMessage
  173. closer *tmsync.Closer
  174. }
  175. // memoryMessage is passed internally, containing either a message or handshake.
  176. type memoryMessage struct {
  177. channelID ChannelID
  178. message []byte
  179. // For handshakes.
  180. nodeInfo *NodeInfo
  181. pubKey crypto.PubKey
  182. }
  183. // newMemoryConnection creates a new MemoryConnection.
  184. func newMemoryConnection(
  185. logger log.Logger,
  186. localID NodeID,
  187. remoteID NodeID,
  188. receiveCh <-chan memoryMessage,
  189. sendCh chan<- memoryMessage,
  190. closer *tmsync.Closer,
  191. ) *MemoryConnection {
  192. return &MemoryConnection{
  193. logger: logger.With("remote", remoteID),
  194. localID: localID,
  195. remoteID: remoteID,
  196. receiveCh: receiveCh,
  197. sendCh: sendCh,
  198. closer: closer,
  199. }
  200. }
  201. // String implements Connection.
  202. func (c *MemoryConnection) String() string {
  203. return c.RemoteEndpoint().String()
  204. }
  205. // LocalEndpoint implements Connection.
  206. func (c *MemoryConnection) LocalEndpoint() Endpoint {
  207. return Endpoint{
  208. Protocol: MemoryProtocol,
  209. Path: string(c.localID),
  210. }
  211. }
  212. // RemoteEndpoint implements Connection.
  213. func (c *MemoryConnection) RemoteEndpoint() Endpoint {
  214. return Endpoint{
  215. Protocol: MemoryProtocol,
  216. Path: string(c.remoteID),
  217. }
  218. }
  219. // Status implements Connection.
  220. func (c *MemoryConnection) Status() conn.ConnectionStatus {
  221. return conn.ConnectionStatus{}
  222. }
  223. // Handshake implements Connection.
  224. func (c *MemoryConnection) Handshake(
  225. ctx context.Context,
  226. nodeInfo NodeInfo,
  227. privKey crypto.PrivKey,
  228. ) (NodeInfo, crypto.PubKey, error) {
  229. select {
  230. case c.sendCh <- memoryMessage{nodeInfo: &nodeInfo, pubKey: privKey.PubKey()}:
  231. c.logger.Debug("sent handshake", "nodeInfo", nodeInfo)
  232. case <-c.closer.Done():
  233. return NodeInfo{}, nil, io.EOF
  234. case <-ctx.Done():
  235. return NodeInfo{}, nil, ctx.Err()
  236. }
  237. select {
  238. case msg := <-c.receiveCh:
  239. if msg.nodeInfo == nil {
  240. return NodeInfo{}, nil, errors.New("no NodeInfo in handshake")
  241. }
  242. c.logger.Debug("received handshake", "peerInfo", msg.nodeInfo)
  243. return *msg.nodeInfo, msg.pubKey, nil
  244. case <-c.closer.Done():
  245. return NodeInfo{}, nil, io.EOF
  246. case <-ctx.Done():
  247. return NodeInfo{}, nil, ctx.Err()
  248. }
  249. }
  250. // ReceiveMessage implements Connection.
  251. func (c *MemoryConnection) ReceiveMessage() (ChannelID, []byte, error) {
  252. // Check close first, since channels are buffered. Otherwise, below select
  253. // may non-deterministically return non-error even when closed.
  254. select {
  255. case <-c.closer.Done():
  256. return 0, nil, io.EOF
  257. default:
  258. }
  259. select {
  260. case msg := <-c.receiveCh:
  261. c.logger.Debug("received message", "chID", msg.channelID, "msg", msg.message)
  262. return msg.channelID, msg.message, nil
  263. case <-c.closer.Done():
  264. return 0, nil, io.EOF
  265. }
  266. }
  267. // SendMessage implements Connection.
  268. func (c *MemoryConnection) SendMessage(chID ChannelID, msg []byte) (bool, error) {
  269. // Check close first, since channels are buffered. Otherwise, below select
  270. // may non-deterministically return non-error even when closed.
  271. select {
  272. case <-c.closer.Done():
  273. return false, io.EOF
  274. default:
  275. }
  276. select {
  277. case c.sendCh <- memoryMessage{channelID: chID, message: msg}:
  278. c.logger.Debug("sent message", "chID", chID, "msg", msg)
  279. return true, nil
  280. case <-c.closer.Done():
  281. return false, io.EOF
  282. }
  283. }
  284. // TrySendMessage implements Connection.
  285. func (c *MemoryConnection) TrySendMessage(chID ChannelID, msg []byte) (bool, error) {
  286. // Check close first, since channels are buffered. Otherwise, below select
  287. // may non-deterministically return non-error even when closed.
  288. select {
  289. case <-c.closer.Done():
  290. return false, io.EOF
  291. default:
  292. }
  293. select {
  294. case c.sendCh <- memoryMessage{channelID: chID, message: msg}:
  295. c.logger.Debug("sent message", "chID", chID, "msg", msg)
  296. return true, nil
  297. case <-c.closer.Done():
  298. return false, io.EOF
  299. default:
  300. return false, nil
  301. }
  302. }
  303. // Close implements Connection.
  304. func (c *MemoryConnection) Close() error {
  305. select {
  306. case <-c.closer.Done():
  307. return nil
  308. default:
  309. c.closer.Close()
  310. c.logger.Info("closed connection")
  311. }
  312. return nil
  313. }
  314. // FlushClose implements Connection.
  315. func (c *MemoryConnection) FlushClose() error {
  316. return c.Close()
  317. }