SDK: Add sysvar to expose recent block hashes to programs#6663
SDK: Add sysvar to expose recent block hashes to programs#6663t-nelson merged 9 commits intosolana-labs:masterfrom
Conversation
|
All uses of |
|
btw, love seeing the unit tests at multiple levels. Great PR! |
Codecov Report
@@ Coverage Diff @@
## master #6663 +/- ##
=========================================
+ Coverage 63.3% 78.6% +15.2%
=========================================
Files 220 213 -7
Lines 51718 41304 -10414
=========================================
- Hits 32772 32483 -289
+ Misses 18946 8821 -10125 |
|
I'll add terminology in a separate PR |
Pull request has been modified.
|
One concern, it looks like this adds two mallocs per slot, and it could be zero. What if we get the previous account and then just overwrite its blockhashes? |
|
@t-nelson, that gets rid of one malloc. To get rid of the other, you should return an |
| Account::new(lamports, RecentBlockhashes::size_of(), &sysvar::id()) | ||
| } | ||
|
|
||
| pub fn update_account(account: &mut Account, recent_blockhashes: Vec<Hash>) -> Option<()> { |
There was a problem hiding this comment.
This should accept an IntoIterator instead of Vec.
| None | ||
| } | ||
|
|
||
| pub fn get_recent_blockhashes(&self, count: usize) -> Vec<Hash> { |
There was a problem hiding this comment.
This should return an impl Iterator instead of a Vec
There was a problem hiding this comment.
On second thought. Hold off. That recent_blockhashes doesn't look to be the Dequeue it used to be. Surprised to see the need to sort there.
There was a problem hiding this comment.
So why does this have a count parameter? It's not used by anything other than the test. And if it wasn't there, you could return an unordered impl Iterator<Item = &Hash> with effectively zero cost.
There was a problem hiding this comment.
count was an attempt to shortcircuit the last iteration and avoid another to truncate in the caller. Returning an impl Iterator<Item=&Hash though, I can move all of that logic to the caller (and avoid the hash copies)
|
Ah cool! Gimme a few |
| let id = sysvar::recent_blockhashes::id(); | ||
| let mut account = self | ||
| .get_account(&id) | ||
| .or_else(|| Some(sysvar::recent_blockhashes::create_account(1))) |
| } | ||
|
|
||
| pub fn update_account(account: &mut Account, recent_blockhashes: Vec<Hash>) -> Option<()> { | ||
| let recent_blockhashes = RecentBlockhashes(recent_blockhashes); |
There was a problem hiding this comment.
@rob-solana, ideally, this would be a zero-copy from_account(account) and then replace the contents of RecentBlockhashes.0 with that from the recent_blockhashes input. And if so, then there's be no need for that to_account() afterward.
There was a problem hiding this comment.
I wanna see a helper library for zero copy serde
pushing a brand new recent_blockhashes into the accounts_db is faster than reading, updating, storing an update....
There was a problem hiding this comment.
pushing a brand new recent_blockhashes into the accounts_db is faster than reading, updating, storing an update....
Unexpected... So 486f017 is counterproductive?
There was a problem hiding this comment.
Probably. I think we need prioritize clear, concise tests and a micro-benchmark, as all this code will change once somebody figures our a good way to do zero-copy deserialization.
There was a problem hiding this comment.
I went ahead and reverted the fetch+update. It costs ~1.3us
|
@t-nelson, since this function gets called once every 400ms, I think this seemingly innocent feature needs a microbenchmark. Between the serialization, the vec mallocs, and hash copies, there's a lot that can be optimized here. |
|
The PR problem description doesn't describe a problem. |
|
This takes ~12.3us. With the account fetch+update ~13.6us. Without iterators ~18.5us. |
5b3ebe4 to
14b26b1
Compare
garious
left a comment
There was a problem hiding this comment.
Nice, thanks for the deep dive!
| I: IntoIterator<Item = (u64, &'a Hash)>, | ||
| { | ||
| let sorted = BinaryHeap::from_iter(recent_blockhash_iter); | ||
| let recent_blockhash_iter = sorted.into_iter().take(MAX_ENTRIES).map(|(_, hash)| hash); |
Problem
Recent blockhashes aren't available to programs
Summary of Changes
Expose a subset of the bank's blockhash_queue via sysvar