vacp2p / nim-libp2p

libp2p implementation in Nim
https://vacp2p.github.io/nim-libp2p/docs/
MIT License
253 stars 55 forks source link

Run nim-libp2p in browser with e.g. WASM #409

Open oskarth opened 4 years ago

oskarth commented 4 years ago

Problem

(This might be the wrong repo for this, not sure).

For Waku v2 to run in browsers we currently have to develop a new (ideally light) client in JS. This leads to duplication of efforts.

It'd be nice to be able to compile nim-libp2p to WASM and have basic transports working. That way it can be used as a kernel, with the JS code being glue code for application developers.

Also see: https://github.com/vacp2p/waku-web-chat/ https://github.com/status-im/nim-libp2p/issues/407 https://github.com/status-im/nim-libp2p/issues/408

Acceptance criteria

Hello world from nim-libp2p in the browser.

sinkingsugar commented 4 years ago

Ideally possible but would require the ARC mode to be working, as the GC is definitely (experience talking) not WASM friendly.

That said I suspect a JS implementation would work better as the backbone would still be JS apis. WASM is mostly meant to compile heavy lifting specific code (say encryption) but when it comes back to use anyway JS calls, directly using JS is likely better, and with libp2p WASM would often call JS/Browser land.

dryajov commented 4 years ago

Ideally possible but would require the ARC mode to be working, as the GC is definitely (experience talking) not WASM friendly.

Any specific info on what causes the GC issues? It should be possible to build the entire thing to C++ and then to WASM with emscripten for example, which should be a pretty complete execution environment, but YMMV.

That said, since we have a pure JS backed it's probably the easiest route and as @sinkingsugar mentioned, we'd still need to call into JS from WASM for all the networking parts either way.

sinkingsugar commented 4 years ago

Well, first and foremost, WASM is literally not designed for GCs because of the memory model, fragmentation happens almost immediately. There is a work in progress official GC but still in very early stage. ( btw yes I know WASM fairly well, used it in few projects ) So yes while nim compiles fine, you will not get to run anything complex easily and sometimes it's actually not possible due to the program simply not fitting the boundaries WASM imposes ( there are parameters yes but not enough ). Also nim GC code for wasm is quite experimental on top of that.

arnetheduck commented 4 years ago

@yglukhov has some experience using the GC with wasm - I'm not sure what version and when, but afair it involved calling the gc explicitly at times - might be worth digging around

dryajov commented 4 years ago

My reasoning was that WASM uses a flat memory model (essentially an array), and it should be possible to map it relatively well to Nim's simplistic GC, but fragmentation is probably the nail in the coffin and requires some address space emulation voodoo. In any case, there is hardly any need for WASM to run libp2p, in fact, for what we need it is probably counterproductive because we'd need to call out to JS for every network interaction, which requires copying to and from the WASM runtime.


Now, in order to make nim-libp2p work in the browser we'd need to:

sinkingsugar commented 4 years ago

@yglukhov has some experience using the GC with wasm - I'm not sure what version and when, but afair it involved calling the gc explicitly at times - might be worth digging around

I built a AI application using nimtorch and WASM for a customer, I think I really know what I am talking about, of course calling full collect every so was very necessary. But in the end it was really a hell of an experience. The final version used gc:regions rather than the regular GC cos the model was too big and would crash when collecting.

sinkingsugar commented 4 years ago

There https://github.com/sinkingsugar/nimtorch/blob/master/examples/webassembly/xor.nim Even this sample had to use gc:regions or would fail. Yeah maybe fiddling with parameters for an indefinite time might make it work for a bit, but doubt it would keep running for very long.

dryajov commented 4 years ago

I really think we should scope WASM to the crypto primitives, there isn't anything else in nim-libp2p that would benefit from it, specially considering the frequent copies to and from the Js runtime for all the networking calls. The crypto primitives on the other hand would be much harder to port to webcrypto(?) and on top of that will most likely end up being slower than the WASM implementation, and memory is probably already deterministic for most crypto stuff, so maybe we can resort to arc/orc for those already.

D4nte commented 3 years ago

@oskarth considering our discussion from yesterday regarding wrapping nim-waku functionalities in WakuJS instead of rewriting them in JS. We agreed that for standard functionalities, a re-write in JS is the most straightforward approach. Using nim code could have some benefits when we start to touch cryptographic functionalities such as spam protection, security and noise related protocol.

Do we know how tightly close with the libp2p layer these functionalities are? Would it be an option to extract those as a lib from waku-nim and have them interact with libp2p-js? Or are they so close to the libp2p layer that we are sure we'll ultimately need to use nim-libp2p in Waku JS?

e.g., for the spam protection, can it be one layer above the libp2p layer, allowing it to be used with libp2p-js instead of nim-libp2p? I am guessing the boundaries may not be clear at this time.

oskarth commented 3 years ago

Currently, I believe all of these types of modules would interact with nim-waku, above nim-libp2p. E.g. RLN spam protection is wrapping a Rust library with Nim bindings and being imported as a submodule to nim-waku. This is outside of nim-libp2p scope.

arnetheduck commented 3 years ago

RLN spam protection is wrapping a Rust library with Nim bindings and being imported as a submodule to nim-waku.

for RLN in particular, although it would be nice to simple compile the nim+rust version to wasm, probably what makes more sense for a browser is to look for an optimized wasm library for the crypto primitives and take it from there - ie something like https://github.com/iden3/snarkjs