-
Notifications
You must be signed in to change notification settings - Fork 108
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
Expose simple whisper api to C / go #331
Conversation
nimbus/status_api.nim
Outdated
discard initENode(nodeId, bootnode) | ||
bootnodes.add(bootnode) | ||
|
||
asyncCheck node.connectToNetwork(bootnodes, true, true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you don't want to wait here? The peerPool.connectToNode
call below seems a bit dangerous, given that node.peerPool.start()
is called in a non-immediate way inside connectToNetwork
.
Maybe it works by accident now, but the assumptions about the API seem fragile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, we're just playing around, it's totally wrong (copied from stratus).. want to see what it would take to call nim from go (!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, so waiting runs the polling loop I presume?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
waitFor
here will poll()
yes. But should only be used at "top-level", so that it can not end-up in another poll
.
@zah, running connectToNode
when the peer pool is not started yet should not be an issue no? I did the same in nimbus here: https://github.com/status-im/nimbus/blob/master/nimbus/nimbus.nim#L127
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that depends a bit of how much of a stateful black box one wants to turn the api into, vs a more lightweight and flexible collection of utilities.. if we block here, we force the caller to run this stuff in a dedicated thread basically - if instead we do more of a callback-based model, they have more control and can integrate it better with whatever they're running, but we lose some control / it becomes slightly easier to mess up.
in either case, it will be somewhat difficult to reconcile the magic that goes on behind our back in the async macro transformations with a flexible C api.. will have to tread carefully here with these features that don't have a good representation in the C world.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But should only be used at "top-level", so that it can not end-up in another poll.
stuff like this is a mess to remember about an API 😞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can provide a callbacks-style API on the C side. Nim will be able to handle this with a more direct usage of future.addCallback
instead of await
. Maybe it's a bit too early to jump the gun, but it's quite likely that this style will appear elsewhere in the API.
This is more of an integration issue with I assume there's some clever way of wrapping/inling/overwriting to ensure these symbol name conflicts are dealt with, but I'm not sure what that looks like. Any ideas @cammellos @arnetheduck? Inside
|
Right, both nim and go link stuff statically, and might not be using the same version of these two libraries. sigh.. this could take a bit of tinkering to get right - one would have to figure our the versions in use and make sure they're not conflicting, then select one of them - not sure if this is easier to do on the go or nim side - ie disabling the inclusion of libsecp256k1.. in nim, it would involve adding a special compile flag to here: https://github.com/status-im/nim-secp256k1/blob/master/secp256k1.nim#L12 when not defined(noCompileSecp):
{.compile... then, when compiling status_api.nim, add |
Unable to strip secp256k1 symbol names from With the following changes:
I see this for local compile:
I've also tried deleting Adding compiler flag to status api script:
Also added to build script:
Running
No
Perhaps it is being included elsewhere? |
I also notice the following when I remove
With:
|
Debug log: https://gist.github.com/oskarth/3667fe4aca3bbf64352c6a227ecf3a66#file-gistfile1-txt-L390 @stefantalpalaru pointed out that archive file is appending. Doing
Running |
The two libraries appear to be different, at least partly:
|
|
Update: shared library resolves the above issue. Now Nimbus can be run from inside status-console-client. However, as soon as it starts up (right after finding some peers and printing some logs) it gets seg faulted. This happens within a few seconds of startup, and sometimes it gets a bit further than other times. However, it is never enough to actually send through a message through Whisper. Relevant lib: https://github.com/status-im/status-nim and PR status-im/status-console-client#79 Here's the stacktrace with debug symbols: https://gist.github.com/oskarth/771034417a52927fa9bbc6df415d5714 |
Tried with naive prelude of setupForeignThreadGc() (not quite sure how it is supposed to be used, teardown etc) and GOMAXPROCS=1. Now it hangs like this: https://gist.github.com/oskarth/c3f4392e84c279c433474d31b3173737 (stuck at L73, sometimes it gets further but not by much. Same if GOMAXPROCS=8 though usually gets quite a bit further) (Same result if I add |
Since the secp shared lib thing is resolved we can get a minimally failing version in this PR. Perhaps some Nim/C experts can help reproduce and debug this? Not too familiar with how the threading/GC etc works. How to reproduce:
You might need to tweak the LDFLAG in main.go. Hangs with following stacktrace:
|
Using On the Go side, it still needs some hooking up to be used for 1:1/public chats etc, but a bridge has been created! Once v1 is out of the way, I expect we can start to push getting all basic use cases solved and start to (at least be able to) use Nimbus instead of Geth. Step by step. On the Nim side, what do we need to do to get this PR merged? It's quite hacky code and I'm not sure what policy you guys use, but it'd be good to have it in trunk, especially for future Go dev integration improvements. Is there something that needs to be done to make that happen in terms of isolating changes / hiding them under flags etc? We can also have a fork but seems meh. The go stuff isn't needed here, but might be good for future enhancements/testing (better threading support?) as it allows isolated end to end testing. It's up to you guys though. There's also the start of a status-nim lib (more like a Go lib now) here with first issue status-im/nim-status#1, it might make sense to put some Status specific Nim stuff there. cc @arnetheduck |
We are working on a plan to make the Nim's side of the APIs more thread-safe, so the GO hacks can be removed. Should be ready in the next two weeks, stay tuned. Otherwise, I think this PR just needs a final round of reviews and it will be ready for merging. |
Next to what zah commented, another question I would ask ourselves is to better understand what our end goals are here. Or at least some idea regarding this. With this Whisper API we actually don't use anything from the Nimbus repo specifically (except its name), so it doesn't necessarily need to be in the Nimbus repository. However, if we are planning to expose more than just the Whisper part in the future, it could make sense to keep it here. The Nimbus repository could be the general location to expose all this, but it doesn't have to be. Ideas? |
nimbus/build_go.sh
Outdated
@@ -0,0 +1,2 @@ | |||
#!/bin/sh | |||
go build --ldflags '-extldflags "-static"' -o test main.go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure @stefantalpalaru would like to provide make targets for these build scripts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go building happens in separate lib, we can remove this script from here if we want to keep it clean. It's more to have a self-contained failing case for debugging thread stuff.
nimbus/status_api.nim
Outdated
discard initENode(nodeId, bootnode) | ||
bootnodes.add(bootnode) | ||
|
||
asyncCheck node.connectToNetwork(bootnodes, true, true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can provide a callbacks-style API on the C side. Nim will be able to handle this with a more direct usage of future.addCallback
instead of await
. Maybe it's a bit too early to jump the gun, but it's quite likely that this style will appear elsewhere in the API.
to truly integrate as a library, we should probably define a set of callbacks and hooks so that the event loop of the calling application can be used. This typically means hooks to register for epoll etc. Libraries that run their own thread are inherently less flexible because not all environments allow access to threads or loop-running (ie in browser) - a really proper solution would have the hooks etc and maybe a convenience option to run a thread with a loop as well as a polling solution that avoids the events / epolls completely. all that is long term though. |
nimbus/status_api.nim
Outdated
var | ||
node: EthereumNode | ||
|
||
proc subscribeChannel( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would need to return the filter ID if we ever want to unsubscribe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added as TODO in-line
nimbus/status_api.nim
Outdated
|
||
subscribeChannel($channel, c_handler) | ||
|
||
proc nimbus_post(payload: cstring) {.exportc.} = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add signing key as parameter.
How would we do key management? In nimbus (like in rpc) or in status go?
How is this done now in status / status cli?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added as TODO, all good questions but seems out of scope of this spike - let's revist later
nimbus/status_api.nim
Outdated
pow*: float64 | ||
hash*: Hash | ||
|
||
proc nimbus_subscribe(channel: cstring, handler: proc (msg: ptr CReceivedMessage) {.gcsafe, cdecl.}) {.exportc.} = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should rename nimbus_subscribe and nimbus_post to something that explains it is a status public chat post/subscribe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added as todo to figure out
nimbus/status_api.nim
Outdated
for i in 0..<4: | ||
topic[i] = channelHash.data[i] | ||
|
||
discard node.postMessage(symKey = some(symKey), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle error case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added as TODO in-line
80e8540
to
194a17f
Compare
Addressed most basic feedback and added some TODOs inline. Also fixed rebase/submodules (was targeting master before, oops). All the API design questions etc are great and important. However, at this stage I think the main goal should be to save the spike progress somewhere (such as in trunk) and then we can revisit and clean things up, do proper error handling, think about where things should live etc (Nimbus, status-nim, status-console-client, other lib?). Does that sound reasonable to people? |
To avoid GC/thread issues causing segmentation fault when running from Go.
7b8754b
to
fd60da5
Compare
Regarding the use of static library, for the time being I'm passing |
don't merge, just playing around