Skip to content
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

partial fill block + UX improvements #59

Merged
merged 15 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions crates/cli/src/default_scenarios/runconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@ pub enum BuiltinScenarioConfig {
max_gas_per_block: u128,
num_txs: u64,
sender: Address,
fill_percent: u16,
},
}

impl BuiltinScenarioConfig {
pub fn fill_block(max_gas_per_block: u128, num_txs: u64, sender: Address) -> Self {
pub fn fill_block(
max_gas_per_block: u128,
num_txs: u64,
sender: Address,
fill_percent: u16,
) -> Self {
Self::FillBlock {
max_gas_per_block,
num_txs,
sender,
fill_percent,
}
}
}
Expand All @@ -35,8 +42,14 @@ impl From<BuiltinScenarioConfig> for TestConfig {
max_gas_per_block,
num_txs,
sender,
fill_percent,
} => {
let gas_per_tx = max_gas_per_block / num_txs as u128;
let gas_per_tx =
((max_gas_per_block / num_txs as u128) / 100) * fill_percent as u128;
println!(
"Filling blocks to {}% with {} gas per tx",
fill_percent, gas_per_tx
);
let spam_txs = (0..num_txs)
.map(|_| {
SpamRequest::Tx(FunctionCallDefinition {
Expand Down
6 changes: 6 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod commands;
mod default_scenarios;

use std::{
env,
io::Write,
str::FromStr,
sync::{Arc, LazyLock},
Expand Down Expand Up @@ -286,11 +287,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
None,
))?;

let fill_percent = env::var("C_FILL_PERCENT")
.map(|s| u16::from_str(&s).expect("invalid u16: fill_percent"))
.unwrap_or(100u16);

let scenario_config = match scenario {
BuiltinScenario::FillBlock => BuiltinScenarioConfig::fill_block(
block_gas_limit,
txs_per_duration as u64,
admin_signer.address(),
fill_percent,
),
};
let testconfig: TestConfig = scenario_config.into();
Expand Down
2 changes: 1 addition & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
futures = { workspace = true }
async-trait = { workspace = true }
tokio = { workspace = true }
tokio = { workspace = true, features = ["signal"]}
alloy-serde = { workspace = true }
serde_json = { workspace = true }
contender_bundle_provider = { workspace = true }
41 changes: 31 additions & 10 deletions crates/core/src/spammer/spammer_trait.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::sync::Mutex;
use std::{pin::Pin, sync::Arc};

use alloy::providers::Provider;
Expand Down Expand Up @@ -39,6 +40,17 @@ where
run_id: Option<u64>,
sent_tx_callback: Arc<F>,
) -> impl std::future::Future<Output = Result<()>> {
let quit = Arc::new(Mutex::new(false));

let quit_clone = quit.clone();
tokio::task::spawn(async move {
loop {
let _ = tokio::signal::ctrl_c().await;
let mut quit = quit_clone.lock().unwrap();
*quit = true;
}
});

async move {
let tx_requests = scenario
.load_txs(crate::generator::PlanType::Spam(
Expand All @@ -57,36 +69,45 @@ where
let mut cursor = self.on_spam(scenario).await?.take(num_periods);

while let Some(trigger) = cursor.next().await {
if *quit.lock().expect("lock failure") {
println!("CTRL-C received, stopping spam and collecting results...");
let mut quit = quit.lock().expect("lock failure");
*quit = false;
break;
}

let trigger = trigger.to_owned();
let payloads = scenario.prepare_spam(tx_req_chunks[tick]).await?;
let spam_tasks = scenario
.execute_spam(trigger, &payloads, sent_tx_callback.clone())
.await?;
for task in spam_tasks {
task.await
.map_err(|e| ContenderError::with_err(e, "spam task failed"))?;
let res = task.await;
if let Err(e) = res {
eprintln!("spam task failed: {:?}", e);
}
}
tick += 1;
}

let mut timeout_counter = 0;
let mut block_counter = 0;
if let Some(run_id) = run_id {
loop {
if timeout_counter > (num_periods * txs_per_period + 1) {
println!("quitting due to timeout");
break;
}
let cache_size = scenario
.msg_handle
.flush_cache(run_id, block_num + timeout_counter as u64)
.flush_cache(run_id, block_num + block_counter as u64)
.await
.expect("failed to flush cache");
if cache_size == 0 {
break;
}
timeout_counter += 1;
if *quit.lock().expect("lock failure") {
println!("CTRL-C received, stopping result collection...");
break;
}
block_counter += 1;
}
println!("done spamming. run_id={}", run_id);
println!("done. run_id={}", run_id);
}

Ok(())
Expand Down
17 changes: 15 additions & 2 deletions crates/core/src/spammer/tx_actor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{sync::Arc, time::Duration};

use alloy::{primitives::TxHash, providers::Provider};
use alloy::{network::ReceiptResponse, primitives::TxHash, providers::Provider};
use tokio::sync::{mpsc, oneshot};

use crate::{
Expand Down Expand Up @@ -117,7 +117,7 @@ where
.await?
.unwrap_or_default();
println!(
"found {} receipts for block #{}",
"found {} receipts for block {}",
receipts.len(),
target_block_num
);
Expand Down Expand Up @@ -150,6 +150,19 @@ where
.iter()
.find(|r| r.transaction_hash == pending_tx.tx_hash)
.expect("this should never happen");
if !receipt.status() {
println!("tx failed: {:?}", pending_tx.tx_hash);
} else {
println!(
"tx landed. hash={}\tgas_used={}\tblock_num={}",
pending_tx.tx_hash,
receipt.gas_used,
receipt
.block_number
.map(|n| n.to_string())
.unwrap_or("N/A".to_owned())
);
}
RunTx {
tx_hash: pending_tx.tx_hash,
start_timestamp: pending_tx.start_timestamp,
Expand Down
35 changes: 15 additions & 20 deletions crates/core/src/test_scenario.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use alloy::consensus::Transaction;
use alloy::eips::eip2718::Encodable2718;
use alloy::hex::ToHexExt;
use alloy::network::{AnyNetwork, EthereumWallet, TransactionBuilder};
use alloy::primitives::{Address, FixedBytes};
use alloy::primitives::{keccak256, Address, FixedBytes};
use alloy::providers::{PendingTransactionConfig, Provider, ProviderBuilder};
use alloy::rpc::types::TransactionRequest;
use alloy::signers::local::PrivateKeySigner;
Expand Down Expand Up @@ -43,7 +43,7 @@ where
pub agent_store: AgentStore,
pub nonces: HashMap<Address, u64>,
pub chain_id: u64,
pub gas_limits: HashMap<FixedBytes<4>, u128>,
pub gas_limits: HashMap<FixedBytes<32>, u128>,
pub msg_handle: Arc<TxActorHandle>,
}

Expand Down Expand Up @@ -295,29 +295,20 @@ where
))?
.to_owned();
self.nonces.insert(from.to_owned(), nonce + 1);
let fn_sig = FixedBytes::<4>::from_slice(
tx_req
.input
.input
.to_owned()
.map(|b| b.split_at(4).0.to_owned())
.ok_or(ContenderError::SetupError(
"invalid function call",
Some(format!("{:?}", tx_req.input.input)),
))?
.as_slice(),
);
if !self.gas_limits.contains_key(fn_sig.as_slice()) {

let key = keccak256(tx_req.input.input.to_owned().unwrap_or_default());

if let std::collections::hash_map::Entry::Vacant(_) = self.gas_limits.entry(key) {
let gas_limit = self
.eth_client
.estimate_gas(tx_req)
.await
.map_err(|e| ContenderError::with_err(e, "failed to estimate gas for tx"))?;
self.gas_limits.insert(fn_sig, gas_limit);
self.gas_limits.insert(key, gas_limit);
}
let gas_limit = self
.gas_limits
.get(&fn_sig)
.get(&key)
.ok_or(ContenderError::SetupError(
"failed to lookup gas limit",
None,
Expand All @@ -337,7 +328,7 @@ where
.with_max_fee_per_gas(gas_price + (gas_price / 5))
.with_max_priority_fee_per_gas(gas_price)
.with_chain_id(self.chain_id)
.with_gas_limit(gas_limit + (gas_limit / 6));
.with_gas_limit(gas_limit);

Ok((full_tx, signer))
}
Expand Down Expand Up @@ -396,7 +387,7 @@ where
})?;

println!(
"sending tx {} from={} to={:?} input={} value={}",
"sending tx {} from={} to={:?} input={} value={} gas_limit={}",
tx_envelope.tx_hash(),
tx_req.from.map(|s| s.encode_hex()).unwrap_or_default(),
tx_envelope.to().to(),
Expand All @@ -409,7 +400,11 @@ where
tx_req
.value
.map(|s| s.to_string())
.unwrap_or_else(|| "0".to_owned())
.unwrap_or_else(|| "0".to_owned()),
tx_req
.gas
.map(|g| g.to_string())
.unwrap_or_else(|| "N/A".to_owned())
);

ExecutionPayload::SignedTx(tx_envelope, req.to_owned())
Expand Down
5 changes: 3 additions & 2 deletions scenarios/mempool.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ from = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
to = "{SpamMe2}"
from_pool = "redpool"
signature = "consumeGas(uint256 gasAmount)"
args = ["51000"]
args = ["910000"]
fuzz = [{ param = "gasAmount", min = "10000000", max = "30000000" }]

[[spam]]

[spam.tx]
to = "{SpamMe2}"
from_pool = "bluepool"
signature = "consumeGas(uint256 gasAmount)"
args = ["51000"]
args = ["13500000"]
41 changes: 41 additions & 0 deletions scenarios/stress.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[[create]]
bytecode = "0x608060405234801561001057600080fd5b5060408051808201909152600d81526c48656c6c6f2c20576f726c642160981b602082015260009061004290826100e7565b506101a5565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007257607f821691505b60208210810361009257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100e257806000526020600020601f840160051c810160208510156100bf5750805b601f840160051c820191505b818110156100df57600081556001016100cb565b50505b505050565b81516001600160401b0381111561010057610100610048565b6101148161010e845461005e565b84610098565b6020601f82116001811461014857600083156101305750848201515b600019600385901b1c1916600184901b1784556100df565b600084815260208120601f198516915b828110156101785787850151825560209485019460019092019101610158565b50848210156101965786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b610a72806101b46000396000f3fe6080604052600436106100555760003560e01c806369f86ec81461005a5780638199ba20146100715780639402c00414610091578063a329e8de146100b1578063c5eeaf17146100d1578063fb0e722b146100d9575b600080fd5b34801561006657600080fd5b5061006f610104565b005b34801561007d57600080fd5b5061006f61008c3660046106f6565b61010f565b34801561009d57600080fd5b5061006f6100ac36600461074f565b610413565b3480156100bd57600080fd5b5061006f6100cc3660046107a0565b610444565b61006f6104d7565b3480156100e557600080fd5b506100ee610506565b6040516100fb91906107dd565b60405180910390f35b5b60325a1161010557565b6040805180820190915260068152657373746f726560d01b6020820152610137908390610594565b1561015d5760005b818110156101585761015060008055565b60010161013f565b505050565b6040805180820190915260058152641cdb1bd85960da1b6020820152610184908390610594565b1561019c5760005b818110156101585760010161018c565b6040805180820190915260068152656d73746f726560d01b60208201526101c4908390610594565b156101e55760005b81811015610158576101dd60008052565b6001016101cc565b6040805180820190915260058152641b5b1bd85960da1b602082015261020c908390610594565b1561022157600081156101585760010161018c565b60408051808201909152600381526218591960ea1b6020820152610246908390610594565b1561025b57600081156101585760010161018c565b60408051808201909152600381526239bab160e91b6020820152610280908390610594565b1561029557600081156101585760010161018c565b6040805180820190915260038152621b5d5b60ea1b60208201526102ba908390610594565b156102cf57600081156101585760010161018c565b6040805180820190915260038152623234bb60e91b60208201526102f4908390610594565b1561030957600081156101585760010161018c565b60408051808201909152600981526832b1b932b1b7bb32b960b91b6020820152610334908390610594565b156103545760005b818110156101585761034c6105ee565b60010161033c565b60408051808201909152600981526835b2b1b1b0b5991a9b60b91b602082015261037f908390610594565b1561039457600081156101585760010161018c565b60408051808201909152600781526662616c616e636560c81b60208201526103bd908390610594565b156103d257600081156101585760010161018c565b60408051808201909152600681526531b0b63632b960d11b60208201526103fa908390610594565b1561040f57600081156101585760010161018c565b5050565b60008160405160200161042792919061084a565b6040516020818303038152906040526000908161040f919061091e565b600081116104985760405162461bcd60e51b815260206004820152601a60248201527f476173206d7573742062652067726561746572207468616e2030000000000000604482015260640160405180910390fd5b600060956104a8610a28846109dd565b6104b291906109fe565b9050806000036104c0575060015b60005b8181101561015857600080556001016104c3565b60405141903480156108fc02916000818181858888f19350505050158015610503573d6000803e3d6000fd5b50565b6000805461051390610810565b80601f016020809104026020016040519081016040528092919081815260200182805461053f90610810565b801561058c5780601f106105615761010080835404028352916020019161058c565b820191906000526020600020905b81548152906001019060200180831161056f57829003601f168201915b505050505081565b6000816040516020016105a79190610a20565b60405160208183030381529060405280519060200120836040516020016105ce9190610a20565b604051602081830303815290604052805190602001201490505b92915050565b604080516000808252602082018084527f7b05e003631381b3ecd0222e748a7900c262a008c4b7f002ce4a9f0a190619539052604292820183905260608201839052608082019290925260019060a0016020604051602081039080840390855afa158015610660573d6000803e3d6000fd5b50505050565b634e487b7160e01b600052604160045260246000fd5b60008067ffffffffffffffff84111561069757610697610666565b50604051601f19601f85018116603f0116810181811067ffffffffffffffff821117156106c6576106c6610666565b6040528381529050808284018510156106de57600080fd5b83836020830137600060208583010152509392505050565b6000806040838503121561070957600080fd5b823567ffffffffffffffff81111561072057600080fd5b8301601f8101851361073157600080fd5b6107408582356020840161067c565b95602094909401359450505050565b60006020828403121561076157600080fd5b813567ffffffffffffffff81111561077857600080fd5b8201601f8101841361078957600080fd5b6107988482356020840161067c565b949350505050565b6000602082840312156107b257600080fd5b5035919050565b60005b838110156107d45781810151838201526020016107bc565b50506000910152565b60208152600082518060208401526107fc8160408501602087016107b9565b601f01601f19169190910160400192915050565b600181811c9082168061082457607f821691505b60208210810361084457634e487b7160e01b600052602260045260246000fd5b50919050565b600080845461085881610810565b60018216801561086f5760018114610884576108b4565b60ff19831686528115158202860193506108b4565b87600052602060002060005b838110156108ac57815488820152600190910190602001610890565b505081860193505b50505083516108c78183602088016107b9565b01949350505050565b601f82111561015857806000526020600020601f840160051c810160208510156108f75750805b601f840160051c820191505b818110156109175760008155600101610903565b5050505050565b815167ffffffffffffffff81111561093857610938610666565b61094c816109468454610810565b846108d0565b6020601f82116001811461098057600083156109685750848201515b600019600385901b1c1916600184901b178455610917565b600084815260208120601f198516915b828110156109b05787850151825560209485019460019092019101610990565b50848210156109ce5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b818103818111156105e857634e487b7160e01b600052601160045260246000fd5b600082610a1b57634e487b7160e01b600052601260045260246000fd5b500490565b60008251610a328184602087016107b9565b919091019291505056fea264697066735822122040db52b9a7c8a77f16a18198a6085a3ff5f3e5c378e4a9cd497037d20f775eb864736f6c634300081b0033"
name = "SpamMe3"
from = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"

[[spam]]

[spam.tx]
to = "{SpamMe3}"
from_pool = "pool1"
signature = "consumeGas(string memory method, uint256 iterations)"
args = ["sstore", "8000"]
# note: the `fuzz` field will spam the network with `estimateGas` calls; every unique calldata requires a new call
# fuzz = [{ param = "iterations", min = "3000", max = "8000" }]

[[spam]]

[spam.tx]
to = "{SpamMe3}"
from_pool = "pool2"
signature = "consumeGas(string memory method, uint256 iterations)"
args = ["sload", "8000"]
# fuzz = [{ param = "iterations", min = "3000", max = "8000" }]

[[spam]]

[spam.tx]
to = "{SpamMe3}"
from_pool = "pool3"
signature = "consumeGas(string memory method, uint256 iterations)"
args = ["mload", "8000"]
# fuzz = [{ param = "iterations", min = "3000", max = "8000" }]

[[spam]]

[spam.tx]
to = "{SpamMe3}"
from_pool = "pool4"
signature = "consumeGas(string memory method, uint256 iterations)"
args = ["mstore", "8000"]
# fuzz = [{ param = "iterations", min = "3000", max = "8000" }]
Loading