Skip to content

Commit

Permalink
Added 'panic' command to test app; improved error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
bigspider committed Oct 11, 2024
1 parent 5b1d647 commit bfa036c
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 35 deletions.
1 change: 1 addition & 0 deletions apps/test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ Once the client is running, these are the available commands:
- `b58enc <hex_buffer>` - Computes the base58 encoding of the given buffer (the output is in hex as well).
- `addnumbers <n>` - Computes the sum of the numbers between `1` and `n`.
- `nprimes <n>` - Counts the number of primes up to `n` using the Sieve of Erathostenes.
- `panic <panic message>` - Cause the V-App to panic. Everything written after 'panic' is the panic message.
- An empty command will exit the V-App.
2 changes: 2 additions & 0 deletions apps/test/app/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum Command {
Base58Encode,
Sha256,
CountPrimes,
Panic = 0xff,
}

impl TryFrom<u8> for Command {
Expand All @@ -20,6 +21,7 @@ impl TryFrom<u8> for Command {
0x02 => Ok(Command::Base58Encode),
0x03 => Ok(Command::Sha256),
0x04 => Ok(Command::CountPrimes),
0xff => Ok(Command::Panic),
_ => Err(()),
}
}
Expand Down
4 changes: 4 additions & 0 deletions apps/test/app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ pub fn main(_: isize, _: *const *const u8) -> isize {
Command::Base58Encode => handle_base58_encode(&msg[1..]),
Command::Sha256 => handle_sha256(&msg[1..]),
Command::CountPrimes => handle_count_primes(&msg[1..]),
Command::Panic => {
let panic_msg = core::str::from_utf8(&msg[1..]).unwrap();
panic!("{}", panic_msg);
}
};

sdk::xsend(&response);
Expand Down
90 changes: 58 additions & 32 deletions apps/test/client/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
use crate::commands::Command;
use sdk::vanadium_client::{VAppClient, VAppExecutionError};

#[derive(Debug)]
pub enum TestClientError {
VAppExecutionError(VAppExecutionError),
GenericError(&'static str),
}

impl From<VAppExecutionError> for TestClientError {
fn from(e: VAppExecutionError) -> Self {
Self::VAppExecutionError(e)
}
}

impl From<&'static str> for TestClientError {
fn from(e: &'static str) -> Self {
Self::GenericError(e)
}
}

impl std::fmt::Display for TestClientError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TestClientError::VAppExecutionError(e) => write!(f, "VAppExecutionError: {}", e),
TestClientError::GenericError(e) => write!(f, "GenericError: {}", e),
}
}
}

impl std::error::Error for TestClientError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
TestClientError::VAppExecutionError(e) => Some(e),
TestClientError::GenericError(_) => None,
}
}
}

pub struct TestClient {
app_client: Box<dyn VAppClient + Send + Sync>,
}
Expand All @@ -10,76 +46,66 @@ impl TestClient {
Self { app_client }
}

pub async fn reverse(&mut self, data: &[u8]) -> Result<Vec<u8>, &'static str> {
pub async fn reverse(&mut self, data: &[u8]) -> Result<Vec<u8>, TestClientError> {
let mut msg: Vec<u8> = Vec::new();
msg.extend_from_slice(&[Command::Reverse as u8]);
msg.extend_from_slice(data);

Ok(self
.app_client
.send_message(msg)
.await
.map_err(|_| "Failed")?)
Ok(self.app_client.send_message(msg).await?)
}

pub async fn add_numbers(&mut self, n: u32) -> Result<u64, &'static str> {
pub async fn add_numbers(&mut self, n: u32) -> Result<u64, TestClientError> {
let mut msg: Vec<u8> = Vec::new();
msg.extend_from_slice(&[Command::AddNumbers as u8]);
msg.extend_from_slice(&n.to_be_bytes());

let result_raw = self
.app_client
.send_message(msg)
.await
.map_err(|_| "Failed")?;
let result_raw = self.app_client.send_message(msg).await?;

if result_raw.len() != 8 {
return Err("Invalid response length");
return Err("Invalid response length".into());
}
Ok(u64::from_be_bytes(result_raw.try_into().unwrap()))
}

pub async fn sha256(&mut self, data: &[u8]) -> Result<Vec<u8>, &'static str> {
pub async fn sha256(&mut self, data: &[u8]) -> Result<Vec<u8>, TestClientError> {
let mut msg: Vec<u8> = Vec::new();
msg.extend_from_slice(&[Command::Sha256 as u8]);
msg.extend_from_slice(data);

Ok(self
.app_client
.send_message(msg)
.await
.map_err(|_| "Failed")?)
Ok(self.app_client.send_message(msg).await?)
}

