Skip to content

Commit

Permalink
✨ chain_id + concurrency in config (#30)
Browse files Browse the repository at this point in the history
* ✨ add concurrency config

* ✨ chain id config

* ✨ add katana config

* fix: max fee
  • Loading branch information
EvolveArt committed Dec 8, 2023
1 parent f81a0b6 commit d2246e5
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ opt-level = 3
# Starknet dependencies
starknet = "0.6.0"

num_cpus = "1.0"
env_logger = "0.10.0"
log = "0.4.17"
tokio = { version = "1", features = ["full"] }
Expand Down
8 changes: 5 additions & 3 deletions config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ setup:
v0: contracts/v0/OpenzeppelinAccount.json

fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
num_accounts: 3
num_accounts: 1
chain_id: "SN_GOERLI"

run:
num_erc20_transfers: 1200
num_erc721_mints: 1200
num_erc20_transfers: 1000
num_erc721_mints: 1000
concurrency: 5

report:
num_blocks: 4
Expand Down
30 changes: 30 additions & 0 deletions config/katana.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
rpc:
url: "http://localhost:5050"

setup:
erc20_contract:
v0: contracts/v0/ERC20.json

erc721_contract:
v0: contracts/v0/ERC721.json

account_contract:
v0: contracts/v0/OpenzeppelinAccount.json

fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
num_accounts: 3
chain_id: "KATANA"

run:
num_erc20_transfers: 300
num_erc721_mints: 300
concurrency: 5

report:
num_blocks: 4
reports_dir: "reports"

deployer:
salt: "1"
address: "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
signing_key: "0x1800000000300000180000000000030000000000003006001800006600"
2 changes: 2 additions & 0 deletions config/sharingan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ setup:

fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
num_accounts: 3
chain_id: "SN_GOERLI"

run:
num_erc20_transfers: 1200
num_erc721_mints: 1200
concurrency: 5

report:
num_blocks: 4
Expand Down
4 changes: 3 additions & 1 deletion config/v2.1.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ setup:
casm_path: contracts/v2.1.0/openzeppelin_Account.casm.json

fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
num_accounts: 3
num_accounts: 1
chain_id: "SN_GOERLI"

run:
num_erc20_transfers: 100
num_erc721_mints: 100
concurrency: 5

report:
num_blocks: 3
Expand Down
62 changes: 43 additions & 19 deletions src/actions/shoot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use starknet::accounts::{
SingleOwnerAccount,
};
use starknet::contract::ContractFactory;
use starknet::core::chain_id;
use starknet::core::types::{
contract::legacy::LegacyContractClass, BlockId, BlockTag, FieldElement, StarknetError,
};
Expand All @@ -39,20 +38,22 @@ use std::time::{Duration, SystemTime};
use url::Url;

// Used to bypass validation
pub static MAX_FEE: FieldElement = felt!("0xffffffff");
pub static MAX_FEE: FieldElement = felt!("0xffffff");
pub static CHECK_INTERVAL: Duration = Duration::from_millis(500);
pub static TX_VALIDATION_CONCURRENCY: usize = 10;

type StarknetAccount = SingleOwnerAccount<Arc<JsonRpcClient<HttpTransport>>, LocalWallet>;

/// Shoot the load test simulation.
pub async fn shoot(config: GatlingConfig) -> Result<GatlingReport> {
info!("starting simulation with config: {:#?}", config);
let mut shooter = GatlingShooter::from_config(config).await?;
let mut shooter = GatlingShooter::from_config(config.clone()).await?;
let mut gatling_report = Default::default();
// Trigger the setup phase.
shooter.setup(&mut gatling_report).await?;

let threads = std::cmp::min(num_cpus::get(), config.run.concurrency as usize);
info!("Using {} threads", threads);

// Run the benchmarks.
shooter.run(&mut gatling_report).await?;

Expand Down Expand Up @@ -80,15 +81,16 @@ pub struct GatlingEnvironment {

impl GatlingShooter {
pub async fn from_config(config: GatlingConfig) -> Result<Self> {
let starknet_rpc = Arc::new(starknet_rpc_provider(Url::parse(&config.clone().rpc.url)?));
let starknet_rpc: Arc<JsonRpcClient<HttpTransport>> =
Arc::new(starknet_rpc_provider(Url::parse(&config.clone().rpc.url)?));

let signer = LocalWallet::from(SigningKey::from_secret_scalar(config.deployer.signing_key));

let account = SingleOwnerAccount::new(
starknet_rpc.clone(),
signer.clone(),
config.deployer.address,
chain_id::TESTNET,
config.setup.chain_id,
ExecutionEncoding::New,
);

Expand Down Expand Up @@ -156,20 +158,21 @@ impl GatlingShooter {
ContractSourceConfig::V1(_) => ExecutionEncoding::New,
};

let erc20_address = self.deploy_erc20(erc20_class_hash).await?;
let erc721_address = self.deploy_erc721(erc721_class_hash).await?;

let accounts = if setup_config.num_accounts > 0 {
self.create_accounts(
account_class_hash,
setup_config.num_accounts,
execution_encoding,
erc20_address,
)
.await?
} else {
Vec::new()
};

let erc20_address = self.deploy_erc20(erc20_class_hash).await?;
let erc721_address = self.deploy_erc721(erc721_class_hash).await?;

let environment = GatlingEnvironment {
_erc20_address: erc20_address,
erc721_address,
Expand Down Expand Up @@ -222,7 +225,7 @@ impl GatlingShooter {

let mut transactions = transactions.into_iter();

for _ in 0..TX_VALIDATION_CONCURRENCY {
for _ in 0..self.config.run.concurrency {
if let Some(transaction) = transactions.next() {
let starknet_rpc = Arc::clone(&self.starknet_rpc);
set.spawn(async move {
Expand Down Expand Up @@ -626,7 +629,8 @@ impl GatlingShooter {
let name = selector!("TestToken");
let symbol = selector!("TT");
let decimals = felt!("128");
let (initial_supply_low, initial_supply_high) = (felt!("100000"), felt!("0"));
let (initial_supply_low, initial_supply_high) =
(felt!("0xFFFFFFFFF"), felt!("0xFFFFFFFFF"));
let recipient = self.account.address();

let constructor_args = vec![
Expand Down Expand Up @@ -658,8 +662,8 @@ impl GatlingShooter {
let deploy = contract_factory.deploy(constructor_args, self.config.deployer.salt, unique);

info!(
"Deploying ERC20 contract with nonce={}, address={address}",
nonce
"Deploying ERC20 contract with nonce={}, address={:#064x}",
nonce, address
);

let result = deploy.nonce(nonce).max_fee(MAX_FEE).send().await?;
Expand All @@ -677,11 +681,23 @@ impl GatlingShooter {
}

/// Create accounts.
///
/// # Arguments
///
/// * `class_hash` - The class hash of the account contract.
/// * `num_accounts` - The number of accounts to create.
/// * `execution_encoding` - Execution encoding to use, `Legacy` for Cairo Zero and `New` for Cairo
/// * `erc20_address` - The address of the ERC20 contract to use for funding the accounts.
///
/// # Returns
///
/// A vector of the created accounts.
async fn create_accounts<'a>(
&mut self,
class_hash: FieldElement,
num_accounts: usize,
execution_encoding: ExecutionEncoding,
erc20_address: FieldElement,
) -> Result<Vec<StarknetAccount>> {
info!("Creating {} accounts", num_accounts);

Expand All @@ -695,9 +711,13 @@ impl GatlingShooter {
// TODO: Check if OpenZepplinAccountFactory could be used with other type of accounts ? or should we require users to use OpenZepplinAccountFactory ?
let signer = self.signer.clone();
let provider = self.starknet_rpc.clone();
let account_factory =
OpenZeppelinAccountFactory::new(class_hash, chain_id::TESTNET, &signer, &provider)
.await?;
let account_factory = OpenZeppelinAccountFactory::new(
class_hash,
self.config.setup.chain_id,
&signer,
&provider,
)
.await?;

let salt = self.config.deployer.salt + FieldElement::from(i);

Expand All @@ -716,7 +736,7 @@ impl GatlingShooter {
self.starknet_rpc.clone(),
signer.clone(),
address,
chain_id::TESTNET,
self.config.setup.chain_id,
execution_encoding,
);
deployed_accounts.push(account);
Expand All @@ -727,12 +747,16 @@ impl GatlingShooter {
}

info!("Funding account {i} at address {address:#064x}");
let tx_hash = self
.transfer(erc20_address, self.account.clone(), address, felt!("0xFFF"))
.await?;
wait_for_tx(&self.starknet_rpc, tx_hash, CHECK_INTERVAL).await?;
let tx_hash = self
.transfer(
fee_token_address,
self.account.clone(),
address,
felt!("0xFFFFFFFFF"),
felt!("0xFFFFFFFFFFFFFF"),
)
.await?;
wait_for_tx(&self.starknet_rpc, tx_hash, CHECK_INTERVAL).await?;
Expand All @@ -743,7 +767,7 @@ impl GatlingShooter {
self.starknet_rpc.clone(),
signer.clone(),
result.contract_address,
chain_id::TESTNET,
self.config.setup.chain_id,
execution_encoding,
);

Expand Down
26 changes: 24 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ use std::path::PathBuf;
use color_eyre::eyre::Result;
use config::{builder::DefaultState, Config, ConfigBuilder, File};

use serde_derive::Deserialize;
use starknet::core::types::{contract::CompiledClass, FieldElement};
use serde::de::Error as DeError;
use serde::Deserialize;
use starknet::core::{
types::{contract::CompiledClass, FieldElement},
utils::{cairo_short_string_to_felt, CairoShortStringToFeltError},
};

/// Configuration for the application.
#[derive(Debug, Deserialize, Clone)]
Expand Down Expand Up @@ -86,6 +90,8 @@ pub struct SetupConfig {
pub account_contract: ContractSourceConfig,
pub fee_token_address: FieldElement,
pub num_accounts: usize,
#[serde(deserialize_with = "from_str_deserializer")]
pub chain_id: FieldElement,
}

#[derive(Debug, Deserialize, Clone)]
Expand All @@ -99,6 +105,7 @@ pub struct DeployerConfig {
pub struct RunConfig {
pub num_erc20_transfers: u64,
pub num_erc721_mints: u64,
pub concurrency: u64,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down Expand Up @@ -134,3 +141,18 @@ fn base_config_builder() -> ConfigBuilder<DefaultState> {
// Eg.. `GATLING_FAIL_FAST=1 ./target/app` would set the `fail_fast` key
.add_source(config::Environment::with_prefix("gatling"))
}

fn from_str_deserializer<'de, D>(deserializer: D) -> Result<FieldElement, D::Error>
where
D: serde::Deserializer<'de>,
{
// Deserialize a string using the deserializer.
let s = String::deserialize(deserializer)?;

// Use your custom function to try to create a FieldElement from the string.
// If there's an error, use the Error::custom method to convert it into a Serde error.
cairo_short_string_to_felt(&s).map_err(|e| match e {
CairoShortStringToFeltError::NonAsciiCharacter => D::Error::custom("non ascii character"),
CairoShortStringToFeltError::StringTooLong => D::Error::custom("string too long"),
})
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use gatling::{
config::GatlingConfig,
};

#[tokio::main]
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() -> Result<()> {
// Initialize the logger.
env_logger::init();
Expand Down

0 comments on commit d2246e5

Please sign in to comment.