-
Notifications
You must be signed in to change notification settings - Fork 35
Composite Scenarios Execution - Setup parallely, spam parallely (and in stages) #242
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
base: main
Are you sure you want to change the base?
Changes from all commits
9d7a6bf
171b220
7c91fdf
bb62181
4b15167
cdf64f4
34c9dd3
e4c262d
52ba64c
2a437b2
b40f725
92e08ec
6f9e430
d264c62
bfbd5ea
7629a88
ad913cc
dd613f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| setup: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be cool if we didn't have to manually call setup. Feels like manually specifying rpc_urls for setup could get confusing in a large file (i.e. the user tries to spam on an alternate chain but forgets to run setup on that chain). Instead, we could check if the scenario TOML file has any setup directives, then run |
||
| simpler: | ||
| testfile: ./scenarios/simpler.toml | ||
| min_balance: 12.1 | ||
| call_forkchoice: true | ||
| optimism: false | ||
| auth_rpc_url: "https://rpc.chain.com" | ||
| jwt_secret: SECRET | ||
| uniV2: | ||
| testfile: ./scenarios/uniV2.toml | ||
| rpc_url: http://localhost:8545 # Optional | ||
| min_balance: "11" | ||
| env: | ||
| - Key1=Valu1 | ||
| - Key2=Valu2 | ||
| tx_type: eip1559 # Optional | ||
|
|
||
| spam: | ||
| stages: | ||
| warmup: | ||
| - testfile: ./scenarios/simpler.toml | ||
| tps: 3 | ||
| duration: 3 | ||
| loop: 2 | ||
| seed: "123" | ||
| - testfile: ./scenarios/simpler.toml | ||
| tps: 1 | ||
| duration: 3 | ||
| loop: 2 | ||
| - testfile: ./scenarios/simpler.toml | ||
| tps: 4 | ||
| duration: 3 | ||
| loop: 2 | ||
|
|
||
| call_forkchoice: true | ||
| optimism: false | ||
| auth_rpc_url: "https://rpc.chain.com" | ||
| jwt_secret: SECRET | ||
| medium: | ||
| - testfile: ./scenarios/uniV2.toml | ||
| tps: 10 | ||
| min_balance: 20 | ||
| loop: 1 | ||
| duration: 2 | ||
| - testfile: ./scenarios/simpler.toml | ||
| tps: 14 | ||
| duration: 3 | ||
| loop: 2 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ contender_core = { workspace = true } | |
| contender_sqlite = { workspace = true } | ||
| contender_testfile = { workspace = true } | ||
| contender_engine_provider = { workspace = true } | ||
| contender_composefile = { workspace = true } | ||
|
|
||
| ansi_term = { workspace = true } | ||
| serde = { workspace = true } | ||
|
|
@@ -42,7 +43,9 @@ serde_json = { workspace = true } | |
| tracing = { workspace = true } | ||
| tracing-subscriber = { workspace = true } | ||
| webbrowser = { workspace = true } | ||
| yaml-rust2 = "0.10.2" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know I specified yaml when I wrote the issue but I wonder if toml would be better -- wdyt?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Toml can be nice, since we're using it for the other configurations too. For this case, I would prefer YAML solely because of the readability and syntax familiarity with Docker compose syntax. |
||
| op-alloy-network = { workspace = true } | ||
| hashlink = "0.10.0" | ||
|
|
||
| [dev-dependencies] | ||
| tempfile = "3.15.0" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| use std::{fmt::Debug, sync::Arc}; | ||
|
|
||
| use contender_composefile::composefile::{ComposeFile, CompositeSpamConfiguration}; | ||
| use tokio::{sync::Mutex, task}; | ||
| use tracing::{error, info}; | ||
|
|
||
| use crate::commands::{setup, spam, SetupCommandArgs, SpamCommandArgs}; | ||
|
|
||
| #[derive(Debug, clap::Args)] | ||
| pub struct CompositeScenarioArgs { | ||
| pub filename: Option<String>, | ||
| pub private_keys: Option<Vec<String>>, | ||
| } | ||
|
|
||
| pub async fn composite( | ||
| db: &(impl contender_core::db::DbOps + Clone + Send + Sync + 'static), | ||
| args: CompositeScenarioArgs, | ||
| ) -> Result<(), Box<dyn std::error::Error>> { | ||
| let compose_file_name = match args.filename { | ||
| Some(filepath) => filepath, | ||
| None => String::from("./contender-compose.yml"), | ||
| }; | ||
|
|
||
| let compose_file = ComposeFile::init_from_path(compose_file_name)?; | ||
| let sharable_db = Arc::new(Mutex::new(db.clone())); | ||
| let sharable_private_keys = Arc::new(Mutex::new(args.private_keys)); | ||
|
|
||
| let setup_scenarios = compose_file.get_setup_config()?; | ||
| let setup_tasks: Vec<_> = setup_scenarios | ||
| .into_iter() | ||
| .enumerate() | ||
| .map(|(index, scenario)| { | ||
| let db_clone = sharable_db.clone(); | ||
| let scenario_config = scenario.clone(); | ||
| let private_keys = sharable_private_keys.clone(); | ||
| let setup_command_args = SetupCommandArgs::from_json(scenario_config.config); | ||
|
|
||
| task::spawn(async move { | ||
| let setup_command = setup_command_args | ||
| .await | ||
| .expect("msg") | ||
| .with_private_keys(private_keys.lock().await.clone()); | ||
| match setup(&*db_clone.lock().await, setup_command).await { | ||
| Ok(_) => info!( | ||
| "Setup [{index}] - {}: completed successfully", | ||
| &scenario_config.name | ||
| ), | ||
| Err(err) => error!( | ||
| "Setup [{index}] - {} failed: {err:?}", | ||
| &scenario_config.name | ||
| ), | ||
| }; | ||
| //setup(&*db_clone.lock().await, scenario_config.config).await.map_err(|e| Err("s".into())) | ||
| }) | ||
| }) | ||
| .collect(); | ||
|
|
||
| futures::future::join_all(setup_tasks).await; | ||
|
|
||
| info!("================================================================================================= Done Composite run for setup ================================================================================================="); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's remove the equal signs from this -- simple logs are fine |
||
|
|
||
| let spam_scenarios = compose_file.get_spam_config()?; | ||
| for scenario in spam_scenarios { | ||
| let CompositeSpamConfiguration { | ||
| stage_name, | ||
| spam_configs, | ||
| } = scenario; | ||
| info!("================================================================================================= Running stage: {stage_name:?} ================================================================================================="); | ||
|
|
||
| let mut spam_tasks = Vec::new(); | ||
| let sharable_stage_name_object = Arc::new(Mutex::new(stage_name.clone())); | ||
| for (spam_scenario_index, spam_command) in spam_configs.into_iter().enumerate() { | ||
| info!("Starting scenario [{spam_scenario_index:?}]"); | ||
| let db_clone = sharable_db.clone(); | ||
| let private_keys = sharable_private_keys.clone(); | ||
| let private_keys_clone = private_keys.clone().lock().await.clone(); | ||
| let task = task::spawn(async move { | ||
| let spam_call = async || -> Result<(), Box<dyn std::error::Error>> { | ||
| let spam_command_args = SpamCommandArgs::from_json(spam_command) | ||
| .await? | ||
| .with_private_keys(private_keys_clone); | ||
|
|
||
| let mut test_scenario = spam_command_args | ||
| .init_scenario(&*db_clone.lock().await) | ||
| .await?; | ||
| spam( | ||
| &*db_clone.lock().await, | ||
| &spam_command_args, | ||
| &mut test_scenario, | ||
| ) | ||
| .await?; | ||
| Ok(()) | ||
| }; | ||
|
|
||
| match spam_call().await { | ||
| Ok(()) => { | ||
| info!("Successful: Scenario [{spam_scenario_index:?}]"); | ||
| } | ||
| Err(err) => { | ||
| error!("Error occured while Scenario [{spam_scenario_index:?}]: {err:?}") | ||
| } | ||
| }; | ||
| }); | ||
| spam_tasks.push(task); | ||
| } | ||
|
|
||
| for task in spam_tasks { | ||
| task.await?; | ||
| } | ||
| info!("================================================================================================= Done Composite run for spam - Stage [{:?}] =================================================================================================", &*sharable_stage_name_object.clone().lock().await); | ||
| } | ||
| Ok(()) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure this should be in the project root -- maybe it would fit better under
scenarios/? Or we could have a new directory calledcomposite-scenarios/or something like that.We should also use valid values, so that users with a simple node (e.g. anvil w/ default config) running on localhost:8545 can run the compose file without error. Any advanced examples we want to show off should go in a document under
docs/.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should also enforce a
.compose.tomlfilename restriction, so users don't accidentally try to run core scenario files as compose files