Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Implementation of delegated routing based on the Edelweiss compiler #11

Merged
merged 46 commits into from
May 4, 2022

Conversation

petar
Copy link
Contributor

@petar petar commented Mar 8, 2022

@petar petar requested a review from aschmahmann March 8, 2022 16:39
@BigLep BigLep added this to the go-ipfs 0.13 milestone Mar 8, 2022
@BigLep
Copy link

BigLep commented Mar 8, 2022

@petar : probably my naivety not to know or see it, but can you provide:

  1. command/process you ran to generate this code?
  2. the schema that was used for the generation?

@petar
Copy link
Contributor Author

petar commented Mar 8, 2022 via email

gen/routing.go Outdated Show resolved Hide resolved
@BigLep
Copy link

BigLep commented Mar 11, 2022

A couple of thoughts here: I'm sure there's legit and genuine curiosity here given that this is some of the first generated code we're seeing come out of Edelweiss (great). I know @petar needs something to target towards and is using the existing proposed schema. We ultimately though need to get the schema fully decided as part of #8.

Thanks @petar for doing some explanation. I know it's on the Edelweiss project roadmap to be working more on docs and communication this month. It looks like those will be welcome and appreciated! Good stuff!

@BigLep
Copy link

BigLep commented Mar 29, 2022

Moving back to in progress because this can't be in review until the spec ipfs/specs#272 is completed.

@BigLep BigLep marked this pull request as draft March 29, 2022 16:39
@BigLep
Copy link

BigLep commented Apr 4, 2022

@petar : thanks for owning this and make the updates for ipfs/specs#272. I'm assuming once the spec changes fully land, you'll keep updating this.

