Skip to content

[ADR] PeerTransport#2069

Merged
xla merged 7 commits intodevelopfrom
xla/adr-peer-transport
Jul 27, 2018
Merged

[ADR] PeerTransport#2069
xla merged 7 commits intodevelopfrom
xla/adr-peer-transport

Conversation

@xla
Copy link
Contributor

@xla xla commented Jul 25, 2018

First iteration in #2067 and an attempt to liberate the Switch from connection handling and low-level network concenrs.

@xla xla added C:p2p Component: P2P pkg T:design Type: Design work is needed labels Jul 25, 2018
@xla xla added this to the launch milestone Jul 25, 2018
@xla xla self-assigned this Jul 25, 2018
@xla xla requested review from jbibla and zramsay as code owners July 25, 2018 16:22
@xla xla changed the title p2p: Propose PeerTransport ADR [ADR] PeerTransport Jul 25, 2018
@codecov-io
Copy link

codecov-io commented Jul 25, 2018

Codecov Report

Merging #2069 into develop will decrease coverage by 0.03%.
The diff coverage is n/a.

@@             Coverage Diff             @@
##           develop    #2069      +/-   ##
===========================================
- Coverage    61.36%   61.32%   -0.04%     
===========================================
  Files          197      197              
  Lines        15678    15663      -15     
===========================================
- Hits          9621     9606      -15     
- Misses        5246     5248       +2     
+ Partials       811      809       -2
Impacted Files Coverage Δ
libs/common/cmap.go 88% <0%> (-2.48%) ⬇️
consensus/state.go 77.09% <0%> (-0.37%) ⬇️
libs/common/kvpair.go 0% <0%> (ø) ⬆️
libs/events/event_cache.go 100% <0%> (ø) ⬆️
p2p/peer.go 61.36% <0%> (+1.13%) ⬆️
consensus/reactor.go 79.01% <0%> (+1.33%) ⬆️
rpc/client/helpers.go 91.3% <0%> (+3.06%) ⬆️

@xla xla force-pushed the xla/adr-peer-transport branch 2 times, most recently from 21c51e0 to 893573d Compare July 25, 2018 20:14
Responsible for emitting and connecting to Peers. The implementation of `Peer`
is left to the transport, which implies that the chosen transport dictates the
characteristics of the implementation handed back to the `Switch`. It is the
place where we enforce low-level guards, like dropping connections from our own
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a list of low level guards we want to enforce anywhere? Its not clear to me what the scope of "low-level" guards is.

