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 specified_transfer_type = request.transfer_type.as_str();
info!("Transfer type specified: {specified_transfer_type}");
let transfer_type = match specified_transfer_type {
"private" => { TransferType::Private },
"public" => { TransferType::Public },
"private_to_public" => { TransferType::PrivateToPublic },
"public_to_private" => { TransferType::PublicToPrivate },
_ => Err(anyhow!("Invalid transfer type specified, type must be one of the following: private, public, private-to-public, public-to-private")).or_reject()?,
};
let (amount_record, fee_record) =
match transfer_type {
TransferType::Public => {
if let Some(fee_record) = request.fee_record {
(None, fee_record)
} else {
(None, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?)
}
}
TransferType::PublicToPrivate => {
if let Some(fee_record) = request.fee_record {
(None, fee_record)
} else {
(None, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?)
}
}
_ => {
match (request.amount_record, request.fee_record) {
(Some(amount_record), Some(fee_record)) => (Some(amount_record), fee_record),
(Some(amount_record), None) => {
(
Some(amount_record),
spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?,
)
}
(None, Some(fee_record)) => (
Some(spawn_blocking!(record_finder.find_one_record(&private_key, request.amount))?),
fee_record,
),
(None, None) => {
let (amount_record, fee_record) = spawn_blocking!(
record_finder.find_amount_and_fee_records(request.amount, request.fee, &private_key)
)?;
(Some(amount_record), fee_record)
}
}
}
};
let transaction_id = spawn_blocking!(program_manager.transfer(
request.amount,
request.fee,
request.recipient,
transfer_type,
None,
amount_record,
fee_record
))?;
Ok(reply::json(&transaction_id))
}
}