Skip to content
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

program-test: Expose bank task to fix fuzzing #14908

Merged
merged 5 commits into from
Jan 29, 2021

Conversation

joncinque
Copy link
Contributor

Problem

Program-test creates a running task to register ticks on the bank, but does not expose this task. For most cases, this works great, but in a fuzzing environment, not closing the thread properly blows up /tmp with all sorts of directories like /tmp/.tmp0000, perhaps related to rocksdb? I'm not too familiar with that side of it.

Summary of Changes

Expose the running task on the bank through a new return type, ProgramTestState, and allow it to be stopped on drop. This changes the API on ProgramTest.start(), which seems reasonable considering most of these are tests users. If needed, I can spin off a new / old function and mark this as deprecated.

One thing to note is that we can't simply destructure this as:

let ProgramTestState { mut banks_client, payer, last_blockhash, .. } = program_test.start().await;

Because the task gets dropped at that point.

The other nice part of this approach is that we can start to support a lot of functions that have been asked for by devs. My next idea is to add a warp_to_slot on ProgramTestState. We'll just need to keep track of the BankForks and use Bank::warp_from_parent.

This approach gets much more consistent performance from fuzzing as well. For the test, we can't easily use the fuzz! macro because then we need to build with cargo hfuzz build, so instead it's simulating what a fuzz run would look like with arbitrary &[u8] data.

Fixes #14707

@joncinque joncinque requested a review from mvines January 28, 2021 19:19
Copy link
Member

@mvines mvines left a comment

Choose a reason for hiding this comment

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

I like the direction. We needed a place to hook up a clock/slot manipulation interface and this provides such a location

}

impl ProgramTestState {
pub fn new(
Copy link
Member

Choose a reason for hiding this comment

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

I think we can limit scope here

Suggested change
pub fn new(
fn new(

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call, I was thinking someone might want to hack on it from the outside, but this'll be safer

}
}

pub struct ProgramTestState {
Copy link
Member

Choose a reason for hiding this comment

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

nit: I think I fancy "context" more:

Suggested change
pub struct ProgramTestState {
pub struct ProgramTestContext {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Works for me!

@@ -539,7 +583,7 @@ impl ProgramTest {
///
/// Returns a `BanksClient` interface into the test environment as well as a payer `Keypair`
/// with SOL for sending transactions
pub async fn start(self) -> (BanksClient, Keypair, Hash) {
pub async fn start(self) -> ProgramTestState {
Copy link
Member

Choose a reason for hiding this comment

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

I'm definitely concerned about changing this signature and blowing up existing users. I think we need to keep it for existing users and future users that just want to keep it simple.

Some ideas for a new method name for this signature:

  1. enter() -- you enter the ProgramTextContext
  2. run() -- confusing, do I "start" or "run"
  3. start_with_context() -- maybe my favourite of the three, consistent with start() and the Rust norms of adding "with" methods that enhance the functionality of the base method

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok no problem, I'll add start_with_context()

@joncinque joncinque added the v1.5 label Jan 28, 2021
mvines
mvines previously approved these changes Jan 28, 2021
Copy link
Member

@mvines mvines left a comment

Choose a reason for hiding this comment

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

nice work

program-test/src/lib.rs Show resolved Hide resolved
program-test/src/lib.rs Show resolved Hide resolved
// are required when sending multiple otherwise identical transactions in series from a
// test
let target_tick_duration = genesis_config.poh_config.target_tick_duration;
let (tx, mut rx) = mpsc::channel(1);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let (tx, mut rx) = mpsc::channel(1);
let (sender, mut receiver) = mpsc::channel(1);

🙏🏼. Most people unfortunately like to use tx to mean transaction in the code base, except when it means something else like in this case

Copy link
Contributor Author

@joncinque joncinque Jan 29, 2021

Choose a reason for hiding this comment

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

Ah, right, on it switching to AtomicBool

tx,
tokio::spawn(async move {
loop {
if rx.try_recv().is_ok() {
Copy link
Member

Choose a reason for hiding this comment

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

An AtomicBool is generally used in other parts of the code for this kind of exit pattern. I'm not opposed to a channel if you want to keep it though.

Here's one example of using the atomic bool:

if exit.load(Ordering::Relaxed) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That was actually my initial approach, but then I thought a message would be clearer. I'll change it to an AtomicBool to keep things consistent in the codebase

@codecov
Copy link

codecov bot commented Jan 29, 2021

Codecov Report

Merging #14908 (a100a36) into master (b948ede) will decrease coverage by 0.0%.
The diff coverage is 0.0%.

@@            Coverage Diff            @@
##           master   #14908     +/-   ##
=========================================
- Coverage    79.9%    79.8%   -0.1%     
=========================================
  Files         401      401             
  Lines      100698   100781     +83     
=========================================
- Hits        80531    80503     -28     
- Misses      20167    20278    +111     

@mergify mergify bot dismissed mvines’s stale review January 29, 2021 11:37

Pull request has been modified.

@joncinque joncinque merged commit 0ce0827 into solana-labs:master Jan 29, 2021
@joncinque joncinque deleted the program-test-fuzz branch January 29, 2021 13:24
mergify bot pushed a commit that referenced this pull request Jan 29, 2021
* program-test: Expose bank task to fix fuzzing

* Run cargo fmt and clippy

* Remove unnecessary print in test

* Review feedback

* Transition to AtomicBool

(cherry picked from commit 0ce0827)
joncinque added a commit that referenced this pull request Jan 29, 2021
* program-test: Expose bank task to fix fuzzing

* Run cargo fmt and clippy

* Remove unnecessary print in test

* Review feedback

* Transition to AtomicBool

(cherry picked from commit 0ce0827)

Co-authored-by: Jon Cinque <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

program-test in fuzzing environment blows up /tmp
2 participants