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
added eth-provider files for pull request #5909
base: develop
Are you sure you want to change the base?
Conversation
Okay ladies and gentlemen, it is finally time to start the process to get this merged into
|
@belisarius222 assigning this one to you for review to put it on your radar |
@belisarius222 ping on this for review and/or next steps. |
I don't know that much about these parts of the system. @Fang- would you be able to review this? |
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.
Let's start with some broad, high-level feedback:
We decided to create a separate
/lib/eth-provider
that mimics the API of/lib/ethio
instead of modifying/lib/ethio
directly. Is this sane?
This description made it sound like the new lib would be a more-or-less drop-in replacement for /lib/ethio
. Maybe dropping the url=@t
from all the samples, but otherwise the same arms with the same signatures. I'd say that's sane and reasonable. But turns out that's not what this is!
Not a fan of encoding the different functionalities provided by /lib/ethio
in a $%
like $ethin
. Would much rather see a /lib/eth-provider
that looks structurally like /lib/ethio
, and just replaces the function bodies with essentially lines 13-30 of the current /lib/eth-provider
.
I guess the underlying reasoning for the current approach is that we still need to send some noun over the wire if we depend on a provider ship, so might as well write an $ethin
and $ethout
. But $request:rpc:ethereum
seems like a much better fit for this. I think it's preferable to only ask providers for formal noun-encoded requests, as opposed to sending them arbitrary rpc json.
Might be a good time to flesh out $response:rpc:ethereum
as well, in place of $ethout
. Unsure if resolving this long-standing todo would be considered scope creep on the grant though... (May or may not need to be $-([request json] response)
, in any case.)
urbit/pkg/base-dev/lib/ethereum.hoon
Line 862 in dac240b
::TODO ++ parse-response |= json ^- response |
Also, some of the code here is laid out exceptionally dense, and would be made more readable with better indentation and more breathing room.
Ok @Fang- I'd say that this is significantly more sane and reasonable since you last took a look. Incorporated all of your feedback. |
@pkova is going to investigate why this has 14,000 additions across 107 files. |
788a621
to
cadbef0
Compare
Ok, fixed the problem, replaced the files. |
@Fang- this is ready, please take another look |
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.
This is a lot better already, thank you for your changes so far!
I do still have some comments on the shape by which requests get sent to the provider, and how the provider handles those. The two main points here are around $request:rpc:ethereum
vs ethio
, and around uniqueness of request identifiers.
Outside of that, the provider's state can be clarified a bit, but this feels directionally correct now. I also left some style comments in specific places, but the advice applies more broadly than just the diffs I highlighted.
pkg/arvo/sur/eth-provider.hoon
Outdated
=provider | ||
=client | ||
== | ||
+$ topics (list ?(@ux (list @ux))) |
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.
Given that both /sur/eth-watcher, /lib/ethio, and this implement this same type, might be time to move it into /lib/ethereum or maybe +ethereum-types
, and have them all import from there instead.
+$ ethin | ||
$% |
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.
Any particular reason this matches the arms in /ted/ethio
instead of the $request:rpc
type from /lib/ethereum
?
They're pretty close and don't differ that much, but iirc the latter sticks as close as it can to the official Ethereum RPC API, whereas the former is more focused around urbit-side implementation details. If possible, I think it would be preferable to have this be something along the lines of:
+$ ethin (list [id=(unit @t) req=request:rpc:ethereum])
With maybe extra flags or w/e for if you want it to be handled as "strict" or "loose" in the case of multiple requests. (Though imo over the network the provider should just always give you all the responses it can get, you can decide on "tightness" locally.)
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.
Now the eth-provider is a drop-in replacement to ethio. The ethio requests in threads are basically forwarded as they are to the provider, but if we go with the $request:rpc
type we would need to convert the ethio
requests to $request:rpc
and back. I think it might make sense to use $request:rpc
if people would want to send requests not in the ethio
format, but otherwise it is unnecessary to change this. (If we do want to switch to $request:rpc
, we would also need to modify or duplicate lib/ethio
to support the new eth-provider).
pkg/arvo/sur/eth-provider.hoon
Outdated
$% [%set-local =local] | ||
[%set-provider =provider] | ||
[%set-client =client] | ||
[%provide tid=@ta =ethin] |
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.
This probably shouldn't be called a tid
for "thread-id", and certainly shouldn't be used as such by /app/eth-provider
. If two ships both decide to construct their request identifiers as sequential numbers, they run a serious risk of conflicting. I propose rid
for "request-id", but anything in that direction would be fine.
pkg/arvo/app/eth-provider.hoon
Outdated
=/ tid +<.action | ||
=/ eth-input +>.action | ||
=/ start-args | ||
[~ `tid byk.bowl(r da+now.bowl) %eth-provider !>(eth-input)] |
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.
As mentioned in the comment on the /sur/eth-provider
file, we shouldn't be reusing the bare request-id for the thread-id here.
It may be appropriate to concatenate it with the requester's ship name (or provide the ship name as the "parent thread id"?), and use that for the thread id instead. Provides some legibility, and prevents the client from submitting multiple requests with the same id (spider would crash), without any extra implementation effort on our part.
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.
And similar to that point, if the final $ethin
structure we end up settling on ends up including a request id that is meant to get sent to the Ethereum node, we'll probably want to prefix that with the requester's @p
, just to make sure that id, too, is actually unique.
pkg/arvo/app/eth-provider.hoon
Outdated
?+ path (on-watch:def path) | ||
[%updates @ ~] | ||
:_ this ~ | ||
== |
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.
Right now, if I can guess what request/thread IDs you're using, and we both have access to the same provider, I can snoop on the responses to your requests, and infer your requests from that.
I don't think it's a big leak by any means, but it would be nice if it was shielded against. Additionally, "responses" might make more sense than "updates". With that in mind, consider:
/responses/[ship]/[request-id]
Where ship
must equal src.bowl
for the watch to be successful, and request-id
is just whatever identifier that ship will be providing in their %provide
pokes.
pkg/arvo/lib/eth-provider.hoon
Outdated
?- -.arg | ||
%request-rpc | ||
;< out=json bind:m (request-rpc:ethio url +.arg) | ||
(pure:m [%request-rpc out]) | ||
%request-batch-rpc-strict | ||
;< out=(list [id=@t =json]) bind:m | ||
(request-batch-rpc-strict:ethio url +.arg) | ||
(pure:m [%request-batch-rpc-strict out]) | ||
%request-batch-rpc-loose |
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.
Big ?-
blocks like these would be easier to read with better indentation and some spacing:
?- -.arg | |
%request-rpc | |
;< out=json bind:m (request-rpc:ethio url +.arg) | |
(pure:m [%request-rpc out]) | |
%request-batch-rpc-strict | |
;< out=(list [id=@t =json]) bind:m | |
(request-batch-rpc-strict:ethio url +.arg) | |
(pure:m [%request-batch-rpc-strict out]) | |
%request-batch-rpc-loose | |
?- -.arg | |
%request-rpc | |
;< out=json bind:m (request-rpc:ethio url +.arg) | |
(pure:m [%request-rpc out]) | |
:: | |
%request-batch-rpc-strict | |
;< out=(list [id=@t =json]) bind:m | |
(request-batch-rpc-strict:ethio url +.arg) | |
(pure:m [%request-batch-rpc-strict out]) | |
:: | |
%request-batch-rpc-loose | |
etc... |
pkg/arvo/sur/eth-provider.hoon
Outdated
[%get-logs-by-hash =hash:block contracts=(list address) =topics] | ||
$: | ||
%get-logs-by-range | ||
contracts=(list address) | ||
=topics | ||
=from=number:block | ||
=to=number:block | ||
== | ||
[%get-next-nonce =address] | ||
[%get-balance =address] | ||
== | ||
+$ ethout | ||
$% | ||
[%request-rpc res=json] | ||
[%request-batch-rpc-strict res=(list [id=@t =json])] |
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.
You don't need to keep the first line of n-ary runes clear like this. But for bigger blocks among one-liners, I would add some spacers:
[%get-logs-by-hash =hash:block contracts=(list address) =topics] | |
$: | |
%get-logs-by-range | |
contracts=(list address) | |
=topics | |
=from=number:block | |
=to=number:block | |
== | |
[%get-next-nonce =address] | |
[%get-balance =address] | |
== | |
+$ ethout | |
$% | |
[%request-rpc res=json] | |
[%request-batch-rpc-strict res=(list [id=@t =json])] | |
[%get-logs-by-hash =hash:block contracts=(list address) =topics] | |
:: | |
$: %get-logs-by-range | |
contracts=(list address) | |
=topics | |
=from=number:block | |
=to=number:block | |
== | |
:: | |
[%get-next-nonce =address] | |
[%get-balance =address] | |
== | |
+$ ethout | |
$% [%request-rpc res=json] | |
[%request-batch-rpc-strict res=(list [id=@t =json])] |
pkg/arvo/ted/eth-provider.hoon
Outdated
%client | ||
(pure:m !>(eth-output)) | ||
== | ||
++ call-ethio |
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 this (and maybe some of the other logic here) is already implemented in /lib/eth-provider
, so can de deduplicated here.
Talked briefly with @philipcmonk about this. We'll probably want to revert the changes to the roller and eth-watcher threads here, because those have an important edge case to deal with: what if your provider breaches? We can just let them keep doing their static-url thing for now, I wouldn't consider accounting for that case in scope for this PR. |
@bzol any updates? |
Co-authored-by: fang <github@fang.io>
@Fang I modified eth-provider according to your suggestions, except this issue: #5909 (comment) |
Okay, I've changed the provider mode to accept |
The From my first review:
Given that the old To reiterate from our last call, I think the most straightforward API here is one where you give the /app/eth-provider a
Yes a timeout seems right. In theory they'll "resolve eventually" but that might not be very nice developer ergonomics. For the ask-over-HTTP case I think Iris times out requests eventually, so would make sense to match that here.
There's another option here, where you only open a single subscription per thread and just receive multiple facts on it. Might require you to check "did we open a subscription for this thread yet" everywhere, but shouldn't be hard to factor that out. I'm not requiring this, but it might be a nicer solution.
If you receive a |
This is ready for review again, we changed the types so now the eth-provider uses both request and response:rpc:ethereum, and added a 10 second timeout that makes the lib/eth-provider thread fail if the provider is not available for some reason. |
Next steps on this:
|
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.
Alright, we're getting close. I think this is looking good for the msot part. Some higher-level comments here, after we resolve this we can do a pass of implementation-level/style comments to clean this up, and then we should be good to go. (:
pkg/base-dev/lib/ethereum.hoon
Outdated
++ dirty-response | ||
$% | ||
response | ||
[%error code=@ta message=@t] | ||
== | ||
++ response | ||
$% ::TODO | ||
[%eth-new-filter fid=@ud] | ||
[%eth-get-filter-logs los=(list event-log)] | ||
[%eth-get-logs los=(list event-log)] | ||
[%eth-get-logs-by-hash los=(list event-log)] | ||
[%eth-got-filter-changes los=(list event-log)] | ||
[%eth-transaction-hash haz=@ux] | ||
$% | ||
[%block-number num=@ud] | ||
[%call data=@t] | ||
[%new-filter fid=@ud] | ||
[%block block=(unit block)] | ||
[%logs los=(list event-log)] | ||
[%transaction-result transaction-result=(unit transaction-result)] | ||
[%transaction-receipt transaction-receipt=(unit transaction-receipt)] | ||
[%transaction-count count=@ud] | ||
[%balance balance=@ud] | ||
[%raw-transaction-hash hash=@ux] |
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 like the addition of the "dirty" type. In most cases, that should just be for internal usage, and not really exposed to the api/library consumer, right?
Feels good to have an expanded $response
type, but I think it's preferable to keep the tags matching their requests. Even if multiple requests give a response with the same type, they might not be semantically equivalent. (You already account for this by separating %transaction-count
and %balance
, for example.) More importantly: it seems like a nice property to be able to know the response type from knowing the request that's being sent. The 1-to-1 relation seems worth preserving, so I'll ask you update this to use the old naming style.
If you're concerned about duplicating the inner types: I don't think it's a particular problem for any in this list. Adding separate types to capture those would probably be overkill.
pkg/base-dev/lib/ethereum.hoon
Outdated
:: TODO pull in all attributes | ||
++ transaction-receipt | ||
$: cumulative-gas-used=@ud | ||
effective-gas-price=@ud | ||
:: logs TODO parse-logs? | ||
to=@ux | ||
from=@ux | ||
type=@ux | ||
gas-used=@ud | ||
:: TODO contractAddress is messy because it is a unit | ||
:: contract-address=(unit @ux) | ||
transaction-hash=@ux | ||
block-number=@ux | ||
:: TODO is this correct | ||
logs-bloom=@ux | ||
transaction-index=@ux | ||
status=@ux | ||
== |
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.
logs
Could do it. Unless these use a special one-off format, we should already have types & logic for it, from the "get logs" requests.
contractAddress
What's messy about (unit @ux)
? May need to do an existence or null check during parsing, but shouldn't be too difficult. For the latter, stdlib json destructuring already has a helper (+mu:dejs:format
).
is this correct
What, the logs-bloom
field? I believe that's just some fixed amount of bytes (256 of them), for which @ux
is a fine representation, yes.
However:
block-number
andtransaction-index
should probably be@ud
, since they're sequence numbers.type
should be either0
or2
, for "transfer" and "contract creation or call" respectively. We probably want to dotype=?(%transfer %call)
for that.status
, similarly, is either0
for failure, or1
for success. I think it can just be a?
loobean.to
andfrom
should use the$address
type. That's an alias for@ux
, so nothing changes, but it's more semantically correct.
Co-authored-by: fang <github@fang.io>
Made the changes for this round. |
This is the pull request related to the eth-provider grant: https://urbit.org/grants/eth-provider.
Information on how to use the test files and other notes can be found in the README.md file at my original repo: https://github.com/bzol/eth-provider