Have monerod running in own container

This commit is contained in:
Philipp Hoenisch 2020-10-29 12:52:29 +11:00
parent 7b101a9c98
commit 0dcb4e56be
No known key found for this signature in database
GPG Key ID: E5F8E74C672BC666
2 changed files with 48 additions and 174 deletions

View File

@ -124,6 +124,12 @@ pub struct Args {
wallets: Vec<WalletArgs>, wallets: Vec<WalletArgs>,
} }
#[derive(Debug)]
pub enum MoneroArgs {
MonerodArgs(MonerodArgs),
WalletArgs(WalletArgs),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MonerodArgs { pub struct MonerodArgs {
pub regtest: bool, pub regtest: bool,
@ -282,10 +288,7 @@ impl IntoIterator for Args {
args.push("/bin/bash".into()); args.push("/bin/bash".into());
args.push("-c".into()); args.push("-c".into());
let wallet_args: Vec<String> = self.wallets.iter().map(|wallet| wallet.args()).collect(); let cmd = format!("{} ", self.monerod.args());
let wallet_args = wallet_args.join(" & ");
let cmd = format!("{} & {} ", self.monerod.args(), wallet_args);
args.push(cmd); args.push(cmd);
args.into_iter() args.into_iter()

View File

@ -27,7 +27,7 @@ pub mod rpc;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use serde::Deserialize; use serde::Deserialize;
use std::time::Duration; use std::time::Duration;
use testcontainers::{clients::Cli, core::Port, Container, Docker}; use testcontainers::{clients::Cli, core::Port, Container, Docker, RunArgs};
use tokio::time; use tokio::time;
use crate::{ use crate::{
@ -44,15 +44,9 @@ const BLOCK_TIME_SECS: u64 = 1;
/// Poll interval when checking if the wallet has synced with monerod. /// Poll interval when checking if the wallet has synced with monerod.
const WAIT_WALLET_SYNC_MILLIS: u64 = 1000; const WAIT_WALLET_SYNC_MILLIS: u64 = 1000;
/// Wallet sub-account indices.
const ACCOUNT_INDEX_PRIMARY: u32 = 0;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Monero { pub struct Monero {
monerod_rpc_port: u16, monerod_rpc_port: u16,
miner_wallet_rpc_port: u16,
alice_wallet_rpc_port: u16,
bob_wallet_rpc_port: u16,
} }
impl<'c> Monero { impl<'c> Monero {
@ -60,59 +54,18 @@ impl<'c> Monero {
pub fn new(cli: &'c Cli) -> Result<(Self, Container<'c, Cli, image::Monero>)> { pub fn new(cli: &'c Cli) -> Result<(Self, Container<'c, Cli, image::Monero>)> {
let monerod_rpc_port: u16 = let monerod_rpc_port: u16 =
port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?;
let miner_wallet_rpc_port: u16 =
port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?;
let alice_wallet_rpc_port: u16 =
port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?;
let bob_wallet_rpc_port: u16 =
port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?;
let image = image::Monero::default() let image = image::Monero::default().with_mapped_port(Port {
.with_mapped_port(Port { local: monerod_rpc_port,
local: monerod_rpc_port, internal: MONEROD_RPC_PORT,
internal: MONEROD_RPC_PORT, });
})
.with_mapped_port(Port {
local: miner_wallet_rpc_port,
internal: MINER_WALLET_RPC_PORT,
})
.with_wallet("miner", MINER_WALLET_RPC_PORT)
.with_mapped_port(Port {
local: alice_wallet_rpc_port,
internal: ALICE_WALLET_RPC_PORT,
})
.with_wallet("alice", ALICE_WALLET_RPC_PORT)
.with_mapped_port(Port {
local: bob_wallet_rpc_port,
internal: BOB_WALLET_RPC_PORT,
})
.with_wallet("bob", BOB_WALLET_RPC_PORT);
println!("running image ..."); let run_args = RunArgs::default()
let docker = cli.run(image); .with_name("monerod")
println!("image ran"); .with_network("monero");
let docker = cli.run_with_args(image, run_args);
Ok(( Ok((Self { monerod_rpc_port }, docker))
Self {
monerod_rpc_port,
miner_wallet_rpc_port,
alice_wallet_rpc_port,
bob_wallet_rpc_port,
},
docker,
))
}
pub fn miner_wallet_rpc_client(&self) -> wallet::Client {
wallet::Client::localhost(self.miner_wallet_rpc_port)
}
pub fn alice_wallet_rpc_client(&self) -> wallet::Client {
wallet::Client::localhost(self.alice_wallet_rpc_port)
}
pub fn bob_wallet_rpc_client(&self) -> wallet::Client {
wallet::Client::localhost(self.bob_wallet_rpc_port)
} }
pub fn monerod_rpc_client(&self) -> monerod::Client { pub fn monerod_rpc_client(&self) -> monerod::Client {
@ -124,122 +77,40 @@ impl<'c> Monero {
/// sub-accounts, one for Alice and one for Bob. If alice/bob_funding is /// sub-accounts, one for Alice and one for Bob. If alice/bob_funding is
/// some, the value needs to be > 0. /// some, the value needs to be > 0.
pub async fn init(&self, alice_funding: u64, bob_funding: u64) -> Result<()> { pub async fn init(&self, alice_funding: u64, bob_funding: u64) -> Result<()> {
let miner_wallet = self.miner_wallet_rpc_client(); // let miner_wallet = self.miner_wallet_rpc_client();
let alice_wallet = self.alice_wallet_rpc_client(); // let alice_wallet = self.alice_wallet_rpc_client();
let bob_wallet = self.bob_wallet_rpc_client(); // let bob_wallet = self.bob_wallet_rpc_client();
let monerod = self.monerod_rpc_client(); // let monerod = self.monerod_rpc_client();
//
miner_wallet.create_wallet("miner_wallet").await?; // miner_wallet.create_wallet("miner_wallet").await?;
alice_wallet.create_wallet("alice_wallet").await?; // alice_wallet.create_wallet("alice_wallet").await?;
bob_wallet.create_wallet("bob_wallet").await?; // bob_wallet.create_wallet("bob_wallet").await?;
//
let miner = self.get_address_miner().await?.address; // let miner = self.get_address_miner().await?.address;
let alice = self.get_address_alice().await?.address; // let alice = self.get_address_alice().await?.address;
let bob = self.get_address_bob().await?.address; // let bob = self.get_address_bob().await?.address;
//
let _ = monerod.generate_blocks(70, &miner).await?; // let _ = monerod.generate_blocks(70, &miner).await?;
self.wait_for_miner_wallet_block_height().await?; // self.wait_for_miner_wallet_block_height().await?;
//
if alice_funding > 0 { // if alice_funding > 0 {
self.fund_account(&alice, &miner, alice_funding).await?; // self.fund_account(&alice, &miner, alice_funding).await?;
self.wait_for_alice_wallet_block_height().await?; // self.wait_for_alice_wallet_block_height().await?;
let balance = self.get_balance_alice().await?; // let balance = self.get_balance_alice().await?;
debug_assert!(balance == alice_funding); // debug_assert!(balance == alice_funding);
} // }
//
if bob_funding > 0 { // if bob_funding > 0 {
self.fund_account(&bob, &miner, bob_funding).await?; // self.fund_account(&bob, &miner, bob_funding).await?;
self.wait_for_bob_wallet_block_height().await?; // self.wait_for_bob_wallet_block_height().await?;
let balance = self.get_balance_bob().await?; // let balance = self.get_balance_bob().await?;
debug_assert!(balance == bob_funding); // debug_assert!(balance == bob_funding);
} // }
//
let _ = tokio::spawn(mine(monerod.clone(), miner)); // let _ = tokio::spawn(mine(monerod.clone(), miner));
Ok(()) Ok(())
} }
async fn fund_account(&self, address: &str, miner: &str, funding: u64) -> Result<()> {
let monerod = self.monerod_rpc_client();
self.transfer_from_primary(funding, address).await?;
let _ = monerod.generate_blocks(10, miner).await?;
self.wait_for_miner_wallet_block_height().await?;
Ok(())
}
async fn wait_for_miner_wallet_block_height(&self) -> Result<()> {
self.wait_for_wallet_height(self.miner_wallet_rpc_client())
.await
}
pub async fn wait_for_alice_wallet_block_height(&self) -> Result<()> {
self.wait_for_wallet_height(self.alice_wallet_rpc_client())
.await
}
pub async fn wait_for_bob_wallet_block_height(&self) -> Result<()> {
self.wait_for_wallet_height(self.bob_wallet_rpc_client())
.await
}
// It takes a little while for the wallet to sync with monerod.
async fn wait_for_wallet_height(&self, wallet: wallet::Client) -> Result<()> {
let monerod = self.monerod_rpc_client();
let height = monerod.get_block_count().await?;
while wallet.block_height().await?.height < height {
time::delay_for(Duration::from_millis(WAIT_WALLET_SYNC_MILLIS)).await;
}
Ok(())
}
/// Get addresses for the primary account.
async fn get_address_miner(&self) -> Result<GetAddress> {
let wallet = self.miner_wallet_rpc_client();
wallet.get_address(ACCOUNT_INDEX_PRIMARY).await
}
/// Get addresses for the Alice's account.
async fn get_address_alice(&self) -> Result<GetAddress> {
let wallet = self.alice_wallet_rpc_client();
wallet.get_address(ACCOUNT_INDEX_PRIMARY).await
}
/// Get addresses for the Bob's account.
async fn get_address_bob(&self) -> Result<GetAddress> {
let wallet = self.bob_wallet_rpc_client();
wallet.get_address(ACCOUNT_INDEX_PRIMARY).await
}
/// Gets the balance of Alice's account.
async fn get_balance_alice(&self) -> Result<u64> {
let wallet = self.alice_wallet_rpc_client();
wallet.get_balance(ACCOUNT_INDEX_PRIMARY).await
}
/// Gets the balance of Bob's account.
async fn get_balance_bob(&self) -> Result<u64> {
let wallet = self.bob_wallet_rpc_client();
wallet.get_balance(ACCOUNT_INDEX_PRIMARY).await
}
/// Transfers moneroj from the primary account.
async fn transfer_from_primary(&self, amount: u64, address: &str) -> Result<Transfer> {
let wallet = self.miner_wallet_rpc_client();
wallet
.transfer(ACCOUNT_INDEX_PRIMARY, amount, address)
.await
}
}
/// Mine a block ever BLOCK_TIME_SECS seconds.
async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> {
loop {
time::delay_for(Duration::from_secs(BLOCK_TIME_SECS)).await;
monerod.generate_blocks(1, &reward_address).await?;
}
} }
// We should be able to use monero-rs for this but it does not include all // We should be able to use monero-rs for this but it does not include all