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

rpc url deployment association #84

Merged
merged 7 commits into from
Jan 14, 2025
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
4 changes: 4 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install libsqlite3
run: sudo apt-get install -y libsqlite3-dev
- name: Build
run: cargo build --verbose --workspace

Expand All @@ -36,5 +38,7 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install libsqlite3
run: sudo apt-get install -y libsqlite3-dev
- name: Run tests
run: cargo test --verbose --workspace
2 changes: 1 addition & 1 deletion crates/cli/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub async fn run(
.await?;

let contract_name = "SpamMe";
let contract_result = db.get_named_tx(contract_name)?;
let contract_result = db.get_named_tx(contract_name, rpc_url.as_str())?;
let do_deploy_contracts = if contract_result.is_some() {
let input = prompt_cli(format!(
"{} deployment already detected. Re-deploy? [y/N]",
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/db/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ impl DbOps for MockDb {
Ok(0)
}

fn insert_named_txs(&self, _named_txs: Vec<NamedTx>) -> Result<()> {
fn insert_named_txs(&self, _named_txs: Vec<NamedTx>, _rpc_url: &str) -> Result<()> {
Ok(())
}

fn get_named_tx(&self, _name: &str) -> Result<Option<NamedTx>> {
fn get_named_tx(&self, _name: &str, _rpc_url: &str) -> Result<Option<NamedTx>> {
Ok(Some(NamedTx::new(
String::default(),
TxHash::default(),
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ pub trait DbOps {

fn num_runs(&self) -> Result<u64>;

fn insert_named_txs(&self, named_txs: Vec<NamedTx>) -> Result<()>;
fn insert_named_txs(&self, named_txs: Vec<NamedTx>, rpc_url: &str) -> Result<()>;

fn get_named_tx(&self, name: &str) -> Result<Option<NamedTx>>;
fn get_named_tx(&self, name: &str, rpc_url: &str) -> Result<Option<NamedTx>>;

fn get_named_tx_by_address(&self, address: &Address) -> Result<Option<NamedTx>>;

Expand Down
15 changes: 12 additions & 3 deletions crates/core/src/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ where
fn get_db(&self) -> &D;
fn get_fuzz_seeder(&self) -> &impl Seeder;
fn get_agent_store(&self) -> &AgentStore;
fn get_rpc_url(&self) -> String;

/// Generates a map of N=`num_values` fuzzed values for each parameter in `fuzz_args`.
fn create_fuzz_map(
Expand Down Expand Up @@ -258,7 +259,12 @@ where
let step = self.make_strict_create(step, 0)?;

// lookup placeholder values in DB & update map before templating
templater.find_placeholder_values(&step.bytecode, &mut placeholder_map, db)?;
templater.find_placeholder_values(
&step.bytecode,
&mut placeholder_map,
db,
&self.get_rpc_url(),
)?;

// create tx with template values
let tx = NamedTxRequestBuilder::new(
Expand All @@ -280,10 +286,11 @@ where
let setup_steps = conf.get_setup_steps()?;

// txs will be grouped by account [from=1, from=1, from=1, from=2, from=2, from=2, ...]
let rpc_url = self.get_rpc_url();

for step in setup_steps.iter() {
// lookup placeholders in DB & update map before templating
templater.find_fncall_placeholders(step, db, &mut placeholder_map)?;
templater.find_fncall_placeholders(step, db, &mut placeholder_map, &rpc_url)?;

// setup tx with template values
let tx = NamedTxRequest::new(
Expand Down Expand Up @@ -321,8 +328,10 @@ where
};

// finds placeholders in a function call definition and populates `placeholder_map` and `canonical_fuzz_map` with injectable values.
let rpc_url = self.get_rpc_url();
let mut lookup_tx_placeholders = |tx: &FunctionCallDefinition| {
let res = templater.find_fncall_placeholders(tx, db, &mut placeholder_map);
let res =
templater.find_fncall_placeholders(tx, db, &mut placeholder_map, &rpc_url);
if let Err(e) = res {
eprintln!("error finding placeholders: {}", e);
return Err(ContenderError::SpamError(
Expand Down
36 changes: 20 additions & 16 deletions crates/core/src/generator/templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ where
arg: &str,
placeholder_map: &mut HashMap<K, String>,
db: &impl DbOps,
rpc_url: &str,
) -> Result<()> {
// count number of placeholders (by left brace) in arg
let num_template_vals = self.num_placeholders(arg);
Expand All @@ -57,25 +58,27 @@ where
}

let template_value = db
.get_named_tx(&template_key.to_string())
.get_named_tx(&template_key.to_string(), rpc_url)
.map_err(|e| {
ContenderError::SpamError(
"failed to get placeholder value from DB",
"Failed to get named tx from DB. There may be an issue with your database.",
Some(format!("value={:?} ({})", template_key, e)),
)
})?
.ok_or(ContenderError::SpamError(
"failed to find placeholder value in DB",
})?;
if let Some(template_value) = template_value {
placeholder_map.insert(
template_key,
template_value
.address
.map(|a| self.encode_contract_address(&a))
.unwrap_or_default(),
);
} else {
return Err(ContenderError::SpamError(
"Address for named contract not found in DB. You may need to run setup steps first.",
Some(template_key.to_string()),
))?;

placeholder_map.insert(
template_key,
template_value
.address
.map(|a| self.encode_contract_address(&a))
.unwrap_or_default(),
);
));
}
}
Ok(())
}
Expand All @@ -88,13 +91,14 @@ where
fncall: &FunctionCallDefinition,
db: &impl DbOps,
placeholder_map: &mut HashMap<K, String>,
rpc_url: &str,
) -> Result<()> {
// find templates in fn args & `to`
let fn_args = fncall.args.to_owned().unwrap_or_default();
for arg in fn_args.iter() {
self.find_placeholder_values(arg, placeholder_map, db)?;
self.find_placeholder_values(arg, placeholder_map, db, rpc_url)?;
}
self.find_placeholder_values(&fncall.to, placeholder_map, db)?;
self.find_placeholder_values(&fncall.to, placeholder_map, db, rpc_url)?;
Ok(())
}

Expand Down
9 changes: 8 additions & 1 deletion crates/core/src/test_scenario.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ where
"deploying contract: {:?}",
tx_req.name.as_ref().unwrap_or(&"".to_string())
);
let rpc_url = self.rpc_url.to_owned();
let handle = tokio::task::spawn(async move {
// estimate gas limit
let gas_limit = wallet
Expand Down Expand Up @@ -217,6 +218,7 @@ where
receipt.contract_address,
)
.into(),
rpc_url.as_str(),
)
.expect("failed to insert tx into db");
});
Expand Down Expand Up @@ -253,7 +255,7 @@ where
let wallet = ProviderBuilder::new()
.with_simple_nonce_management()
.wallet(wallet)
.on_http(rpc_url);
.on_http(rpc_url.to_owned());

let chain_id = wallet.get_chain_id().await.expect("failed to get chain id");
let gas_price = wallet
Expand All @@ -280,6 +282,7 @@ where
db.insert_named_txs(
NamedTx::new(name, receipt.transaction_hash, receipt.contract_address)
.into(),
rpc_url.as_str(),
)
.expect("failed to insert tx into db");
}
Expand Down Expand Up @@ -595,6 +598,10 @@ where
fn get_agent_store(&self) -> &AgentStore {
&self.agent_store
}

fn get_rpc_url(&self) -> String {
self.rpc_url.to_string()
}
}

#[cfg(test)]
Expand Down
57 changes: 45 additions & 12 deletions crates/sqlite_db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,21 @@ impl DbOps for SqliteDb {
)",
params![],
)?;
self.execute(
"CREATE TABLE rpc_urls (
id INTEGER PRIMARY KEY,
url TEXT NOT NULL UNIQUE
)",
params![],
)?;
self.execute(
"CREATE TABLE named_txs (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
tx_hash TEXT NOT NULL,
contract_address TEXT
contract_address TEXT,
rpc_url_id INTEGER NOT NULL,
FOREIGN KEY (rpc_url_id) REFERENCES rpc_urls(id)
)",
params![],
)?;
Expand Down Expand Up @@ -196,14 +205,30 @@ impl DbOps for SqliteDb {
Ok(res)
}

fn insert_named_txs(&self, named_txs: Vec<NamedTx>) -> Result<()> {
fn insert_named_txs(&self, named_txs: Vec<NamedTx>, rpc_url: &str) -> Result<()> {
let pool = self.get_pool()?;

// first check the rpc_urls table; insert if not present
pool.execute(
"INSERT OR IGNORE INTO rpc_urls (url) VALUES (?)",
params![rpc_url],
)
.map_err(|e| ContenderError::with_err(e, "failed to insert rpc_url into DB"))?;

// then get the rpc_url ID
let rpc_url_id: i64 = self.query_row(
"SELECT id FROM rpc_urls WHERE url = ?1",
params![rpc_url],
|row| row.get(0),
)?;

let stmts = named_txs.iter().map(|tx| {
format!(
"INSERT INTO named_txs (name, tx_hash, contract_address) VALUES ('{}', '{}', '{}');",
"INSERT INTO named_txs (name, tx_hash, contract_address, rpc_url_id) VALUES ('{}', '{}', '{}', {});",
tx.name,
tx.tx_hash.encode_hex(),
tx.address.map(|a| a.encode_hex()).unwrap_or_default()
tx.address.map(|a| a.encode_hex()).unwrap_or_default(),
rpc_url_id,
)
});
pool.execute_batch(&format!(
Expand All @@ -218,16 +243,18 @@ impl DbOps for SqliteDb {
Ok(())
}

fn get_named_tx(&self, name: &str) -> Result<Option<NamedTx>> {
fn get_named_tx(&self, name: &str, rpc_url: &str) -> Result<Option<NamedTx>> {
let pool = self.get_pool()?;
let mut stmt = pool
.prepare(
"SELECT name, tx_hash, contract_address FROM named_txs WHERE name = ?1 ORDER BY id DESC LIMIT 1",
"SELECT name, tx_hash, contract_address, rpc_url_id FROM named_txs WHERE name = ?1 AND rpc_url_id = (
SELECT id FROM rpc_urls WHERE url = ?2
) ORDER BY id DESC LIMIT 1",
)
.map_err(|e| ContenderError::with_err(e, "failed to prepare statement"))?;

let row = stmt
.query_map(params![name], NamedTxRow::from_row)
.query_map(params![name, rpc_url], NamedTxRow::from_row)
.map_err(|e| ContenderError::with_err(e, "failed to map row"))?;
let res = row
.last()
Expand Down Expand Up @@ -328,10 +355,14 @@ mod tests {
let contract_address = Some(Address::from_slice(&[4u8; 20]));
let name1 = "test_tx".to_string();
let name2 = "test_tx2";
db.insert_named_txs(vec![
NamedTx::new(name1.to_owned(), tx_hash, contract_address),
NamedTx::new(name2.to_string(), tx_hash, contract_address),
])
let rpc_url = "http://test.url:8545";
db.insert_named_txs(
vec![
NamedTx::new(name1.to_owned(), tx_hash, contract_address),
NamedTx::new(name2.to_string(), tx_hash, contract_address),
],
rpc_url,
)
.unwrap();
let count: i64 = db
.get_pool()
Expand All @@ -342,10 +373,12 @@ mod tests {
.unwrap();
assert_eq!(count, 2);

let res1 = db.get_named_tx(&name1).unwrap().unwrap();
let res1 = db.get_named_tx(&name1, rpc_url).unwrap().unwrap();
assert_eq!(res1.name, name1);
assert_eq!(res1.tx_hash, tx_hash);
assert_eq!(res1.address, contract_address);
let res2 = db.get_named_tx(&name1, "http://wrong.url:8545").unwrap();
assert!(res2.is_none());
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions crates/testfile/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Configuration to run a test scenario; used to generate PlanConfigs.
/// Defines TOML schema for scenario files.
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct TestConfig {
/// Template variables
Expand Down
2 changes: 1 addition & 1 deletion scenarios/stress.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[[create]]
bytecode = "0x608060405234801561001057600080fd5b5060408051808201909152600d81526c48656c6c6f2c20576f726c642160981b602082015260009061004290826100e7565b506101a5565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007257607f821691505b60208210810361009257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100e257806000526020600020601f840160051c810160208510156100bf5750805b601f840160051c820191505b818110156100df57600081556001016100cb565b50505b505050565b81516001600160401b0381111561010057610100610048565b6101148161010e845461005e565b84610098565b6020601f82116001811461014857600083156101305750848201515b600019600385901b1c1916600184901b1784556100df565b600084815260208120601f198516915b828110156101785787850151825560209485019460019092019101610158565b50848210156101965786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b610a72806101b46000396000f3fe6080604052600436106100555760003560e01c806369f86ec81461005a5780638199ba20146100715780639402c00414610091578063a329e8de146100b1578063c5eeaf17146100d1578063fb0e722b146100d9575b600080fd5b34801561006657600080fd5b5061006f610104565b005b34801561007d57600080fd5b5061006f61008c3660046106f6565b61010f565b34801561009d57600080fd5b5061006f6100ac36600461074f565b610413565b3480156100bd57600080fd5b5061006f6100cc3660046107a0565b610444565b61006f6104d7565b3480156100e557600080fd5b506100ee610506565b6040516100fb91906107dd565b60405180910390f35b5b60325a1161010557565b6040805180820190915260068152657373746f726560d01b6020820152610137908390610594565b1561015d5760005b818110156101585761015060008055565b60010161013f565b505050565b6040805180820190915260058152641cdb1bd85960da1b6020820152610184908390610594565b1561019c5760005b818110156101585760010161018c565b6040805180820190915260068152656d73746f726560d01b60208201526101c4908390610594565b156101e55760005b81811015610158576101dd60008052565b6001016101cc565b6040805180820190915260058152641b5b1bd85960da1b602082015261020c908390610594565b1561022157600081156101585760010161018c565b60408051808201909152600381526218591960ea1b6020820152610246908390610594565b1561025b57600081156101585760010161018c565b60408051808201909152600381526239bab160e91b6020820152610280908390610594565b1561029557600081156101585760010161018c565b6040805180820190915260038152621b5d5b60ea1b60208201526102ba908390610594565b156102cf57600081156101585760010161018c565b6040805180820190915260038152623234bb60e91b60208201526102f4908390610594565b1561030957600081156101585760010161018c565b60408051808201909152600981526832b1b932b1b7bb32b960b91b6020820152610334908390610594565b156103545760005b818110156101585761034c6105ee565b60010161033c565b60408051808201909152600981526835b2b1b1b0b5991a9b60b91b602082015261037f908390610594565b1561039457600081156101585760010161018c565b60408051808201909152600781526662616c616e636560c81b60208201526103bd908390610594565b156103d257600081156101585760010161018c565b60408051808201909152600681526531b0b63632b960d11b60208201526103fa908390610594565b1561040f57600081156101585760010161018c565b5050565b60008160405160200161042792919061084a565b6040516020818303038152906040526000908161040f919061091e565b600081116104985760405162461bcd60e51b815260206004820152601a60248201527f476173206d7573742062652067726561746572207468616e2030000000000000604482015260640160405180910390fd5b600060956104a8610a28846109dd565b6104b291906109fe565b9050806000036104c0575060015b60005b8181101561015857600080556001016104c3565b60405141903480156108fc02916000818181858888f19350505050158015610503573d6000803e3d6000fd5b50565b6000805461051390610810565b80601f016020809104026020016040519081016040528092919081815260200182805461053f90610810565b801561058c5780601f106105615761010080835404028352916020019161058c565b820191906000526020600020905b81548152906001019060200180831161056f57829003601f168201915b505050505081565b6000816040516020016105a79190610a20565b60405160208183030381529060405280519060200120836040516020016105ce9190610a20565b604051602081830303815290604052805190602001201490505b92915050565b604080516000808252602082018084527f7b05e003631381b3ecd0222e748a7900c262a008c4b7f002ce4a9f0a190619539052604292820183905260608201839052608082019290925260019060a0016020604051602081039080840390855afa158015610660573d6000803e3d6000fd5b50505050565b634e487b7160e01b600052604160045260246000fd5b60008067ffffffffffffffff84111561069757610697610666565b50604051601f19601f85018116603f0116810181811067ffffffffffffffff821117156106c6576106c6610666565b6040528381529050808284018510156106de57600080fd5b83836020830137600060208583010152509392505050565b6000806040838503121561070957600080fd5b823567ffffffffffffffff81111561072057600080fd5b8301601f8101851361073157600080fd5b6107408582356020840161067c565b95602094909401359450505050565b60006020828403121561076157600080fd5b813567ffffffffffffffff81111561077857600080fd5b8201601f8101841361078957600080fd5b6107988482356020840161067c565b949350505050565b6000602082840312156107b257600080fd5b5035919050565b60005b838110156107d45781810151838201526020016107bc565b50506000910152565b60208152600082518060208401526107fc8160408501602087016107b9565b601f01601f19169190910160400192915050565b600181811c9082168061082457607f821691505b60208210810361084457634e487b7160e01b600052602260045260246000fd5b50919050565b600080845461085881610810565b60018216801561086f5760018114610884576108b4565b60ff19831686528115158202860193506108b4565b87600052602060002060005b838110156108ac57815488820152600190910190602001610890565b505081860193505b50505083516108c78183602088016107b9565b01949350505050565b601f82111561015857806000526020600020601f840160051c810160208510156108f75750805b601f840160051c820191505b818110156109175760008155600101610903565b5050505050565b815167ffffffffffffffff81111561093857610938610666565b61094c816109468454610810565b846108d0565b6020601f82116001811461098057600083156109685750848201515b600019600385901b1c1916600184901b178455610917565b600084815260208120601f198516915b828110156109b05787850151825560209485019460019092019101610990565b50848210156109ce5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b818103818111156105e857634e487b7160e01b600052601160045260246000fd5b600082610a1b57634e487b7160e01b600052601260045260246000fd5b500490565b60008251610a328184602087016107b9565b919091019291505056fea264697066735822122040db52b9a7c8a77f16a18198a6085a3ff5f3e5c378e4a9cd497037d20f775eb864736f6c634300081b0033"
name = "SpamMe3"
from = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
from_pool = "admin"

[[spam]]

Expand Down
Loading