Also, given we don't want to spend people's time reviewing the generated code itself, it would be great if the unit test coverage on go-delegated-server was pretty high for client/server communication so that we can have confidence in the generated code as a result. (I'm saying that as a general statement. I don't know how high unit test coverage is right now, but if it should have more, let's please include it.)

@petar petar marked this pull request as ready for review April 12, 2022 14:45
@petar
Copy link
Contributor Author

petar commented Apr 12, 2022

@aschmahmann First draft of delegated routing using the new Reframe API is ready. You can do a pass on this PR and then let's regroup to discuss next steps. At the moment, this PR implements the content routing interface which we already use to connect delegated routing into Hydra. As such, this PR is a drop-in replacement for the current delegated routing in master.

In particular, Get/PutIPNS are not implemented. Also, FindProviders extracts the AddrInfo of all returned provider nodes, regardless of which transport protocols they offer. Perhaps we need to filter out only the bitswap providers, or otherwise we need to extend the Go content routing interface to capture supported transfer protocols.

If I recall correctly, you also want to go a step further and implement a more general content routing interface so that it can be used both in Hydra and IPFS? Let's discuss what that would be.

@petar
Copy link
Contributor Author

petar commented Apr 12, 2022

@aschmahmann I finished all remaining items we mentioned at standup today:

  • FindProviders filters Bitswap nodes
  • GetIPNS and PutIPNS included in the Go interface
  • Test covers all code-generated code (all method calls)

@aschmahmann
Copy link
Contributor

aschmahmann commented Apr 13, 2022

@petar can you hook this up to unified CI? I'm seeing the tests fail and/or hang locally (Windows).

@petar
Copy link
Contributor Author

petar commented Apr 13, 2022 via email

func buildPeerFromAddrInfo(addrInfo peer.AddrInfo) *proto.Peer {
pm := make([]values.Bytes, len(addrInfo.Addrs))
for i, addr := range addrInfo.Addrs {
// XXX: Adin, please, verify this is as intended.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@aschmahmann Please, verify this is as intended. PeerAddrs are created from whatever the server-implementing user passes. The code rewrites the multiaddresses to make sure they conform to the spec.

Copy link
Contributor

Choose a reason for hiding this comment

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

A peer.AddrInfo should not have the last component be a /p2p/peerID in any event. For example some functions that would stop working include https://github.com/libp2p/go-libp2p-core/blob/02cbdcc4191b0f512c6cf4f2b1a8eeaaf32f1061/peer/addrinfo.go#L88

We could clean the data here, but really if this is happening then something else is likely wrong with your application. To me this means either we should just pass it through without validation, or when we validate and there's a problem we should return an error to the application to let them know they passed in invalid input.

}
infos = append(infos, *ai)
// ParseNodeAddresses parses peer node addresses from the protocol structure Peer.
// XXX: Adin, please, verify this is as intended.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@aschmahmann Please, verify this is as intended.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good 👍

@petar
Copy link
Contributor Author

petar commented Apr 27, 2022

@aschmahmann I've addressed all the comments. Please take another look.

Copy link
Contributor

@aschmahmann aschmahmann 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! The main comments are around lack of validation of the responses we get as a client and missing chunks of the IPNS records.

For the IPNS records I'm fine if you'd prefer to split it into a different PR, but I don't think it'll be too much if you want to do it here (i.e. do validation and some basic testing).

}
infos = append(infos, *ai)
// ParseNodeAddresses parses peer node addresses from the protocol structure Peer.
// XXX: Adin, please, verify this is as intended.
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good 👍

func buildPeerFromAddrInfo(addrInfo peer.AddrInfo) *proto.Peer {
pm := make([]values.Bytes, len(addrInfo.Addrs))
for i, addr := range addrInfo.Addrs {
// XXX: Adin, please, verify this is as intended.
Copy link
Contributor

Choose a reason for hiding this comment

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

A peer.AddrInfo should not have the last component be a /p2p/peerID in any event. For example some functions that would stop working include https://github.com/libp2p/go-libp2p-core/blob/02cbdcc4191b0f512c6cf4f2b1a8eeaaf32f1061/peer/addrinfo.go#L88

We could clean the data here, but really if this is happening then something else is likely wrong with your application. To me this means either we should just pass it through without validation, or when we validate and there's a problem we should return an error to the application to let them know they passed in invalid input.

client/contentrouting.go Outdated Show resolved Hide resolved
client/findproviders.go Outdated Show resolved Hide resolved
client/contentrouting_test.go Show resolved Hide resolved
client/contentrouting_test.go Outdated Show resolved Hide resolved
test/clientserver_test.go Outdated Show resolved Hide resolved
test/clientserver_test.go Outdated Show resolved Hide resolved
client/findproviders.go Outdated Show resolved Hide resolved
close(addrInfoCh)
return addrInfoCh
}
go func() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Thoughts (not blockers for merge):

Not sure if this is avoidable but wanted your thoughts on this. It looks like every abstraction layer involving a channel turns into another goroutine to pull x from the channel and return f(x) into a new channel.

Maybe once generics become more widely supported in our codebase (once Go 1.19 is released) this will become easier by letting us return generic channels and pass in functions to convert between types so a goroutine isn't required.

To be fair short lived goroutines aren't necessarily a big issue unless we're doing them on mass so we can cross this bridge when it becomes a problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Without generics, we would need to resort to empty interfaces, which I think makes the code very unmanageable. I lean towards code readability unless there is a clear performance problem. And indeed it seems like Go generics can fix this issue.

go.mod Outdated Show resolved Hide resolved
go.mod Outdated Show resolved Hide resolved
go.mod Outdated Show resolved Hide resolved
test/clientserver_test.go Show resolved Hide resolved
client/getipns.go Outdated Show resolved Hide resolved
client/getipns.go Outdated Show resolved Hide resolved
client/getipns.go Outdated Show resolved Hide resolved
client/getipns.go Outdated Show resolved Hide resolved
client/getipns.go Outdated Show resolved Hide resolved
@petar
Copy link
Contributor Author

petar commented May 3, 2022

@aschmahmann It's worth another look. I think I've addressed all comments in this round.

Copy link
Contributor

@aschmahmann aschmahmann 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! There may be some more things we learn about here and need to improve the wrapper APIs down the road, but this is enough for us to make some good progress trying to integrate.

Thanks for all the hard work here 🙏

@petar
Copy link
Contributor Author

petar commented May 4, 2022

@aschmahmann Here's what I am thinking should be next steps:

  • I'll make a release on Edelweiss at its current commit
  • Bump the dependencies here on the Edelweiss release
  • Merge this PR
    Then:
  • Start a Hydra PR that utilizes this PR
  • Then we need to discuss re-deployment of Hydra
    Sound good?

@aschmahmann
Copy link
Contributor

@petar sounds like a plan to me 😄. In order for the hydras to properly utilize it there needs to be some server responding to Reframe requests.

However, you might save yourself some pain by working on getting the indexers to serve the data using Reframe earlier. Otherwise you'll have to get the Hydras to support both the Indexer and Reframe endpoints.

Your call though, if you think it'll be easier to start off working in the Hydras then start there.

@petar petar merged commit 2bc3457 into main May 4, 2022
@petar
Copy link
Contributor Author

petar commented May 5, 2022

@petar sounds like a plan to me 😄. In order for the hydras to properly utilize it there needs to be some server responding to Reframe requests.

However, you might save yourself some pain by working on getting the indexers to serve the data using Reframe earlier. Otherwise you'll have to get the Hydras to support both the Indexer and Reframe endpoints.

Your call though, if you think it'll be easier to start off working in the Hydras then start there.

Sounds good! Thanks for reviewing this monster PR :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

load test auto-generated server/clients as part of CI
4 participants