get_signatures_for_address does not correctly account for result sets that span local and Bigtable sources#22115
get_signatures_for_address does not correctly account for result sets that span local and Bigtable sources#22115CriesofCarrots merged 3 commits intosolana-labs:masterfrom omarkilani:patch-1
Conversation
Codecov Report
@@ Coverage Diff @@
## master #22115 +/- ##
=========================================
- Coverage 81.1% 81.1% -0.1%
=========================================
Files 521 521
Lines 146196 146233 +37
=========================================
+ Hits 118673 118685 +12
- Misses 27523 27548 +25 |
|
Improved the commit and tested all 3 scenarios. In this case, I generated a new tx Bigtable had an older tx, When the new tx was generated, Solscan and Explorer both "lost" the old tx for around 30 minutes. This RPC output is from the patched validator. Case where only Bigtable contains tx history:Case where both local storage and Bigtable contain non-overlapping sets of tx history:Case where local storage and Bigtable have overlapping sets of tx history: |
CriesofCarrots
left a comment
There was a problem hiding this comment.
Aha, nice. Thank you for tracking this down!
However, I don't think this is quite right.
The current fix could still hit the RowNotFound error when the getSignaturesForAddress RPC is called with a before parameter that is found in Blockstore but is not yet written to BigTable.
Also, when handling a getSignaturesForAddress RPC request without a specified before, this fix could cause increased (and unnecessary) latency when there are a bunch of signatures in Blockstore that have already been written to BigTable. This could be painful for a very active account.
See my code suggestion to reset before to None only when some last signature is found in Blockstore but not BigTable.
|
@CriesofCarrots okay, will test your patch soon. Please feel free to just do your own commit / PR -- I mainly just wanted to highlight the issue and have a hot-fix I can use. (Sorry about the newb-ness of my patch... first time looking at the validator.😅) |
|
@CriesofCarrots updated the patch. I'm not sure it's working as expected with Patch: Before creating the new tx: After creating the new tx, now So far so good, but: Once Hmmm. |
|
In the case where the result set looks like: Where A |
|
Updated the patch to restrict the It works for the cases where:
However |
Ah, okay. I was sending a "convey an idea" back at you :) The gist of my suggestion is that when BigTable receives |
|
Yeah, that makes sense. So you view Bigtable as a "continuation" of the Blockstore, and I'm naively looking at them as two distinct things, maybe? lol. I always kind of go back to these two screenshots where... for some reason, the validator was returning a tx from the middle of the set (???) and then once the "event" passed it returned tx on either side of that tx. I'll go back to the |
|
Okay so the issue is the Bigtable This is what I was trying to say above. But then anything passed in to |
|
Okay, the latest patch looks like it works in all cases. Data only in Bigtable: Validator output: At this point, I generate a new tx by moving the token. Data spanning Blockstore and Bigtable (no overlap): Validator output: Data spanning Blockstore and Bigtable (with tx overlap -- i.e. tx is present in both stores): Validator output: With Validator output: With Validator output: |
Almost, but not quite. In the case of a query for a non-existent |
Ahh... yeah, I did have that Q above: But then anything passed in to before that Bigtable hasn't seen would trigger a full tx history return? lol. And yes to dupe checks. :) |
|
Okay, I basically combined all the bits of your various pushes, plus a new flag from Blockstore. This now handles all the edge cases I came up with. Do let me know if you think of any more 🙏 |
|
That's amazing -- team work! :) Tested all the different corner cases. There is (optimistically? :) one left, unfortunately. (I'm not sure how you want to solve it in the Tyera-approved way so I'll just describe it. :) My test case was this: This shouldn't return anything since the However it returned the full data set for the address instead. I may be... missing something (?)... but in get_confirmed_signatures_for_address2
|
This one may be working as expected. It is intended that a client can use a Either way, thanks for the reminder. I'll do a focused testing of non-associated |
|
Ah. That actually is a nice feature. Didn't quite make sense at 3am but makes sense now. :) Okay, then I think... this is (hopefully) good. (I've been running production stuff against the patched validator for ~4 hours and don't notice any perf degradation.) |
|
Non-associated |
… that span local and Bigtable sources (#22115) * get_signatures_for_address does not correctly account for result sets that span Blockstore and Bigtable. This causes Bigtable to return `RowNotFound` until the new tx is uploaded. Check that `before` exists in Bigtable, and if not, set it to `None` to return the full data set. References #21442 Closes #22110 * Differentiate between before sig not found and no newer signatures * Dedupe bigtable results to account for potential upload race Co-authored-by: Tyera Eulberg <tyera@solana.com> (cherry picked from commit bac6821) # Conflicts: # ledger/src/blockstore.rs
… that span local and Bigtable sources (#22115) * get_signatures_for_address does not correctly account for result sets that span Blockstore and Bigtable. This causes Bigtable to return `RowNotFound` until the new tx is uploaded. Check that `before` exists in Bigtable, and if not, set it to `None` to return the full data set. References #21442 Closes #22110 * Differentiate between before sig not found and no newer signatures * Dedupe bigtable results to account for potential upload race Co-authored-by: Tyera Eulberg <tyera@solana.com> (cherry picked from commit bac6821)
|
Thank you @CriesofCarrots ! |
… that span local and Bigtable sources (#22115) (#22168) * get_signatures_for_address does not correctly account for result sets that span Blockstore and Bigtable. This causes Bigtable to return `RowNotFound` until the new tx is uploaded. Check that `before` exists in Bigtable, and if not, set it to `None` to return the full data set. References #21442 Closes #22110 * Differentiate between before sig not found and no newer signatures * Dedupe bigtable results to account for potential upload race Co-authored-by: Tyera Eulberg <tyera@solana.com> (cherry picked from commit bac6821) Co-authored-by: Omar Kilani <omar.kilani@gmail.com>
… that span local and Bigtable sources (backport #22115) (#22167) * get_signatures_for_address does not correctly account for result sets that span local and Bigtable sources (#22115) * get_signatures_for_address does not correctly account for result sets that span Blockstore and Bigtable. This causes Bigtable to return `RowNotFound` until the new tx is uploaded. Check that `before` exists in Bigtable, and if not, set it to `None` to return the full data set. References #21442 Closes #22110 * Differentiate between before sig not found and no newer signatures * Dedupe bigtable results to account for potential upload race Co-authored-by: Tyera Eulberg <tyera@solana.com> (cherry picked from commit bac6821) # Conflicts: # ledger/src/blockstore.rs * Fix conflicts Co-authored-by: Omar Kilani <omar.kilani@gmail.com> Co-authored-by: Tyera Eulberg <tyera@solana.com>
|
@CriesofCarrots I'm not sure if you see notifications on merged PRs, but just a random observation since Bigtable is currently down (at least from Germany, but looks like Triton One from SF also isn't able to access it). I presume it's okay that this new code path hangs on .await (until a very long timeout?) while Bigtable is down? I mean... it is in an async function and the existing code has the same issue a little later. But this change introduces 2 times the timeout wait? Is it DoS-able? |
Yeah, that's a fair point. Perhaps we can mitigate that somewhat by changing that |


Problem
When an account has tx history both in the Blockstore and Bigtable, but the tx hasn't been uploaded to Bigtable yet, there is no way for Bigtable to know which txs precede the tx passed in as
before.This causes Bigtable to return
RowNotFounduntil the new tx is uploaded.Proposed Solution
Check that
beforeexists in Bigtable, and if not, set it toNoneto return the full data set.References #21442
Fixes #22110