diff --git a/ledger/Cargo.toml b/ledger/Cargo.toml index be34ffd2b4..e75f892a86 100644 --- a/ledger/Cargo.toml +++ b/ledger/Cargo.toml @@ -21,6 +21,11 @@ name = "block" path = "benches/block.rs" harness = false +[[bench]] +name = "bonded_mapping" +path = "benches/bonded_mapping.rs" +harness = false + [[bench]] name = "transaction" path = "benches/transaction.rs" diff --git a/ledger/benches/bonded_mapping.rs b/ledger/benches/bonded_mapping.rs new file mode 100644 index 0000000000..94d9e7b967 --- /dev/null +++ b/ledger/benches/bonded_mapping.rs @@ -0,0 +1,110 @@ +// Copyright (C) 2019-2023 Aleo Systems Inc. +// This file is part of the snarkVM library. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[macro_use] +extern crate criterion; + +use console::{ + account::{Address, Field, PrivateKey}, + collections::U64, + network::MainnetV0, + program::{Identifier, Literal, Plaintext, ProgramID, Value}, +}; +use ledger_committee::{MAX_DELEGATORS, MIN_DELEGATOR_STAKE}; +#[cfg(not(feature = "rocks"))] +use ledger_store::helpers::memory::ConsensusMemory; +#[cfg(feature = "rocks")] +use ledger_store::helpers::rocksdb::ConsensusDB; +use ledger_store::ConsensusStore; +use synthesizer::VM; + +use criterion::Criterion; +use indexmap::indexmap; +use std::{str::FromStr, time::Duration}; + +pub type CurrentNetwork = MainnetV0; +#[cfg(feature = "rocks")] +pub type CurrentStorage = ConsensusDB; +#[cfg(not(feature = "rocks"))] +pub type CurrentStorage = ConsensusMemory; + +pub const BONDED_INTERVALS: &[usize; 7] = &[10, 5_000, 10_000, 20_000, 40_000, 80_000, 100_000]; + +fn bench_bonded_mappings(c: &mut Criterion) { + // Construct the credits.aleo program ID. + let credits_program_id = ProgramID::from_str("credits.aleo").unwrap(); + // Construct the bonded mapping name. + let bonded_mapping = Identifier::from_str("bonded").unwrap(); + // Construct the bond_state identifiers. + let validator_identifier = Identifier::from_str("validator").unwrap(); + let microcredits_identifier = Identifier::from_str("microcredits").unwrap(); + // Create a DB store for the consensus. + let store = ConsensusStore::::open(None).unwrap(); + // Create a VM from the store. + let vm = VM::from(store).unwrap(); + // Create a sample validator address. + let validator_address = + Address::from_str("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px").unwrap(); + + // Generate 100_000 bonded mapping entries. + let bonded_map = (0..(MAX_DELEGATORS as u64)) + .map(|i| { + // Generate a staker address. + let private_key = PrivateKey::try_from(Field::from_u64(i)).unwrap(); + let staker_address = Address::::try_from(&private_key).unwrap(); + + // Create the bonded state. + let bonded_state = indexmap! { + validator_identifier => Plaintext::from(Literal::Address(validator_address)), + microcredits_identifier => Plaintext::from(Literal::U64(U64::new(MIN_DELEGATOR_STAKE))), + }; + ( + Plaintext::from(Literal::Address(staker_address)), + Value::Plaintext(Plaintext::Struct(bonded_state, Default::default())), + ) + }) + .collect::, Value)>>(); + + // Get a key that exists within the bonded mapping. + let private_key = PrivateKey::try_from(Field::from_u64(5)).unwrap(); + let staker_address = Address::::try_from(&private_key).unwrap(); + let key = Plaintext::from(Literal::Address(staker_address)); + + // Insert increasing numbers of entries into the bonded mapping and bench get_value_speculative and get_value_confirmed at each interval. + BONDED_INTERVALS.iter().for_each(|num_entries| { + let entries = bonded_map.iter().take(*num_entries).cloned().collect::>(); + vm.finalize_store().replace_mapping(credits_program_id, bonded_mapping, entries).unwrap(); + + // Benchmark get_value_speculative on the bonded mapping. + c.bench_function(&format!("bonded mapping - get_value_speculative - {num_entries} entries"), |b| { + b.iter(|| { + vm.finalize_store().get_value_speculative(credits_program_id, bonded_mapping, &key).unwrap(); + }) + }); + + // Benchmark get_value_confirmed on the bonded mapping. + c.bench_function(&format!("bonded mapping - get_value_confirmed - {num_entries} entries"), |b| { + b.iter(|| { + vm.finalize_store().get_value_confirmed(credits_program_id, bonded_mapping, &key).unwrap(); + }) + }); + }); +} + +criterion_group! { + name = mappings; + config = Criterion::default().sample_size(100).measurement_time(Duration::from_secs(10)); + targets = bench_bonded_mappings +} +criterion_main!(mappings);