Skip to content

Commit

Permalink
support from_pool in create steps
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroXbrock committed Jan 6, 2025
1 parent d73f14e commit a47694e
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 104 deletions.
25 changes: 16 additions & 9 deletions crates/cli/src/commands/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use contender_testfile::TestConfig;
use std::str::FromStr;

use crate::util::{
check_private_keys_fns, find_insufficient_balance_addrs, fund_accounts, get_setup_pools,
get_signers_with_defaults,
check_private_keys_fns, find_insufficient_balance_addrs, fund_accounts, get_create_pools,
get_setup_pools, get_signers_with_defaults,
};

pub async fn setup(
Expand All @@ -38,11 +38,15 @@ pub async fn setup(
.iter()
.map(|key| PrivateKeySigner::from_str(key).expect("invalid private key"))
.collect::<Vec<PrivateKeySigner>>();
let default_signers = get_signers_with_defaults(private_keys);

let user_signers_with_defaults = get_signers_with_defaults(private_keys);

check_private_keys_fns(
&testconfig.setup.to_owned().unwrap_or_default(),
&default_signers,
&user_signers_with_defaults,
);

// ensure user-provided accounts have sufficient balance
let broke_accounts = find_insufficient_balance_addrs(
&user_signers.iter().map(|s| s.address()).collect::<Vec<_>>(),
min_balance,
Expand All @@ -53,11 +57,14 @@ pub async fn setup(
panic!("Insufficient balance in provided user account(s)");
}

let mut agents = AgentStore::new();
let from_pools = get_setup_pools(&testconfig);
// collect all signers
let mut all_signers = vec![];
all_signers.extend_from_slice(&user_signers);

// load agents from setup and create pools
let mut from_pools = get_setup_pools(&testconfig);
from_pools.extend(get_create_pools(&testconfig));
let mut agents = AgentStore::new();
for from_pool in &from_pools {
if agents.has_agent(from_pool) {
continue;
Expand All @@ -69,11 +76,11 @@ pub async fn setup(
}

fund_accounts(
&all_signers,
&user_signers_with_defaults[0],
&rpc_client,
&eth_client,
min_balance,
&all_signers,
&default_signers[0],
)
.await?;

Expand All @@ -83,7 +90,7 @@ pub async fn setup(
url,
None,
seed,
&default_signers,
&user_signers_with_defaults,
agents,
)
.await?;
Expand Down
4 changes: 2 additions & 2 deletions crates/cli/src/commands/spam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ pub async fn spam(
check_private_keys(&testconfig, &all_signers);

fund_accounts(
&all_signers,
&user_signers[0],
&rpc_client,
&eth_client,
min_balance,
&all_signers,
&user_signers[0],
)
.await?;

Expand Down
3 changes: 2 additions & 1 deletion crates/cli/src/default_scenarios/runconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ impl From<BuiltinScenarioConfig> for TestConfig {
create: Some(vec![CreateDefinition {
name: "SpamMe".to_owned(),
bytecode: bytecode::SPAM_ME.to_owned(),
from: sender.to_string(),
from: Some(sender.to_string()),
from_pool: None,
}]),
setup: None,
spam: Some(spam_txs),
Expand Down
39 changes: 23 additions & 16 deletions crates/cli/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ pub const DEFAULT_PRV_KEYS: [&str; 10] = [
"0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6",
];

pub fn get_create_pools(testconfig: &TestConfig) -> Vec<String> {
testconfig
.create
.to_owned()
.unwrap_or_default()
.into_iter()
.filter_map(|s| s.from_pool)
.collect()
}

pub fn get_setup_pools(testconfig: &TestConfig) -> Vec<String> {
testconfig
.setup
Expand Down Expand Up @@ -139,30 +149,31 @@ async fn is_balance_sufficient(
Ok(balance >= min_balance)
}

///
pub async fn fund_accounts(
accounts: &[PrivateKeySigner],
fund_with: &PrivateKeySigner,
rpc_client: &AnyProvider,
eth_client: &EthProvider,
min_balance: U256,
all_signers: &[PrivateKeySigner],
admin_signer: &PrivateKeySigner,
) -> Result<(), Box<dyn std::error::Error>> {
let insufficient_balance_addrs = find_insufficient_balance_addrs(
&all_signers.iter().map(|s| s.address()).collect::<Vec<_>>(),
&accounts.iter().map(|s| s.address()).collect::<Vec<_>>(),
min_balance,
rpc_client,
)
.await?;

let mut pending_fund_txs = vec![];
let admin_nonce = rpc_client
.get_transaction_count(admin_signer.address())
.get_transaction_count(fund_with.address())
.await?;
for (idx, address) in insufficient_balance_addrs.iter().enumerate() {
if !is_balance_sufficient(&admin_signer.address(), min_balance, rpc_client).await? {
if !is_balance_sufficient(&fund_with.address(), min_balance, rpc_client).await? {
// panic early if admin account runs out of funds
return Err(format!(
"Admin account {} has insufficient balance to fund this account.",
admin_signer.address()
fund_with.address()
)
.into());
}
Expand All @@ -178,7 +189,7 @@ pub async fn fund_accounts(
let fund_amount = min_balance;
pending_fund_txs.push(
fund_account(
admin_signer,
fund_with,
*address,
fund_amount,
eth_client,
Expand All @@ -197,7 +208,7 @@ pub async fn fund_accounts(
}

pub async fn fund_account(
admin_signer: &PrivateKeySigner,
sender: &PrivateKeySigner,
recipient: Address,
amount: U256,
rpc_client: &EthProvider,
Expand All @@ -206,18 +217,14 @@ pub async fn fund_account(
println!(
"funding account {} with user account {}",
recipient,
admin_signer.address()
sender.address()
);

let gas_price = rpc_client.get_gas_price().await?;
let nonce = nonce.unwrap_or(
rpc_client
.get_transaction_count(admin_signer.address())
.await?,
);
let nonce = nonce.unwrap_or(rpc_client.get_transaction_count(sender.address()).await?);
let chain_id = rpc_client.get_chain_id().await?;
let tx_req = TransactionRequest {
from: Some(admin_signer.address()),
from: Some(sender.address()),
to: Some(alloy::primitives::TxKind::Call(recipient)),
value: Some(amount),
gas: Some(21000),
Expand All @@ -226,7 +233,7 @@ pub async fn fund_account(
chain_id: Some(chain_id),
..Default::default()
};
let eth_wallet = EthereumWallet::from(admin_signer.to_owned());
let eth_wallet = EthereumWallet::from(sender.to_owned());
let tx = tx_req.build(&eth_wallet).await?;
let res = rpc_client.send_tx_envelope(tx).await?;

Expand Down
118 changes: 89 additions & 29 deletions crates/core/src/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use crate::{
},
Result,
};
use alloy::{hex::ToHexExt, primitives::U256};
use alloy::primitives::{Address, U256};
use async_trait::async_trait;
use named_txs::ExecutionRequest;
pub use named_txs::NamedTxRequestBuilder;
pub use seeder::rand_seed::RandSeed;
use std::{collections::HashMap, fmt::Debug, hash::Hash};
use types::{FunctionCallDefinitionStrict, SpamRequest};
use types::{CreateDefinitionStrict, FunctionCallDefinitionStrict, SpamRequest};

pub use types::{CallbackResult, NamedTxRequest, PlanType};

Expand Down Expand Up @@ -122,28 +122,68 @@ where
Ok(map)
}

fn make_strict_create(
&self,
create_def: &CreateDefinition,
idx: usize,
) -> Result<CreateDefinitionStrict> {
let agents = self.get_agent_store();
let from_address: Address = if let Some(from_pool) = &create_def.from_pool {
let agent = agents
.get_agent(from_pool)
.ok_or(ContenderError::SpamError(
"from_pool not found in agent store",
Some(from_pool.to_owned()),
))?;
agent.get_address(idx).ok_or(ContenderError::SpamError(
"signer not found in agent store",
Some(format!("from_pool={}, idx={}", from_pool, idx)),
))?
} else if let Some(from) = &create_def.from {
from.parse().map_err(|e| {
ContenderError::SpamError(
"failed to parse 'from' address",
Some(format!("from={}, error={}", from, e)),
)
})?
} else {
return Err(ContenderError::SpamError(
"invalid runtime config: must specify 'from' or 'from_pool'",
None,
));
};

Ok(CreateDefinitionStrict {
name: create_def.name.to_owned(),
bytecode: create_def.bytecode.to_owned(),
from: from_address,
})
}

fn make_strict_call(
&self,
funcdef: &FunctionCallDefinition,
idx: usize,
) -> Result<FunctionCallDefinitionStrict> {
let agents = self.get_agent_store();
let from_address: String = if let Some(from_pool) = &funcdef.from_pool {
let from_address: Address = if let Some(from_pool) = &funcdef.from_pool {
let agent = agents
.get_agent(from_pool)
.ok_or(ContenderError::SpamError(
"from_pool not found in agent store",
Some(from_pool.to_owned()),
))?;
agent
.get_address(idx)
.ok_or(ContenderError::SpamError(
"signer not found in agent store",
Some(format!("from_pool={}, idx={}", from_pool, idx)),
))?
.encode_hex_with_prefix()
agent.get_address(idx).ok_or(ContenderError::SpamError(
"signer not found in agent store",
Some(format!("from_pool={}, idx={}", from_pool, idx)),
))?
} else if let Some(from) = &funcdef.from {
from.to_owned()
from.parse().map_err(|e| {
ContenderError::SpamError(
"failed to parse 'from' address",
Some(format!("from={}, error={}", from, e)),
)
})?
} else {
return Err(ContenderError::SpamError(
"invalid runtime config: must specify 'from' or 'from_pool'",
Expand All @@ -152,7 +192,12 @@ where
};

Ok(FunctionCallDefinitionStrict {
to: funcdef.to.to_owned(),
to: funcdef.to.parse().map_err(|e| {
ContenderError::SpamError(
"failed to parse 'to' address",
Some(format!("to={}, error={}", funcdef.to, e)),
)
})?,
from: from_address,
signature: funcdef.signature.to_owned(),
args: funcdef.args.to_owned().unwrap_or_default(),
Expand Down Expand Up @@ -181,24 +226,39 @@ where
match plan_type {
PlanType::Create(on_create_step) => {
let create_steps = conf.get_create_steps()?;
for step in create_steps.iter() {
// lookup placeholder values in DB & update map before templating
templater.find_placeholder_values(&step.bytecode, &mut placeholder_map, db)?;

// create tx with template values
let tx = NamedTxRequestBuilder::new(
templater.template_contract_deploy(step, &placeholder_map)?,
)
.with_name(&step.name)
.build();

let handle = on_create_step(tx.to_owned())?;
if let Some(handle) = handle {
handle.await.map_err(|e| {
ContenderError::with_err(e, "join error; callback crashed")
})?;

let agents = self.get_agent_store();
let num_accts = agents
.all_agents()
.next()
.map(|(_, store)| store.signers.len())
.unwrap_or(1);

for idx in 0..num_accts {
for step in create_steps.iter() {
// lookup placeholder values in DB & update map before templating
templater.find_placeholder_values(
&step.bytecode,
&mut placeholder_map,
db,
)?;

// create tx with template values
let step = self.make_strict_create(step, idx)?;
let tx = NamedTxRequestBuilder::new(
templater.template_contract_deploy(&step, &placeholder_map)?,
)
.with_name(&step.name)
.build();

let handle = on_create_step(tx.to_owned())?;
if let Some(handle) = handle {
handle.await.map_err(|e| {
ContenderError::with_err(e, "join error; callback crashed")
})?;
}
txs.push(tx.into());
}
txs.push(tx.into());
}
}
PlanType::Setup(on_setup_step) => {
Expand Down
Loading

0 comments on commit a47694e

Please sign in to comment.