pub async fn b58enc(&mut self, data: &[u8]) -> Result<Vec<u8>, &'static str> {
pub async fn b58enc(&mut self, data: &[u8]) -> Result<Vec<u8>, TestClientError> {
let mut msg: Vec<u8> = Vec::new();
msg.extend_from_slice(&[Command::Base58Encode as u8]);
msg.extend_from_slice(data);

Ok(self
.app_client
.send_message(msg)
.await
.map_err(|_| "Failed")?)
Ok(self.app_client.send_message(msg).await?)
}

pub async fn nprimes(&mut self, n: u32) -> Result<u32, &'static str> {
pub async fn nprimes(&mut self, n: u32) -> Result<u32, TestClientError> {
let mut msg: Vec<u8> = Vec::new();
msg.extend_from_slice(&[Command::CountPrimes as u8]);
msg.extend_from_slice(&n.to_be_bytes());

let result_raw = self
.app_client
.send_message(msg)
.await
.map_err(|_| "Failed")?;
let result_raw = self.app_client.send_message(msg).await?;

if result_raw.len() != 4 {
return Err("Invalid response length");
return Err("Invalid response length".into());
}
Ok(u32::from_be_bytes(result_raw.try_into().unwrap()))
}

pub async fn panic(&mut self, panic_msg: &str) -> Result<(), TestClientError> {
let mut msg: Vec<u8> = Vec::new();
msg.extend_from_slice(&[Command::Panic as u8]);
msg.extend_from_slice(panic_msg.as_bytes());

self.app_client.send_message(msg).await?;

Err("The app should have panicked!".into())
}

pub async fn exit(&mut self) -> Result<i32, &'static str> {
match self.app_client.send_message(Vec::new()).await {
Ok(_) => {
Expand Down
2 changes: 2 additions & 0 deletions apps/test/client/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum Command {
Base58Encode,
Sha256,
CountPrimes,
Panic = 0xff,
}

impl TryFrom<u8> for Command {
Expand All @@ -20,6 +21,7 @@ impl TryFrom<u8> for Command {
0x02 => Ok(Command::Base58Encode),
0x03 => Ok(Command::Sha256),
0x04 => Ok(Command::CountPrimes),
0xff => Ok(Command::Panic),
_ => Err(()),
}
}
Expand Down
24 changes: 21 additions & 3 deletions apps/test/client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum CliCommand {
Sha256(Vec<u8>),
B58Enc(Vec<u8>),
NPrimes(u32),
Panic(String),
Exit,
}

Expand Down Expand Up @@ -82,6 +83,14 @@ fn parse_command(line: &str) -> Result<CliCommand, String> {
_ => unreachable!(),
}
}
"panic" => {
// find where the word "panic" ends and the message starts
let msg = line
.find("panic")
.map(|i| line[i + 5..].trim())
.unwrap_or("");
Ok(CliCommand::Panic(msg.to_string()))
}
_ => Err(format!("Unknown command: '{}'", command)),
}
} else {
Expand All @@ -90,7 +99,7 @@ fn parse_command(line: &str) -> Result<CliCommand, String> {
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();

let default_app_path = if args.native {
Expand All @@ -102,7 +111,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let app_path_str = args.app.unwrap_or(default_app_path.to_string());

let mut test_client = if args.native {
TestClient::new(Box::new(NativeAppClient::new(&app_path_str).await?))
TestClient::new(Box::new(
NativeAppClient::new(&app_path_str)
.await
.map_err(|_| "Failed to create client")?,
))
} else {
let transport_raw: Arc<
dyn Transport<Error = Box<dyn std::error::Error + Send + Sync>> + Send + Sync,
Expand All @@ -123,7 +136,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let transport = TransportWrapper::new(transport_raw.clone());

TestClient::new(Box::new(
VanadiumAppClient::new(&app_path_str, Arc::new(transport)).await?,
VanadiumAppClient::new(&app_path_str, Arc::new(transport))
.await
.map_err(|_| "Failed to create client")?,
))
};

Expand Down Expand Up @@ -153,6 +168,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
CliCommand::NPrimes(n) => {
println!("{}", test_client.nprimes(n).await?);
}
CliCommand::Panic(msg) => {
test_client.panic(&msg).await?;
}
CliCommand::Exit => {
let status = test_client.exit().await?;
if status != 0 {
Expand Down

0 comments on commit bfa036c

Please sign in to comment.