-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
web3.js: add getSignatureStatuses to confirm transaction #28290
web3.js: add getSignatureStatuses to confirm transaction #28290
Conversation
Codecov Report
@@ Coverage Diff @@
## master solana-labs/solana#28290 +/- ##
=========================================
- Coverage 77.1% 77.0% -0.2%
=========================================
Files 55 55
Lines 2934 2977 +43
Branches 408 422 +14
=========================================
+ Hits 2264 2294 +30
- Misses 529 535 +6
- Partials 141 148 +7 |
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.
Hey! Thanks for this PR; I really appreciate the help to make transaction confirmation more robust.
I have ideas to make this way simpler.
You've implemented a polling strategy here, and have done so without removing the existing subscription strategy. This means that we now have two competing strategies, where what we could do instead is to make them compliment each other.
In the original issue, I wrote:
- Before subscribing or honouring expiry signals, check the signature status using the getSignatureStatuses method.
- If the signature has not been confirmed and you have not received an expiry signal, subscribe for status updates.
- Race the expiry strategy and the confirmation strategy.
What I was getting at there is that – between the time you send the transaction and you subscribe for the signature – you can miss the subscription notification.
The solution for this should be simple:
- Subscribe first.
- Immediately after the subscription is live, send a single
getSignatureStatuses
to rule out the possibility of having missed a prior signature change.
This should make this PR almost literally one line, and should eliminate the inefficiency of polling!
Want to take a crack at that?
Hi we use pooling like that in mango/gov ui and its quite nice. Websockets can sometimes fail and its good to have a backup method to confirm tx. What do you think about adding option to config it for example: a. websockets only and change suggested by you ofc to shot first with getSignatureStatuses for websockets |
I would rather resolve the architectural decision here amongst ourselves, rather than to push it out to library users as a choice. Some reasons I disfavor polling:
I think I would need some evidence that websockets are so unreliable – other than the known problem of being able to ‘miss’ signatures that this PR aims to solve – as to warrant making every Solana application that uses |
Pull request has been modified.
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.
After those couple fixes we'll need these tests, and then we're done!
- Test that
getSignatureStatuses
does not get fired off untilonSignature
has resolved. - Test that
getSignatureStatuses
does not get fired at all if (somehow)onSignature
resolves synchronously (who knows; that could get implemented in the future) - Test that transactions get confirmed if no subscription notifications get fired, but
getSignatureStatuses
returns a confirmation - Test that transactions still get confirmed if
getSignatureStatuses
returns nothing, but then you get a subscription notification.
You should be able to accomplish that without writing a ‘live’ test at all.
@@ -3295,6 +3295,24 @@ export class Connection { | |||
}, | |||
subscriptionCommitment, | |||
); | |||
|
|||
(async () => { |
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 doesn’t quite do what we set out to do yet, because it doesn’t wait for the subscription to be set up (ie. wait for the server to vend a clientSubscriptionId
). We want to wait for the subscription to be live before firing off the patch-up call to getSignatureStatuses
.
his also could use a test! Assert that the gss call does not get made until onSignature
resolves.
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.
isn't subscriptionId returned immediately from onSignature ?
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, right! Those are the client ids, not the server ids which we keep internal.
Ooh, nice. This just got way more complicated. Essentially, you need a way now of observing the state change of the subscription you just set up from 'pending'
to 'subscribed'
before you make the gSS call. Oftentimes you’ll be the first subscription for the whole app, in which case this could take considerable time (ie. the whole WebSocket connection has to be set up first).
This will be the first time that any code needs to observe the internal state of a subscription. Any ideas on how to achieve this with a minimum of changes?
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.
at first glance maybe we could get hash like this.onSignature do it (i would need to look if for sure it will be the same).
Observe this._subscriptionsByHash (maybe event raise in _updateSubscriptions? Or just check changes in while loop) and when typeof this._subscriptionsByHash[hash] !== 'undefined' && state is 'subscribed' fire gss we can do it all in confirmation promise.
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.
Ok i pushed some solution for you to look this is just working poc and we can probably make it better. still needs to write tests if it fulfills all needs. It dont have any impact on outside code.
Pull request has been modified.
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 me take a crack at this.
…ture subscription
adbaa5c
to
78b36ee
Compare
Pull request has been modified.
@jordansexton, other than the fact that commented-out test doesn't work, what do you think of this (see my three commits in the history here). |
The solution proposed here looks good, and I do not see an undue burden on RPC nodes. The server load could go down if clients stop polling in a loop. Thanks for working on this! |
…onfirmed txs (solana-labs#28290) * chore: create internal method for subscribing to subscription state changes * add status pool * fix tests * more tests * syntax fix * variable rename * fix test * comment fix * remove getSignatureStatuses pooling * rename variable * IIFE * wait for subscription * fix interval clear * test: you can now pause the establishment of subscriptions in tests * feat: implementation of signature status check after setting up signature subscription Co-authored-by: steveluscher <[email protected]>
…onfirmed txs (solana-labs#28290) * chore: create internal method for subscribing to subscription state changes * add status pool * fix tests * more tests * syntax fix * variable rename * fix test * comment fix * remove getSignatureStatuses pooling * rename variable * IIFE * wait for subscription * fix interval clear * test: you can now pause the establishment of subscriptions in tests * feat: implementation of signature status check after setting up signature subscription Co-authored-by: steveluscher <[email protected]>
Problem
If you call confirmTransaction for a signature that has already been processed, the signatureSubscribe subscription will never fire a notification. This will certainly mean that confirmTransaction() will throw an expiry error for a transaction that is, in actual fact, confirmed.
solana-labs/solana-web3.js#1107
Summary of Changes
add getSignatureStatuses
Fixes #1107.