protoschool.github.io
protoschool.github.io copied to clipboard
Feature: Add support for libp2p validation
@jacobheun I heard you mention on a call today that the blocker for you to creating meaningful lessons on libp2p in ProtoSchool is that a libp2p node isn't created and you therefore can't do the validation you want to in exercises. I'm sure I'm phrasing that poorly, but I'd love it if you could say more about what would be needed to make the system work for you so that we could potentially add some functionality and turn your content into a ProtoSchool tutorial lesson after IPFS Camp. Thanks!
So, we have a few types of interactive lessons that we've put together. Thinking more through this I think we could workaround some of these things. I'll write this out so we can talk through potential options/improvements.
The first type of lessons, are basic configuration lessons like adding transports, discovery services, stream muxers, etc. These should be fairly straightforward to check in the result
of validate. An example of this configuring TCP and Websockets might look like:
const run = async () => { /* globals TCP, Websockets */
// Return libp2p configuration
return {
modules: {
// Add transports here
},
config: {}
}
}
return run
The second type, are directly calling libp2p methods. For example, adding a protocol handler. This would require us being able to check the libp2p instance they used to verify the correct things were added. We can technically get the libp2p instance from ipfs, ipfs.libp2p
, but I worry that could just cause confusion. If we modify the libp2p instance, do we get that back in the verify
code? If so, instead of checking the result (undefined) we could do some checking on the libp2p instance to make sure it had the protocol registered.
const run = async () => { /* globals ipfs, CustomProtocol */
// Add the CustomProtocol to libp2p
ipfs.libp2p.handle(CustomProtocol.protocolTag, CustomProtocol.handler)
}
return run
The third type involves communicating with other nodes. For protoschool, I think we'd need to be able to mock out some of the code. I don't think it makes sense to have actual dial or discovery code running, but mocking those methods would make it easy for us to verify they're doing the correct thing.
const run = async (peerInfo) => { /* globals libp2p, dialHandler */
// If we could mock/stub `dial` we'd be able to validate it was called with the correct values
libp2p.dial(peerInfo, dialHandler)
}
return run
I think the main challenge with the libp2p lessons right now is that a significant part of the learning is in customizing libp2p itself, as that's the nature of how libp2p is designed (bring what you need). I think there are plenty of lessons we could build around using the libp2p apis (provided we could mock certain things to avoid actual network calls), but I think it's valuable they also start with configuring the specific portion of libp2p needed for that.
If we created a lesson where we could have a build progression, that would be helpful. While we wouldn't use the users results from the previously lesson, starting with the previous lessons solution code could be helpful.
A full example could be something such as working with pubsub. It could involve:
- Configuring libp2p to use pubsub
- Subscribing to topics (starts with the pubsub enabled node from previous step)
- Publishing to topics
@mikeal Since you built the internal workings of ProtoSchool originally and are more familiar with libp2p than I am, would you mind taking a look at @jacobheun's suggestions above? Does this proposal look feasible? Any technical challenges you expect we'd encounter?
As part of our mid-quarter scoring, and in anticipation of a reduction in folks available, we're deprioritizing this to a P2 and don't expect to get to it this quarter unless any volunteers pop out of the woodwork.
@codynhat I believe we chatted about this issue while at Offline Camp. It's something the core ProtoSchool team won't have time for this quarter but we're very open to having others start working on it if it's something that interests you. (I think there was one other person discussing this with us. Was it Tim S.?)
@jacobheun just circling around to see if there's interest from the libp2p team in building out this validation support in the near future. The core ProtoSchool team doesn't have the technical experience to make it happen independently in Q1, but we'd be happy to support the libp2p team in understanding the structure of the project if someone there is able to spend some time on it.
As a reminder, the currently lack of ability to create a libp2p node under the hood is a block to creating validated code challenges for libp2p in ProtoSchool, but we could currently create either text-only or multiple-choice lessons on libp2p concepts.
@terichadbourne we'd definitely like to get something integrated. We're working on finishing up the async refactor for libp2p. Once that's done, the Getting Started guide we're created would, I think, translate nicely into a ProtoSchool lesson/lessons.
@raulk has confirmed that the async refactor for libp2p is complete. @zebateira will update us tomorrow on what he's learned about the limitations of the in-browser JavaScript implementation of libp2p so we can continue the conversation with the team about what under-the-hood setup will best unlock the creation of useful content in ProtoSchool.
Thank you @terichadbourne!
So after my convo with @vasco-santos I learned that the libp2p team is still working out the issue of peer discovery in the browser without a server. The current solution right now is to use a signaling server
.
I think that would work for us since the server would be very low maintenance and low infra requirements. And in the future we would be able to remove it.
But let me know if this is an option for us.
So, we have a few types of interactive lessons that we've put together. Thinking more through this I think we could workaround some of these things. I'll write this out so we can talk through potential options/improvements.
The first type of lessons, are basic configuration lessons like adding transports, discovery services, stream muxers, etc. These should be fairly straightforward to check in the
result
of validate. An example of this configuring TCP and Websockets might look like:const run = async () => { /* globals TCP, Websockets */ // Return libp2p configuration return { modules: { // Add transports here }, config: {} } } return run
The second type, are directly calling libp2p methods. For example, adding a protocol handler. This would require us being able to check the libp2p instance they used to verify the correct things were added. We can technically get the libp2p instance from ipfs,
ipfs.libp2p
, but I worry that could just cause confusion. If we modify the libp2p instance, do we get that back in theverify
code? If so, instead of checking the result (undefined) we could do some checking on the libp2p instance to make sure it had the protocol registered.const run = async () => { /* globals ipfs, CustomProtocol */ // Add the CustomProtocol to libp2p ipfs.libp2p.handle(CustomProtocol.protocolTag, CustomProtocol.handler) } return run
The third type involves communicating with other nodes. For protoschool, I think we'd need to be able to mock out some of the code. I don't think it makes sense to have actual dial or discovery code running, but mocking those methods would make it easy for us to verify they're doing the correct thing.
const run = async (peerInfo) => { /* globals libp2p, dialHandler */ // If we could mock/stub `dial` we'd be able to validate it was called with the correct values libp2p.dial(peerInfo, dialHandler) } return run
I think the main challenge with the libp2p lessons right now is that a significant part of the learning is in customizing libp2p itself, as that's the nature of how libp2p is designed (bring what you need). I think there are plenty of lessons we could build around using the libp2p apis (provided we could mock certain things to avoid actual network calls), but I think it's valuable they also start with configuring the specific portion of libp2p needed for that.
If we created a lesson where we could have a build progression, that would be helpful. While we wouldn't use the users results from the previously lesson, starting with the previous lessons solution code could be helpful.
A full example could be something such as working with pubsub. It could involve:
- Configuring libp2p to use pubsub
- Subscribing to topics (starts with the pubsub enabled node from previous step)
- Publishing to topics
@jacobheun going through your ideas for types of lessons, I think they look great and feasible. So if we go with the strategy to mock libp2p api methods that require network operations, I don't see any limitations on what we can teach at Protoschool.
Now the only concern I have is that we really wanted the libp2p tutorial code challenges to actually run code (not mocks), but since we have tech limitations (if we don't use a sig server), I think it is reasonable. We just need to be careful about making sure the code we present to the user is as close as possible to a real code example.
@terichadbourne @raulk @vasco-santos and me had a call today to discuss where to go from here.
-
libp2p node transport/discovery:
- after some thoughts on it, we don't believe mocking is a good sustainable solution: it is a fragile approach with regards to future maintenance of the validation code. A simple major release upgrade is already a lot of work, so on top of that supporting unofficial changes to the internals is not something we can afford to do.
- @raulk mentioned two other ideas to explore (besides the signalling server):
window.postMessage
andService Workers
-
Content: Tutorial Ideas and others
- it's important to stress that libp2p has a lot of implementations, not only js
- @raulk gave other specific ideas for content:
- create a custom transport as an advanced tutorial
- mention that libp2p nodes can communicate between each other, regardless of the implementation, so it would be nice to have a "
js-libp2p
" node communicating with a "go-libp2p
" node in an advanced lesson.
- regarding other possible future content here are some other resources:
-
Next:
- I'll proceed with investigating if it is possible to have local discovery with either
window.postMessage
orService Workers
(with the help of @vasco-santos if needed) by creating a custom transport.
- I'll proceed with investigating if it is possible to have local discovery with either
🔄 Update on this:
- I'm almost done creating a memory transport for js: https://github.com/zebateira/js-libp2p-memory
- So instead of using
window.postMessage
orService Workers
we can just have two nodes connect to each other in-memory - You can see the latest work on the branch libp2p-memory.