poa-bridge/bridge/src/bridge/deploy.rs

140 lines
4.8 KiB
Rust

use std::sync::Arc;
use futures::{Future, Poll};
#[cfg(feature = "deploy")]
use futures::future;
use web3::Transport;
#[cfg(feature = "deploy")]
use web3::types::U256;
use app::App;
use database::Database;
use error::{Error, ErrorKind};
#[cfg(feature = "deploy")]
use api;
#[cfg(feature = "deploy")]
use ethcore_transaction::{Transaction, Action};
#[cfg(feature = "deploy")]
use super::nonce::{NonceCheck,TransactionWithConfirmation};
pub enum Deployed {
/// No existing database found. Deployed new contracts.
New(Database),
/// Reusing existing contracts.
Existing(Database),
}
#[cfg(feature = "deploy")]
enum DeployState<T: Transport + Clone> {
CheckIfNeeded,
Deploying(future::Join<NonceCheck<T, TransactionWithConfirmation<T>>, NonceCheck<T, TransactionWithConfirmation<T>>>),
}
#[cfg(not(feature = "deploy"))]
enum DeployState {
CheckIfNeeded,
}
#[allow(unused_variables)]
pub fn create_deploy<T: Transport + Clone>(app: Arc<App<T>>, home_chain_id: u64, foreign_chain_id: u64) -> Deploy<T> {
Deploy {
app,
state: DeployState::CheckIfNeeded,
#[cfg(feature = "deploy")]
home_chain_id,
#[cfg(feature = "deploy")]
foreign_chain_id,
}
}
pub struct Deploy<T: Transport + Clone> {
app: Arc<App<T>>,
#[cfg(feature = "deploy")]
state: DeployState<T>,
#[cfg(not(feature = "deploy"))]
state: DeployState,
#[cfg(feature = "deploy")]
home_chain_id: u64,
#[cfg(feature = "deploy")]
foreign_chain_id: u64,
}
impl<T: Transport + Clone> Future for Deploy<T> {
type Item = Deployed;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
let _next_state = match self.state {
DeployState::CheckIfNeeded => match Database::load(&self.app.database_path).map_err(ErrorKind::from) {
Ok(database) => return Ok(Deployed::Existing(database).into()),
Err(ErrorKind::MissingFile(_e)) => {
#[cfg(feature = "deploy")] {
println!("deploy");
let main_data = self.app.home_bridge.constructor(
self.app.config.home.contract.bin.clone().0,
self.app.config.authorities.required_signatures,
self.app.config.authorities.accounts.clone(),
self.app.config.estimated_gas_cost_of_withdraw
);
let test_data = self.app.foreign_bridge.constructor(
self.app.config.foreign.contract.bin.clone().0,
self.app.config.authorities.required_signatures,
self.app.config.authorities.accounts.clone(),
self.app.config.estimated_gas_cost_of_withdraw
);
let main_tx = Transaction {
nonce: U256::zero(),
gas_price: self.app.config.txs.home_deploy.gas_price.into(),
gas: self.app.config.txs.home_deploy.gas.into(),
action: Action::Create,
value: U256::zero(),
data: main_data.into(),
};
let test_tx = Transaction {
nonce: U256::zero(),
gas_price: self.app.config.txs.foreign_deploy.gas_price.into(),
gas: self.app.config.txs.foreign_deploy.gas.into(),
action: Action::Create,
value: U256::zero(),
data: test_data.into(),
};
let main_future = api::send_transaction_with_nonce(self.app.connections.home.clone(), self.app.clone(),
self.app.config.home.clone(), main_tx, self.home_chain_id,
TransactionWithConfirmation(self.app.connections.home.clone(), self.app.config.home.poll_interval, self.app.config.home.required_confirmations));
let test_future = api::send_transaction_with_nonce(self.app.connections.foreign.clone(), self.app.clone(),
self.app.config.foreign.clone(), test_tx, self.foreign_chain_id,
TransactionWithConfirmation(self.app.connections.foreign.clone(), self.app.config.foreign.poll_interval, self.app.config.foreign.required_confirmations));
DeployState::Deploying(main_future.join(test_future))
}
#[cfg(not(feature = "deploy"))] {
return Err(ErrorKind::MissingFile(_e).into())
}
},
Err(err) => return Err(err.into()),
},
#[cfg(feature = "deploy")]
DeployState::Deploying(ref mut future) => {
let (main_receipt, test_receipt) = try_ready!(future.poll());
let database = Database {
home_contract_address: main_receipt.contract_address.expect("contract creation receipt must have an address; qed"),
foreign_contract_address: test_receipt.contract_address.expect("contract creation receipt must have an address; qed"),
home_deploy: main_receipt.block_number.low_u64(),
foreign_deploy: test_receipt.block_number.low_u64(),
checked_deposit_relay: main_receipt.block_number.low_u64(),
checked_withdraw_relay: test_receipt.block_number.low_u64(),
checked_withdraw_confirm: test_receipt.block_number.low_u64(),
};
return Ok(Deployed::New(database).into())
},
};
#[allow(unreachable_code)] {
self.state = _next_state;
}
}
}
}