-
Notifications
You must be signed in to change notification settings - Fork 4
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
Updates for Chronos V4 #61
Conversation
522ff48
to
8ca2b37
Compare
@@ -26,10 +26,12 @@ proc raiseEstimateGasError( | |||
parent: parent) | |||
raise e | |||
|
|||
method provider*(signer: Signer): Provider {.base, gcsafe.} = | |||
method provider*(signer: Signer): | |||
Provider {.base, gcsafe, raises: [CatchableError].} = |
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.
Hmm... I would not blanked raise CatchableError
, in fact I would set this to raises: []
and only list those exceptions that are intended to propagate. The whole point of this is preventing spurious exceptions from bubbling up, otherwise there is no point in tracking exceptions at all.
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.
In fact I would use the push: raises []
pragma in all the files and only override this per method on an as needed basis.
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.
Yeah, I mean, as I was working through this, I was faced with two choices:
- do the minimal amount of changes so that the current implementation works with Chronos V4;
- actually track the entire exception chains and expose the exceptions that all method implementations may throw, which is what you're proposing.
(2) seems like a good idea, but it is actually sort of tricky. Without some feeling as to how the API has to be designed, I could easily replace CatchableError
with EthersError
pretty much everywhere, and it would compile without much gain in exception semantics. The actual narrow types for the exceptions that would make sense to expose depends on what we expect clients to want to try to recover from, so that's why I ended up going with the (1) route.
I'll give it a stab anyhow, let's see what comes out of it.
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.
Yeah, I understand, this gets messy pretty quickly, but I still think that push pragma with raises: []
and an explicit EthersError
where required is a much better than the bare CatchableError
. Also, I suspect that a lot of issues are stemming from the fact that callbacks aren't annotated with raises: []
.
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.
Its actually not that bad. Here's a compiling commit with {.push raises:[].}
: 7973ce8
@@ -14,6 +14,14 @@ type | |||
callbacks: Table[JsonNode, SubscriptionCallback] | |||
SubscriptionCallback = proc(id, arguments: JsonNode) {.gcsafe, raises:[].} | |||
|
|||
# FIXME Nim 1.6.XX seems to have issues tracking exception effects and will see |
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.
Actually, this is probably the wrong way of doing it, as you noted in the forum post, annotating the callback type with a raises: []
fixes the issue, this is in fact the correct fix. Callbacks should (almost) never allow exceptions to escape.
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.
Also, here is a pointer on how to handle the strict effect changes in a backwards/forwards compatible way in the 1.6.0 release notes - https://github.com/narimiran/Nim/blob/f14925d3bc778bcb7eef4eb9085f08d65f4281ce/changelogs/changelog_1_6_0.md#strict-effects, should be helpful.
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 @dryajov and araq mentioned, the correct fix is to use raises:[]
in the callback definition instead of mitigateEffectsBug
. The unhandled Exception
being raised (and the difference between your example in the forum post and the current implementation in ethers) is that the Table
uses a JsonNode
as a key. As a guess, the Exception
could possibly come from use of parseJson
in Table
's key handling when the key type is JsonNode
. Here's a compiling commit that uses string
as key and no mitigateEffectsBug
. Note that this commit is not necessarily complete or the correct way to completely remove JsonNode
as the callback table key; it's to illustrate that the issue indeed lies in the use of JsonNode
as a table key: a1eb549
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.
In summary, the solution would be a combination of using raises:[]
in the callback definition, and changing the callback table key type.
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.
Note that table accessors such as get
or []
will raise an exception, so this should either use the non throwing versions (getOrDefault, etc), or handle the exceptions in the callback itself.
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.
Awesome, so we have two issues that end in the same symptom (gotta love when that happens):
- the nim effects issue (https://forum.nim-lang.org/t/10749);
- using JsonNode as a table key.
I'm not sure I follow your explanation though @emizzle (and that's probably the problem :-)): is parseJson called during the hashing of JsonNode?
@dryajov yes but in this case we're writing to the table ([]=
), this should not raise exceptions.
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.
Exception handling is always super tricky!
requires "chronicles >= 0.10.3 & < 0.11.0" | ||
requires "chronos >= 3.0.0 & < 4.0.0" | ||
requires "chronos#head" # FIXME: change to >= 4.0.0 when chronos 4 is released |
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 it be better to reference the specific chronos commit instead of head
?
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.
Yeah... I think both are bad TBH. 😄 The tradeoff I see is:
- using a specific commit buys you stability for the nim-ethers build in the short term, but will require you to constantly bump this to keep up with the latest V4 commits;
- using head means every time someone pushes you'll be testing against the latest pre-release of V4, and you may be able to catch issues earlier. Can be annoying to someone who just want to change unrelated stuff and all of a sudden finds themselves with a Chronos error unrelated to their change, though.
Either one sort of sucks IMHO, so I'd be fine with either.
@@ -26,10 +26,12 @@ proc raiseEstimateGasError( | |||
parent: parent) | |||
raise e | |||
|
|||
method provider*(signer: Signer): Provider {.base, gcsafe.} = | |||
method provider*(signer: Signer): | |||
Provider {.base, gcsafe, raises: [CatchableError].} = |
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.
Its actually not that bad. Here's a compiling commit with {.push raises:[].}
: 7973ce8
@@ -14,6 +14,14 @@ type | |||
callbacks: Table[JsonNode, SubscriptionCallback] | |||
SubscriptionCallback = proc(id, arguments: JsonNode) {.gcsafe, raises:[].} | |||
|
|||
# FIXME Nim 1.6.XX seems to have issues tracking exception effects and will see |
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 @dryajov and araq mentioned, the correct fix is to use raises:[]
in the callback definition instead of mitigateEffectsBug
. The unhandled Exception
being raised (and the difference between your example in the forum post and the current implementation in ethers) is that the Table
uses a JsonNode
as a key. As a guess, the Exception
could possibly come from use of parseJson
in Table
's key handling when the key type is JsonNode
. Here's a compiling commit that uses string
as key and no mitigateEffectsBug
. Note that this commit is not necessarily complete or the correct way to completely remove JsonNode
as the callback table key; it's to illustrate that the issue indeed lies in the use of JsonNode
as a table key: a1eb549
@@ -14,6 +14,14 @@ type | |||
callbacks: Table[JsonNode, SubscriptionCallback] | |||
SubscriptionCallback = proc(id, arguments: JsonNode) {.gcsafe, raises:[].} | |||
|
|||
# FIXME Nim 1.6.XX seems to have issues tracking exception effects and will see |
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.
In summary, the solution would be a combination of using raises:[]
in the callback definition, and changing the callback table key type.
Are we ok to close this in favour of #64? |
This PR adds minimal adjustments to ensure that nim-ethers works (i.e. compiles and the test suite passes) with Chronos V4. Changes are minimal enough that it should still work with Chronos 3.x, though that's more of a bonus than a goal.
Two of the more controversial points in this PR are:
{.cast(raises: []).}
in table operations which 1.6.x will otherwise (erroneously) declare as raisers of Exception. I had asked for this in nim-forum with a smaller example and Araq suggested using{.experimental: "strictEffects".}
(https://forum.nim-lang.org/t/10749) which indeed fixed my example, but for reasons I can't understand it doesn't work here. The problem seems to not exist with 2.x;