// PeerTransport proxies incoming and outgoing peer connections.
type PeerTransport interface {
// Accept returns a newly connected Peer.
Accept() (Peer, error)
Copy link
Contributor

@ValarDragon ValarDragon Jul 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having trouble understanding Accept. Is Accept supposed to evaluate an incoming connection? If so why doesn't it have connection as a parameter.

It seems to me that this should be doing the handshake and secret connection stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having trouble understanding Accept. Is Accept supposed to evaluate an incoming connection? If so why doesn't it have connection as a parameter.

It has nothing to do with connections as the PeerTransport only hands back peers, which may or may not be based on a tcp connection over the wire. Accept is the way for the caller to signal that they are ready to deal with one more incoming Peer.

It seems to me that this should be doing the handshake and secret connection stuff.

The default implementation it will, other transports may not need to that:

tendermint/p2p/transport.go

Lines 101 to 111 in 791c15b

func (mt *multiplexTransport) Accept(cfg peerConfig) (Peer, error) {
a := <-mt.acceptc
if a.err != nil {
return nil, a.err
}
cfg.mConfig = mt.mConfig
cfg.nodeInfo = mt.nodeInfo
cfg.nodeKey = mt.nodeKey
return upgrade(a.conn, mt.handshakeTimeout, cfg)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accept is the way for the caller to signal that they are ready to deal with one more incoming Peer.

Ohh I see. Perhaps this may be more clearly named as "GetPeer"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to avoid getter semantics when possible, in the domain of transport accept and dial are very well understood and the signature already communicates what is returned.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! Thank you for the explanations :)

Responsible for emitting and connecting to Peers. The implementation of `Peer`
is left to the transport, which implies that the chosen transport dictates the
characteristics of the implementation handed back to the `Switch`. It is the
place where we enforce low-level guards[0]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for listing out the intended low-level guards! I still don't really understand what low-level means here.

Are these the set of checks that can only be determined from information in the handshake and the local nodes' configuration? (No knowledge of other peers that this is node is connected to, or how many peers it is currently connected to?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More concretely, I'm confused about why the following aren't here:

"Ensure this isn't a duplicate connection from the same IP" or "Ensure that we don't already have too many peers"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point. Indeed the use of low-level might be missleading as it actually should say domain-specific. As long as we only handle aspects that belong to the transport domain it should be clear. This might result in that protocol/app version check is down somewhere else. Most certainly the check if we already are connected to too many peers belongs in the switch.

Will add the duplicate ip check and rephrase low-level.

* connections from our own node
* handshake fails
* upgrade to secret connection fails
* prevent duplicate ip
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also filter based on:

  • duplicate ID
  • node info compatibility

could also clarify that it doesn't handle max-peers, thats for the switch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will there be another ADR explaining why these are the right choices?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liamsi Which choices are you referring to?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The choices of what was previously called "guards".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be valuable to include some explanation in here as to the "why" for sure

closec <-chan struct{}
listenc <-chan struct{}

addr NetAddress
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nodeAddr

type multiplexTransport struct {
listener net.Listener

acceptc chan accept
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer acceptCh, but feel free to ignore

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't ignore: also, closeCh and listenCh for consistency.


One of the more apparent problems with the current architecture in the p2p
package is that there is no clear separation of concerns between different
components. Most notably the `Switch` is currently doing physical connection
Copy link
Contributor

@liamsi liamsi Jul 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you link to some code (ideally) with a perma-link? I'm not familiar with the current implementation and it makes it easier to read and understand this. e.g. Switch (not only for me but other people reading the ADRs as documentation etc)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I appreciate this point, we need to strike a balance in these ADRs between being an efficient document for design and including enough information for an outsider to keep up. I think to some extent, readers of the ADR should be expected to have some familiarity with the codebase, so that we don't need to worry too much about adding too many links.

### Positive

* free Switch from transport concerns - simpler implementation
* pluggable transport implementation - simpler test setup
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know what you mean but could we use another word here? pluggable transports often means sth. else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you prefer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me the words pluggable transport is overloaded by what I linked above (means tor obfuscate tor traffic as regular https traffic). But yeah in this context it describes correctly what this is about: the ability to plug in different transport implementations. So that's fine.

Copy link
Contributor

@liamsi liamsi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given my limited knowledge about the current p2p layer this looks like a thought through and well-written, concise ADR. In general, I'm in favour of writing these with readers in mind that are not knee deep in the current p2p stack (or, more general, whatever code snippets the ADR is addressing). This only means adding a few links or summarizing with very words where more appropriate.

One of the more apparent problems with the current architecture in the p2p
package is that there is no clear separation of concerns between different
components. Most notably the `Switch` is currently doing physical connection
handling. An artifact is the dependency of the Switch on `config.P2PConfig`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link would be helpful again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to what in that section would you like to see?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xla xla merged commit fd29fd6 into develop Jul 27, 2018
@xla xla deleted the xla/adr-peer-transport branch July 27, 2018 00:27
@xla xla mentioned this pull request Sep 6, 2018
@xla xla restored the xla/adr-peer-transport branch September 18, 2018 20:17
xla added a commit that referenced this pull request Sep 18, 2018
This is the implementation for the design described in ADR 12[0]. It's
the first step of a larger refactor of the p2p package as tracked in
interface bundling all concerns of low-level connection handling and
isolating the rest of peer lifecycle management from the specifics of
the low-level internet protocols. Even if the swappable implementation
will never be utilised, already the isolation of conn related code in
one place will help with the reasoning about execution path and
addressation of security sensitive issues surfaced through bounty
programs and audits.

We deliberately decided to not have Peer filtering and other management
in the Transport, its sole responsibility is the translation of
connections to Peers, handing those to the caller fully setup. It's the
responsibility of the caller to reject those and or keep track. Peer
filtering will take place in the Switch and can be inspected in a the
following commit.

This changeset additionally is an exercise in clean separation of logic
and other infrastructural concerns like logging and instrumentation. By
leveraging a clean and minimal interface. How this looks can be seen in
a follow-up change.

Design #2069[2]
Refs #2067[3]
Fixes #2047[4]
Fixes #2046[5]

changes:
* describe Transport interface
* implement new default Transport: MultiplexTransport
* test MultiplexTransport with new constraints
* implement ConnSet for concurrent management of net.Conn, synchronous
to PeerSet
* implement and expose duplicate IP filter
* implemnt TransportOption for optional parametirisation

[0] https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-012-peer-transport.md
[1] #2067
[2] #2069
[3] #2067
[4] #2047
[5] #2046
xla added a commit that referenced this pull request Sep 18, 2018
This is the implementation for the design described in ADR 12[0]. It's
the first step of a larger refactor of the p2p package as tracked in
interface bundling all concerns of low-level connection handling and
isolating the rest of peer lifecycle management from the specifics of
the low-level internet protocols. Even if the swappable implementation
will never be utilised, already the isolation of conn related code in
one place will help with the reasoning about execution path and
addressation of security sensitive issues surfaced through bounty
programs and audits.

We deliberately decided to not have Peer filtering and other management
in the Transport, its sole responsibility is the translation of
connections to Peers, handing those to the caller fully setup. It's the
responsibility of the caller to reject those and or keep track. Peer
filtering will take place in the Switch and can be inspected in a the
following commit.

This changeset additionally is an exercise in clean separation of logic
and other infrastructural concerns like logging and instrumentation. By
leveraging a clean and minimal interface. How this looks can be seen in
a follow-up change.

Design #2069[2]
Refs #2067[3]
Fixes #2047[4]
Fixes #2046[5]

changes:
* describe Transport interface
* implement new default Transport: MultiplexTransport
* test MultiplexTransport with new constraints
* implement ConnSet for concurrent management of net.Conn, synchronous
to PeerSet
* implement and expose duplicate IP filter
* implemnt TransportOption for optional parametirisation

[0] https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-012-peer-transport.md
[1] #2067
[2] #2069
[3] #2067
[4] #2047
[5] #2046
@xla xla deleted the xla/adr-peer-transport branch September 18, 2018 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C:p2p Component: P2P pkg T:design Type: Design work is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants