|
|
@ -1,35 +1,77 @@ |
|
|
|
# P2P Module |
|
|
|
|
|
|
|
P2P provides an abstraction around peer-to-peer communication.<br/> |
|
|
|
Communication happens via Reactors that react to messages from peers.<br/> |
|
|
|
Each Reactor has one or more Channels of communication for each Peer.<br/> |
|
|
|
Channels are multiplexed automatically and can be configured.<br/> |
|
|
|
A Switch is started upon app start, and handles Peer management.<br/> |
|
|
|
A PEXReactor implementation is provided to automate peer discovery.<br/> |
|
|
|
|
|
|
|
## Channels |
|
|
|
|
|
|
|
Each peer connection is multiplexed into channels. |
|
|
|
The p2p module comes with a channel implementation used for peer |
|
|
|
discovery (called PEX, short for "peer exchange"). |
|
|
|
|
|
|
|
<table> |
|
|
|
<tr> |
|
|
|
<td><b>Channel</b></td> |
|
|
|
<td>"PEX"</td> |
|
|
|
</tr> |
|
|
|
<tr> |
|
|
|
<td><b>Messages</b></td> |
|
|
|
<td> |
|
|
|
<ul> |
|
|
|
<li>pexRequestMsg</li> |
|
|
|
<li>pexResponseMsg</li> |
|
|
|
</ul> |
|
|
|
</td> |
|
|
|
</tr> |
|
|
|
</table> |
|
|
|
<hr /> |
|
|
|
|
|
|
|
## Resources |
|
|
|
|
|
|
|
* http://www.upnp-hacks.org/upnp.html |
|
|
|
# `tendermint/p2p` |
|
|
|
|
|
|
|
`tendermint/p2p` provides an abstraction around peer-to-peer communication.<br/> |
|
|
|
|
|
|
|
## Peer/MConnection/Channel |
|
|
|
|
|
|
|
Each peer has one `MConnection` (multiplex connection) instance. |
|
|
|
|
|
|
|
__multiplex__ *noun* a system or signal involving simultaneous transmission of |
|
|
|
several messages along a single channel of communication. |
|
|
|
|
|
|
|
Each `MConnection` handles message transmission on multiple abstract communication |
|
|
|
`Channel`s. Each channel has a globally unique byte id. |
|
|
|
The byte id and the relative priorities of each `Channel` are configured upon |
|
|
|
initialization of the connection. |
|
|
|
|
|
|
|
There are two methods for sending messages: |
|
|
|
```go |
|
|
|
func (m MConnection) Send(chId byte, msg interface{}) bool {} |
|
|
|
func (m MConnection) TrySend(chId byte, msg interface{}) bool {} |
|
|
|
``` |
|
|
|
|
|
|
|
`Send(chId, msg)` is a blocking call that waits until `msg` is successfully queued |
|
|
|
for the channel with the given id byte `chId`. The message `msg` is serialized |
|
|
|
using the `tendermint/binary` submodule's `WriteBinary()` reflection routine. |
|
|
|
|
|
|
|
`TrySend(chId, msg)` is a nonblocking call that returns false if the channel's |
|
|
|
queue is full. |
|
|
|
|
|
|
|
`Send()` and `TrySend()` are also exposed for each `Peer`. |
|
|
|
|
|
|
|
## Switch/Reactor |
|
|
|
|
|
|
|
The `Switch` handles peer connections and exposes an API to receive incoming messages |
|
|
|
on `Reactors`. Each `Reactor` is responsible for handling incoming messages of one |
|
|
|
or more `Channels`. So while sending outgoing messages is typically performed on the peer, |
|
|
|
incoming messages are received on the reactor. |
|
|
|
|
|
|
|
```go |
|
|
|
// Declare a MyReactor reactor that handles messages on MyChannelId. |
|
|
|
type MyReactor struct{} |
|
|
|
|
|
|
|
func (reactor MyReactor) GetChannels() []*ChannelDescriptor { |
|
|
|
return []*ChannelDescriptor{ChannelDescriptor{Id:MyChannelId, Priority: 1}} |
|
|
|
} |
|
|
|
|
|
|
|
func (reactor MyReactor) Receive(chId byte, peer *Peer, msgBytes []byte) { |
|
|
|
r, n, err := bytes.NewBuffer(msgBytes), new(int64), new(error) |
|
|
|
msgString := ReadString(r, n, err) |
|
|
|
fmt.Println(msgString) |
|
|
|
} |
|
|
|
|
|
|
|
// Other Reactor methods omitted for brevity |
|
|
|
... |
|
|
|
|
|
|
|
switch := NewSwitch([]Reactor{MyReactor{}}) |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
// Send a random message to all outbound connections |
|
|
|
for _, peer := range switch.Peers().List() { |
|
|
|
if peer.IsOutbound() { |
|
|
|
peer.Send(MyChannelId, "Here's a random message") |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
### PexReactor/AddrBook |
|
|
|
|
|
|
|
A `PEXReactor` reactor implementation is provided to automate peer discovery. |
|
|
|
|
|
|
|
```go |
|
|
|
book := p2p.NewAddrBook(config.AddrBookFile()) |
|
|
|
pexReactor := p2p.NewPEXReactor(book) |
|
|
|
... |
|
|
|
switch := NewSwitch([]Reactor{pexReactor, myReactor, ...}) |
|
|
|
``` |