Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

SDK: Add sysvar to expose recent block hashes to programs#6663

Merged
t-nelson merged 9 commits intosolana-labs:masterfrom
t-nelson:recent_block_hashes_sysvar
Nov 4, 2019
Merged

SDK: Add sysvar to expose recent block hashes to programs#6663
t-nelson merged 9 commits intosolana-labs:masterfrom
t-nelson:recent_block_hashes_sysvar

Conversation

@t-nelson
Copy link
Copy Markdown
Contributor

@t-nelson t-nelson commented Oct 31, 2019

Problem

Recent blockhashes aren't available to programs

Summary of Changes

Expose a subset of the bank's blockhash_queue via sysvar

@t-nelson t-nelson requested a review from rob-solana October 31, 2019 20:07
rob-solana
rob-solana previously approved these changes Oct 31, 2019
@garious
Copy link
Copy Markdown
Contributor

garious commented Oct 31, 2019

All uses of BlockHash and block_hash need to be Blockhash and blockhash respectively. In Solana, blockhash is one word, not two. Also, can you add that term to the book? I see the code is nicely consistent, but that term never made it to the terminology page.

@garious
Copy link
Copy Markdown
Contributor

garious commented Oct 31, 2019

btw, love seeing the unit tests at multiple levels. Great PR!

@codecov
Copy link
Copy Markdown

codecov Bot commented Oct 31, 2019

Codecov Report

Merging #6663 into master will increase coverage by 15.2%.
The diff coverage is 93.6%.

@@            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

@t-nelson
Copy link
Copy Markdown
Contributor Author

I'll add terminology in a separate PR

@mergify mergify Bot dismissed rob-solana’s stale review October 31, 2019 20:51

Pull request has been modified.

@garious
Copy link
Copy Markdown
Contributor

garious commented Oct 31, 2019

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
Copy link
Copy Markdown
Contributor Author

@garious
Copy link
Copy Markdown
Contributor

garious commented Oct 31, 2019

@t-nelson, that gets rid of one malloc. To get rid of the other, you should return an impl Iterator instead of a Vec.

Comment thread sdk/src/sysvar/recent_blockhashes.rs Outdated
Account::new(lamports, RecentBlockhashes::size_of(), &sysvar::id())
}

pub fn update_account(account: &mut Account, recent_blockhashes: Vec<Hash>) -> Option<()> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should accept an IntoIterator instead of Vec.

Comment thread runtime/src/blockhash_queue.rs Outdated
None
}

pub fn get_recent_blockhashes(&self, count: usize) -> Vec<Hash> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should return an impl Iterator instead of a Vec

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

@t-nelson
Copy link
Copy Markdown
Contributor Author

Ah cool! Gimme a few

Comment thread runtime/src/bank.rs Outdated
let id = sysvar::recent_blockhashes::id();
let mut account = self
.get_account(&id)
.or_else(|| Some(sysvar::recent_blockhashes::create_account(1)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unwrap_or_else

Comment thread sdk/src/sysvar/recent_blockhashes.rs Outdated
}

pub fn update_account(account: &mut Account, recent_blockhashes: Vec<Hash>) -> Option<()> {
let recent_blockhashes = RecentBlockhashes(recent_blockhashes);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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....

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushing a brand new recent_blockhashes into the accounts_db is faster than reading, updating, storing an update....

Unexpected... So 486f017 is counterproductive?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and reverted the fetch+update. It costs ~1.3us

@garious
Copy link
Copy Markdown
Contributor

garious commented Oct 31, 2019

@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.

@garious
Copy link
Copy Markdown
Contributor

garious commented Nov 1, 2019

The PR problem description doesn't describe a problem.

@t-nelson
Copy link
Copy Markdown
Contributor Author

t-nelson commented Nov 2, 2019

This takes ~12.3us. With the account fetch+update ~13.6us. Without iterators ~18.5us.

@t-nelson t-nelson force-pushed the recent_block_hashes_sysvar branch from 5b3ebe4 to 14b26b1 Compare November 2, 2019 20:02
Copy link
Copy Markdown
Contributor

@garious garious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks for the deep dive!

@t-nelson t-nelson merged commit 5416c11 into solana-labs:master Nov 4, 2019
@t-nelson t-nelson deleted the recent_block_hashes_sysvar branch November 4, 2019 17:51
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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bug which will be fixed by #7918.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants