2020-06-10 12:21:16 +00:00
|
|
|
use std::{
|
|
|
|
process::{Child, Command},
|
|
|
|
time::Duration,
|
|
|
|
};
|
|
|
|
|
|
|
|
const SLEEP_TIME: Duration = Duration::from_secs(3);
|
2020-05-30 14:11:51 +00:00
|
|
|
|
|
|
|
/// A ganache CLI instance. Will close the instance when dropped.
|
2020-06-10 07:33:51 +00:00
|
|
|
///
|
|
|
|
/// Construct this using [`Ganache`](./struct.Ganache.html)
|
|
|
|
pub struct GanacheInstance(Child);
|
2020-05-30 14:11:51 +00:00
|
|
|
|
2020-06-10 07:33:51 +00:00
|
|
|
impl Drop for GanacheInstance {
|
2020-05-30 14:11:51 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
self.0.kill().expect("could not kill ganache");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Builder for launching `ganache-cli`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// If `spawn` is called without `ganache-cli` being available in the user's $PATH
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-06-10 07:33:51 +00:00
|
|
|
/// ```no_run
|
2020-06-17 08:02:03 +00:00
|
|
|
/// use ethers::utils::Ganache;
|
2020-05-31 15:31:13 +00:00
|
|
|
///
|
2020-05-30 14:11:51 +00:00
|
|
|
/// let port = 8545u64;
|
|
|
|
/// let url = format!("http://localhost:{}", port).to_string();
|
|
|
|
///
|
2020-06-10 07:33:51 +00:00
|
|
|
/// let ganache = Ganache::new()
|
2020-05-30 14:11:51 +00:00
|
|
|
/// .port(port)
|
|
|
|
/// .mnemonic("abstract vacuum mammal awkward pudding scene penalty purchase dinner depart evoke puzzle")
|
|
|
|
/// .spawn();
|
|
|
|
///
|
|
|
|
/// drop(ganache); // this will kill the instance
|
|
|
|
/// ```
|
|
|
|
#[derive(Clone, Default)]
|
2020-06-10 07:33:51 +00:00
|
|
|
pub struct Ganache {
|
2020-05-30 14:11:51 +00:00
|
|
|
port: Option<u64>,
|
2020-06-17 08:02:03 +00:00
|
|
|
block_time: Option<u64>,
|
2020-05-30 14:11:51 +00:00
|
|
|
mnemonic: Option<String>,
|
|
|
|
}
|
|
|
|
|
2020-06-10 07:33:51 +00:00
|
|
|
impl Ganache {
|
2020-05-30 14:11:51 +00:00
|
|
|
/// Creates an empty Ganache builder.
|
|
|
|
/// The default port is 8545. The mnemonic is chosen randomly.
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the port which will be used when the `ganache-cli` instance is launched.
|
|
|
|
pub fn port<T: Into<u64>>(mut self, port: T) -> Self {
|
|
|
|
self.port = Some(port.into());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the mnemonic which will be used when the `ganache-cli` instance is launched.
|
|
|
|
pub fn mnemonic<T: Into<String>>(mut self, mnemonic: T) -> Self {
|
|
|
|
self.mnemonic = Some(mnemonic.into());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-06-17 08:02:03 +00:00
|
|
|
/// Sets the block-time which will be used when the `ganache-cli` instance is launched.
|
|
|
|
pub fn block_time<T: Into<u64>>(mut self, block_time: T) -> Self {
|
|
|
|
self.block_time = Some(block_time.into());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-05-30 14:11:51 +00:00
|
|
|
/// Consumes the builder and spawns `ganache-cli` with stdout redirected
|
|
|
|
/// to /dev/null. This takes ~2 seconds to execute as it blocks while
|
|
|
|
/// waiting for `ganache-cli` to launch.
|
2020-06-10 07:33:51 +00:00
|
|
|
pub fn spawn(self) -> GanacheInstance {
|
2020-05-30 14:11:51 +00:00
|
|
|
let mut cmd = Command::new("ganache-cli");
|
|
|
|
cmd.stdout(std::process::Stdio::null());
|
|
|
|
if let Some(port) = self.port {
|
|
|
|
cmd.arg("-p").arg(port.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(mnemonic) = self.mnemonic {
|
|
|
|
cmd.arg("-m").arg(mnemonic);
|
|
|
|
}
|
|
|
|
|
2020-06-17 08:02:03 +00:00
|
|
|
if let Some(block_time) = self.block_time {
|
|
|
|
cmd.arg("-b").arg(block_time.to_string());
|
|
|
|
}
|
|
|
|
|
2020-05-30 14:11:51 +00:00
|
|
|
let ganache_pid = cmd.spawn().expect("couldnt start ganache-cli");
|
|
|
|
|
|
|
|
// wait a couple of seconds for ganache to boot up
|
2020-06-10 12:21:16 +00:00
|
|
|
std::thread::sleep(SLEEP_TIME);
|
2020-06-10 07:33:51 +00:00
|
|
|
GanacheInstance(ganache_pid)
|
2020-05-30 14:11:51 +00:00
|
|
|
}
|
|
|
|
}
|