From 5331efde48b2fb78e5a48e063bc1c420ea2deed4 Mon Sep 17 00:00:00 2001 From: Joe C Date: Sun, 23 Jun 2024 16:27:13 -0500 Subject: [PATCH] Update docs (#11) --- Cargo.lock | 10 ++--- Cargo.toml | 6 +++ README.md | 77 ++++++++++++++++++++++++++++----- bencher/Cargo.toml | 13 ++++-- bencher/src/lib.rs | 11 ++++- bencher/src/result.rs | 4 +- bencher/tests/markdown.rs | 4 +- harness/Cargo.toml | 12 +++-- harness/benches/ips.rs | 2 +- harness/tests/bpf_program.rs | 2 +- harness/tests/system_program.rs | 2 +- 11 files changed, 113 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99b447b..f086c28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1659,8 +1659,8 @@ dependencies = [ ] [[package]] -name = "mollusk" -version = "0.1.0" +name = "mollusk-svm" +version = "0.0.1" dependencies = [ "bincode", "criterion", @@ -1672,11 +1672,11 @@ dependencies = [ ] [[package]] -name = "mollusk-bencher" -version = "0.1.0" +name = "mollusk-svm-bencher" +version = "0.0.1" dependencies = [ "chrono", - "mollusk", + "mollusk-svm", "num-format", "serde_json", "solana-logger", diff --git a/Cargo.toml b/Cargo.toml index 858626e..c64fd62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,12 @@ members = [ ] resolver = "2" +[workspace.package] +authors = ["Joe Caulfield "] +repository = "https://github.com/buffalojoec/mollusk" +license = "../license" +edition = "2021" + [workspace.dependencies] bincode = "1.3.3" num-format = "0.4.4" diff --git a/README.md b/README.md index f8ed5eb..fa1b879 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Mollusk -Solana program testing tools. +SVM program test harness. ## Harness @@ -8,8 +8,6 @@ The harness is designed to directly invoke the loaded executable program using the BPF Loader, bypassing any transaction sanitization and runtime checks, and instead directly processing the instruction with the BPF Loader. -Example: - ```rust let program_id = Pubkey::new_unique(); let key1 = Pubkey::new_unique(); @@ -31,7 +29,47 @@ let accounts = vec![ let mollusk = Mollusk::new(program_id, "my_program"); -let result = mollusk.process_instruction(instruction, accounts); +let result = mollusk.process_instruction(&instruction, &accounts); +``` + +You can also use the `Checks` API provided by Mollusk for easy post-execution +checks, rather than writing them manually. The API method +`process_and_validate_instruction` will still return the result, allowing you +to perform further checks if you desire. + +> Note: `Mollusk::default()` will use the System program as the program to +> invoke. + +```rust +let sender = Pubkey::new_unique(); +let recipient = Pubkey::new_unique(); + +let base_lamports = 100_000_000u64; +let transfer_amount = 42_000u64; + +let instruction = system_instruction::transfer(&sender, &recipient, transfer_amount); +let accounts = [ + ( + sender, + AccountSharedData::new(base_lamports, 0, &system_program::id()), + ), + ( + recipient, + AccountSharedData::new(base_lamports, 0, &system_program::id()), + ), +]; +let checks = vec![ + Check::success(), + Check::compute_units(system_processor::DEFAULT_COMPUTE_UNITS), + Check::account(&sender) + .lamports(base_lamports - transfer_amount) + .build(), + Check::account(&recipient) + .lamports(base_lamports + transfer_amount) + .build(), +]; + +Mollusk::default().process_and_validate_instruction(&instruction, &accounts, &checks); ``` ## Bencher @@ -42,18 +80,37 @@ compute unit usage. Example: ```rust +// If using with `cargo bench`, tell Mollusk where to find the program. +std::env::set_var("SBF_OUT_DIR", "../target/deploy"); + +// Optionally disable logging. +solana_logger::setup_with(""); + +/* Instruction & accounts setup ... */ + +let mollusk = Mollusk::new(&program_id, "my_program"); + MolluskComputeUnitBencher::new(mollusk) - .benchmark(BENCHMARK_COMPUTE_UNITS) - .bench("bench1", instruction1, accounts1) - .bench("bench2", instruction2, accounts2) - .bench("bench3", instruction3, accounts3) - .iterations(100) + .bench(("bench0", &instruction0, &accounts0)) + .bench(("bench1", &instruction1, &accounts1)) + .bench(("bench2", &instruction2, &accounts2)) + .bench(("bench3", &instruction3, &accounts3)) + .bench(("bench4", &instruction4, &accounts4)) + .bench(("bench5", &instruction5, &accounts5)) + .bench(("bench6", &instruction6, &accounts6)) .must_pass(true) .out_dir("../target/benches") .execute(); ``` -You can invoke this benchmark test with `cargo bench`. +You can invoke this benchmark test with `cargo bench`. Don't forget to add a +bench to your project's `Cargo.toml`. + +```toml +[[bench]] +name = "compute_units" +harness = false +``` Mollusk will output bench details to the output directory in both JSON and Markdown. diff --git a/bencher/Cargo.toml b/bencher/Cargo.toml index 3c20e8b..7be821e 100644 --- a/bencher/Cargo.toml +++ b/bencher/Cargo.toml @@ -1,13 +1,18 @@ [package] -name = "mollusk-bencher" -version = "0.1.0" -edition = "2021" +name = "mollusk-svm-bencher" +version = "0.0.1" +description = "SVM program bench harness." +documentation = "https://docs.rs/mollusk-svm-bencher" +authors = { workspace = true } +repository = { workspace = true } +license = { workspace = true } +edition = { workspace = true } [dependencies] chrono = "0.4.38" -mollusk = { path = "../harness" } num-format = { workspace = true } serde_json = { workspace = true } +mollusk-svm = { path = "../harness" } solana-sdk = { workspace = true } [dev-dependencies] diff --git a/bencher/src/lib.rs b/bencher/src/lib.rs index ac687f5..6214780 100644 --- a/bencher/src/lib.rs +++ b/bencher/src/lib.rs @@ -3,14 +3,18 @@ mod result; use { - mollusk::{result::ProgramResult, Mollusk}, + mollusk_svm::{result::ProgramResult, Mollusk}, result::{write_results, MolluskComputeUnitBenchResult}, solana_sdk::{account::AccountSharedData, instruction::Instruction, pubkey::Pubkey}, std::path::PathBuf, }; +/// A bench is a tuple of a name, an instruction, and a list of accounts. pub type Bench<'a> = (&'a str, &'a Instruction, &'a [(Pubkey, AccountSharedData)]); +/// Mollusk's compute unit bencher. +/// +/// Allows developers to bench test compute unit usage on their programs. pub struct MolluskComputeUnitBencher<'a> { benches: Vec>, mollusk: Mollusk, @@ -19,6 +23,7 @@ pub struct MolluskComputeUnitBencher<'a> { } impl<'a> MolluskComputeUnitBencher<'a> { + /// Create a new bencher, to which benches and configurations can be added. pub fn new(mollusk: Mollusk) -> Self { let mut out_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); out_dir.push("benches"); @@ -30,21 +35,25 @@ impl<'a> MolluskComputeUnitBencher<'a> { } } + /// Add a bench to the bencher. pub fn bench(mut self, bench: Bench<'a>) -> Self { self.benches.push(bench); self } + /// Set whether the bencher should panic if a program execution fails. pub fn must_pass(mut self, must_pass: bool) -> Self { self.must_pass = must_pass; self } + /// Set the output directory for the results. pub fn out_dir(mut self, out_dir: &str) -> Self { self.out_dir = PathBuf::from(out_dir); self } + /// Execute the benches. pub fn execute(&mut self) { let bench_results = std::mem::take(&mut self.benches) .into_iter() diff --git a/bencher/src/result.rs b/bencher/src/result.rs index d40e5be..64bc2fa 100644 --- a/bencher/src/result.rs +++ b/bencher/src/result.rs @@ -1,6 +1,8 @@ +//! Compute unit benchmarking results and checks. + use { chrono::{DateTime, Utc}, - mollusk::result::InstructionResult, + mollusk_svm::result::InstructionResult, num_format::{Locale, ToFormattedString}, std::path::Path, }; diff --git a/bencher/tests/markdown.rs b/bencher/tests/markdown.rs index c5765d0..439be33 100644 --- a/bencher/tests/markdown.rs +++ b/bencher/tests/markdown.rs @@ -1,6 +1,6 @@ use { - mollusk::Mollusk, - mollusk_bencher::MolluskComputeUnitBencher, + mollusk_svm::Mollusk, + mollusk_svm_bencher::MolluskComputeUnitBencher, solana_sdk::{instruction::Instruction, pubkey::Pubkey}, }; diff --git a/harness/Cargo.toml b/harness/Cargo.toml index 4ca0262..acc0eb7 100644 --- a/harness/Cargo.toml +++ b/harness/Cargo.toml @@ -1,7 +1,12 @@ [package] -name = "mollusk" -version = "0.1.0" -edition = "2021" +name = "mollusk-svm" +version = "0.0.1" +description = "SVM program test harness." +documentation = "https://docs.rs/mollusk-svm" +authors = { workspace = true } +repository = { workspace = true } +license = { workspace = true } +edition = { workspace = true } [dependencies] bincode = { workspace = true } @@ -11,7 +16,6 @@ solana-system-program = { workspace = true } solana-sdk = { workspace = true } solana-logger = { workspace = true } - [[bench]] name = "ips" harness = false diff --git a/harness/benches/ips.rs b/harness/benches/ips.rs index 0b93cc9..0c08751 100644 --- a/harness/benches/ips.rs +++ b/harness/benches/ips.rs @@ -1,7 +1,7 @@ //! Benches Mollusk invocation (instructions per second) use { criterion::{criterion_group, criterion_main, Criterion, Throughput}, - mollusk::{result::Check, Mollusk}, + mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ account::AccountSharedData, native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, system_instruction, system_program, diff --git a/harness/tests/bpf_program.rs b/harness/tests/bpf_program.rs index 99431ad..ded6988 100644 --- a/harness/tests/bpf_program.rs +++ b/harness/tests/bpf_program.rs @@ -1,5 +1,5 @@ use { - mollusk::{ + mollusk_svm::{ program::{create_program_account, system_program_account}, result::Check, Mollusk, diff --git a/harness/tests/system_program.rs b/harness/tests/system_program.rs index e874ae8..c47c920 100644 --- a/harness/tests/system_program.rs +++ b/harness/tests/system_program.rs @@ -1,5 +1,5 @@ use { - mollusk::{result::Check, Mollusk}, + mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ account::AccountSharedData, instruction::InstructionError, pubkey::Pubkey, system_instruction, system_program,