use super::*;
impl<N: Network> Rest<N> {
pub fn routes(&self) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
let deploy = warp::post()
.and(warp::path!("testnet3" / "deploy"))
.and(warp::body::content_length_limit(16 * 1024 * 1024))
.and(warp::body::json())
.and(with(self.record_finder.clone()))
.and(with(self.private_key_ciphertext.clone()))
.and(with(self.api_client.clone()))
.and_then(Self::deploy_program);
let execute = warp::post()
.and(warp::path!("testnet3" / "execute"))
.and(warp::body::content_length_limit(16 * 1024 * 1024))
.and(warp::body::json())
.and(with(self.record_finder.clone()))
.and(with(self.private_key_ciphertext.clone()))
.and(with(self.api_client.clone()))
.and_then(Self::execute_program);
let transfer = warp::post()
.and(warp::path!("testnet3" / "transfer"))
.and(warp::body::content_length_limit(16 * 1024 * 1024))
.and(warp::body::json())
.and(with(self.record_finder.clone()))
.and(with(self.private_key_ciphertext.clone()))
.and(with(self.api_client.clone()))
.and_then(Self::transfer);
let health = warp::get().and(warp::path!("health")).map(reply::reply);
deploy.or(execute).or(transfer).or(health)
}
}
impl<N: Network> Rest<N> {
fn get_private_key(
private_key_ciphertext: Option<Ciphertext<N>>,
private_key: Option<PrivateKey<N>>,
password: Option<String>,
) -> Result<PrivateKey<N>, Rejection> {
if let Some(private_key) = private_key {
Ok(private_key)
} else if let Some(password) = private_key_ciphertext.as_ref().and(password) {
let private_key_ciphertext = private_key_ciphertext.as_ref().unwrap();
Encryptor::decrypt_private_key_with_secret(private_key_ciphertext, &password).or_reject()
} else {
if private_key_ciphertext.is_none() {
return Err(reject::custom(RestError::Request(
"No private key was provided, and no encrypted keys were found in the server's configuration."
.to_string(),
)));
}
Err(reject::custom(RestError::Request("No private key or decryption passwords were provided.".to_string())))
}
}
fn get_api_client(api_client: AleoAPIClient<N>, peer_url: &Option<String>) -> Result<AleoAPIClient<N>, Rejection> {
if let Some(peer_url) = peer_url {
AleoAPIClient::new(peer_url, "testnet3").or_reject()
} else {
Ok(api_client)
}
}
async fn deploy_program(
request: DeployRequest<N>,
record_finder: RecordFinder<N>,
private_key_ciphertext: Option<Ciphertext<N>>,
api_client: AleoAPIClient<N>,
) -> Result<impl Reply, Rejection> {
if request.fee == 0 {
return Err(reject::custom(RestError::Request(
"Fee must be greater than zero in order to deploy a program to the Aleo Network".to_string(),
)));
}
let api_client = Self::get_api_client(api_client, &request.peer_url)?;
let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?;
let mut program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?;
program_manager.add_program(&request.program).or_reject()?;
let fee_record = if request.fee_record.is_none() {
spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?
} else {
request.fee_record.unwrap()
};
let transaction_id =
spawn_blocking!(program_manager.deploy_program(request.program.id(), request.fee, fee_record, None))?;
Ok(reply::json(&transaction_id))
}
async fn execute_program(
mut request: ExecuteRequest<N>,
record_finder: RecordFinder<N>,
private_key_ciphertext: Option<Ciphertext<N>>,
api_client: AleoAPIClient<N>,
) -> Result<impl Reply, Rejection> {
if request.fee == 0 {
return Err(reject::custom(RestError::Request(
"Fee must be greater than zero in order to execute a program on the Aleo Network".to_string(),
)));
}
let api_client = Self::get_api_client(api_client, &request.peer_url)?;
let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?;
let mut program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?;
let fee_record = if request.fee_record.is_none() {
spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?
} else {
request.fee_record.take().unwrap()
};
let transaction_id = spawn_blocking!(program_manager.execute_program(
request.program_id,
request.program_function,
request.inputs.iter(),
request.fee,
fee_record,
None,
))?;
Ok(reply::json(&transaction_id))
}
async fn transfer(
request: TransferRequest<N>,
record_finder: RecordFinder<N>,
private_key_ciphertext: Option<Ciphertext<N>>,
api_client: AleoAPIClient<N>,
) -> Result<impl Reply, Rejection> {
if request.fee == 0 {
return Err(reject::custom(RestError::Request(
"Fee must be greater than zero in order to transfer funds on the Aleo Network".to_string(),
)));
}
let api_client = Self::get_api_client(api_client, &request.peer_url)?;
let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?;
let program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?;
let (amount_record, fee_record) = match (request.amount_record, request.fee_record) {
(Some(amount_record), Some(fee_record)) => (amount_record, fee_record),
(Some(amount_record), None) => {
(amount_record, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?)
}
(None, Some(fee_record)) => {
(spawn_blocking!(record_finder.find_one_record(&private_key, request.amount))?, fee_record)
}
(None, None) => {
spawn_blocking!(record_finder.find_amount_and_fee_records(request.amount, request.fee, &private_key))?
}
};
let transaction_id = spawn_blocking!(program_manager.transfer(
request.amount,
request.fee,
request.recipient,
None,
amount_record,
fee_record
))?;
Ok(reply::json(&transaction_id))
}
}