Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: implement BIP-155 addrv2 support #1812

Merged
merged 3 commits into from
Apr 13, 2022
Merged

Conversation

Crypt-iQ
Copy link
Collaborator

@Crypt-iQ Crypt-iQ commented Feb 11, 2022

Commit overview:

  • wire: netaddressv2 and tests adds (de)serialization routines for BIP-155 addresses. It also allows wire.NetAddress to be converted into wire.NetAddressV2.
  • multi: update addrmgr, server to use NetAddressV2 instead of legacy updates the address manager to use wire.NetAddressV2 internally and does so without a database upgrade. The server is also updated to use wire.NetAddressV2 where appropriate.
  • peer+wire: add addrv2 message, protocol negotiation implements the p2p negotiation of BIP-155 (sendaddr, addrv2) and updates the peer to use wire.NetAddressV2 where appropriate. The tests here were modified to not use io.Pipe in some cases due to the implementation of the BIP-155 "handshake" not working with a synchronous read/write pipe.

Closes #1671 as this pull ignores unknown messages both during version-verack (as does bitcoind) and after the version-verack handshake.

Fixes #1671

@coveralls
Copy link

coveralls commented Feb 11, 2022

Pull Request Test Coverage Report for Build 1894615664

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 79.676%

Totals Coverage Status
Change from base Build 1808348675: 0.0%
Covered Lines: 1231
Relevant Lines: 1545

💛 - Coveralls

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

Great work! Completed an initial pass, and will start to run this using btcd and neutrino on testnet

My main question is regarding backwards compatibility: are we still able to read the old addr v1 JSOn messages? As a follow up: will we convert all the addrv1 to addrv2 on disk when we first start using this PR?

wire/netaddressv2.go Show resolved Hide resolved
wire/netaddressv2.go Show resolved Hide resolved
wire/netaddressv2.go Show resolved Hide resolved
wire/netaddressv2.go Outdated Show resolved Hide resolved
addrmgr/addrmanager.go Show resolved Hide resolved
peer/peer.go Show resolved Hide resolved
peer/peer.go Outdated Show resolved Hide resolved
for {
remoteMsg, _, err := p.readMessage(wire.LatestEncoding)
if err == wire.ErrUnknownMessage {
continue
Copy link
Member

Choose a reason for hiding this comment

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

Log the message?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

remoteMsg is nil here, would need to bubble up the command string. Could also log it at a lower level inside one of the readMessage helper functions

peer/peer.go Outdated Show resolved Hide resolved
peer/peer.go Show resolved Hide resolved
@Roasbeef
Copy link
Member

Giving this a spin on mainnet+testnet now.

@Roasbeef
Copy link
Member

Attempted to do a diff of my peers.json file before and after, but then realized that won't really help here, since map iteration order and json encoding aren't deterministic...

@Roasbeef
Copy link
Member

cc @ellemouton

Copy link
Contributor

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

Looks good! Did a pass, left some nits & questions. Tested on regtest that nodes running this patch can successfully complete the handshake with older and newer btcd nodes and with new bitcoind nodes.


// maxNetAddressV2Payload returns the max payload size for an address used in
// the addrv2 message.
func maxNetAddressV2Payload() uint32 {
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason not to have a hardcoded const for this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nope, can change, just wanted to show the derivation

legacyNa.IP = a.addr[:]
case *torv2Addr:
legacyNa.IP = a.onionCatEncoding()
case *torv3Addr:
Copy link
Contributor

Choose a reason for hiding this comment

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

should this not just be the default case so that we catch future network ID types too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it could just be updated when BIP155.2 comes out? We already ignore unknown network IDs from our peers, so this should only be called for netIDs we know about


type ipv4Addr struct {
addr [ipv4Size]byte
netID networkID
Copy link
Contributor

Choose a reason for hiding this comment

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

since network ID is fixed per addr type, should we not either remove this field and have the Network() func return a const or add a newIPV4Addr(addr) func that sets the netID to a const?

Copy link
Contributor

Choose a reason for hiding this comment

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

that also avoids us having to do

addr := &ipv4Addr{}
addr.netID = ipv4 

etc in the NetAddressV2FromBytes func

Copy link
Contributor

Choose a reason for hiding this comment

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

same could likely go for the addr size

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Network() returns a string, and is only provided to make the structs conform to the net.Addr interface, so we'd have to convert back and forth to an int which I wanted to avoid. I think a newIPV4Addr and related constructors might work, but there may have been a reason I'm forgetting that I didn't do this. How would addr size fit in here?

} else {
// This is an non-nil IP address that was parsed in the else if
// above.
na = wire.NetAddressV2FromBytes(time.Now(), services, ip, port)
Copy link
Contributor

Choose a reason for hiding this comment

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

should we not have an err check here rather and make NetAddressV2FromBytes return an error in its default case? cause if we are host here doesnt match any of the above cases nor any of the cases in NetAddressV2FromBytes, then we will return a non-nil NetAddressV2 here with an empty Addr

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If this branch is reached, then ip is either an IPv6 or IPv4 address. The parsing is a little funky because the above branch actually sets ip here. So NetAddressV2FromBytes should hit the ipv4/ipv6 case and return no problem

@@ -585,7 +592,7 @@ func (p *Peer) ID() int32 {
// NA returns the peer network address.
//
// This function is safe for concurrent access.
func (p *Peer) NA() *wire.NetAddress {
func (p *Peer) NA() *wire.NetAddressV2 {
Copy link
Contributor

Choose a reason for hiding this comment

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

i think these peer changes need to be in the previous commit else it does not compile.

Comment on lines +355 to +356
if addr.IsTorV3() {
continue
Copy link
Contributor

Choose a reason for hiding this comment

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

seems we check if the addr is tor v3 both here and in ToLegacy. cant we just return a "NotSupported" error or something from the default case in ToLegacy?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I guess it's a matter of preference of receiving an error vs receiving a bool or nil

server.go Show resolved Hide resolved
Comment on lines +2226 to +2233
var protoVersion uint32
p.flagsMtx.Lock()
protoVersion = p.protocolVersion
p.flagsMtx.Unlock()

if err := p.writeSendAddrV2Msg(protoVersion); err != nil {
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

out of interest (more a question about the spec, not the impl) why do we need to send a sendaddrV2 message to indicate that we want addrv2s if we have already gating this on negotiated version? ie, cant the peer tell from our version that we want v2 and vice versa?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since addrv2 did not come with a version bump (wtxidrelay also uses 70016 - WTXID_RELAY_VERSION in bitcoin core code), it wouldn't be possible to know if your peer supports addrv2 on the version alone (maybe they only support wtxidrelay). This approach is used by bitcoin core now to introduce new feature via messages (during handshake). I think version bumping could have been done, but maybe there's some other reason. In other words, I dont know

Copy link
Member

Choose a reason for hiding this comment

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

Yeh agree that a version bump should have been done instead, as the current interactive negotiation stuff just serves to make the logic to figure out which features you can use more complicated, vs the way we do things on the LN side re looking at the feature bit intersection.

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

LGTM 🐙

@Roasbeef Roasbeef merged commit bf64c8b into btcsuite:master Apr 13, 2022
@Crypt-iQ Crypt-iQ deleted the btcd_addrv2 branch April 13, 2022 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants