Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: snot errors #93

Merged
merged 14 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"rust-analyzer.rustfmt.extraArgs": ["+nightly"]
"rust-analyzer.rustfmt.extraArgs": [
"+nightly"
],
"rust-analyzer.showUnlinkedFileNotification": false
}
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions crates/aot/src/ledger/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ pub struct LedgerQuery {
pub readonly: bool,

#[arg(long)]
/// Receive messages from /mainnet/transaction/broadcast and record them to the output
/// Receive messages from /mainnet/transaction/broadcast and record them to
/// the output
pub record: bool,

#[arg(long, short, default_value = "transactions.json")]
Expand Down Expand Up @@ -81,8 +82,8 @@ impl LedgerQuery {
.route("/mainnet/block/hash/latest", get(Self::latest_hash))
.route("/mainnet/transaction/broadcast", post(Self::broadcast_tx))
.route("/block", post(Self::add_block))
// TODO: for ahead of time ledger generation, support a /beacon_block endpoint to write beacon block
// TODO: api to get and decrypt records for a private key
// TODO: for ahead of time ledger generation, support a /beacon_block endpoint to write
// beacon block TODO: api to get and decrypt records for a private key
.with_state(Arc::new(state));

let listener = tokio::net::TcpListener::bind(SocketAddr::new(self.bind, self.port)).await?;
Expand Down
4 changes: 2 additions & 2 deletions crates/aot/src/ledger/tx/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ impl Num {
util::CannonTx::Dependent(id, tx) => {
// println!(
// "{id}\t{}",
// serde_json::to_string(&tx).expect("serialize proof")
// );
// serde_json::to_string(&tx).expect("serialize
// proof") );
}
})
.map(drop)
Expand Down
2 changes: 1 addition & 1 deletion crates/aot/src/runner/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::str::FromStr;
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
path::PathBuf,
Expand All @@ -6,7 +7,6 @@ use std::{
use aleo_std::StorageMode;
use anyhow::{bail, Result};
use clap::Args;
use core::str::FromStr;
use serde::{Deserialize, Serialize};
use serde_clap_deserialize::serde_clap_default;
use snarkos_node::Node;
Expand Down
3 changes: 2 additions & 1 deletion crates/snot-agent/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ pub struct Cli {
#[arg(long)]
pub id: Option<AgentId>,

/// Locally provided private key file, used for envs where private keys are locally provided
/// Locally provided private key file, used for envs where private keys are
/// locally provided
#[arg(long)]
#[clap(long = "private-key-file")]
pub private_key_file: Option<PathBuf>,
Expand Down
6 changes: 2 additions & 4 deletions crates/snot-agent/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ use std::{

use snot_common::{
rpc::{
agent::{
AgentError, AgentMetric, AgentService, AgentServiceRequest, AgentServiceResponse,
ReconcileError,
},
agent::{AgentMetric, AgentService, AgentServiceRequest, AgentServiceResponse},
control::{ControlServiceRequest, ControlServiceResponse},
error::{AgentError, ReconcileError},
MuxMessage,
},
state::{AgentId, AgentPeer, AgentState, KeyState, PortConfig},
Expand Down
1 change: 1 addition & 0 deletions crates/snot-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ lazy_static.workspace = true
regex.workspace = true
serde.workspace = true
serde_json.workspace = true
strum_macros = "0.26"
tarpc.workspace = true
thiserror.workspace = true
tokio.workspace = true
33 changes: 3 additions & 30 deletions crates/snot-common/src/rpc/agent.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::net::IpAddr;

use serde::{Deserialize, Serialize};
use thiserror::Error;

use super::control::ResolveError;
use super::error::*;
use crate::state::{AgentState, PortConfig};

/// The RPC service that agents implement as a server.
Expand All @@ -27,7 +26,8 @@ pub trait AgentService {
async fn broadcast_tx(tx: String) -> Result<(), AgentError>;

/// Locally execute an authorization, using the given query
/// environment id is passed so the agent can determine which aot binary to use
/// environment id is passed so the agent can determine which aot binary to
/// use
async fn execute_authorization(
env_id: usize,
query: String,
Expand All @@ -37,33 +37,6 @@ pub trait AgentService {
async fn get_metric(metric: AgentMetric) -> f64;
}

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum ReconcileError {
#[error("aborted by a more recent reconcilation request")]
Aborted,
#[error("failed to download the specified storage")]
StorageAcquireError,
#[error("failed to resolve addresses of stated peers")]
ResolveAddrError(ResolveError),
#[error("agent did not provide a local private key")]
NoLocalPrivateKey,
#[error("unknown error")]
Unknown,
}

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum AgentError {
#[error("invalid agent state")]
InvalidState,
#[error("failed to parse json")]
FailedToParseJson,
#[error("failed to make a request")]
FailedToMakeRequest,
#[error("failed to spawn a process")]
FailedToSpawnProcess,
#[error("process failed")]
ProcessFailed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AgentMetric {
Tps,
Expand Down
12 changes: 1 addition & 11 deletions crates/snot-common/src/rpc/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use std::{
net::IpAddr,
};

use serde::{Deserialize, Serialize};
use thiserror::Error;

use super::error::ResolveError;
use crate::state::AgentId;

#[tarpc::service]
Expand All @@ -17,11 +15,3 @@ pub trait ControlService {
peers: HashSet<AgentId>,
) -> Result<HashMap<AgentId, IpAddr>, ResolveError>;
}

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum ResolveError {
#[error("source agent not found")]
SourceAgentNotFound,
#[error("agent has no addresses")]
AgentHasNoAddresses,
}
58 changes: 58 additions & 0 deletions crates/snot-common/src/rpc/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use serde::{Deserialize, Serialize};
use strum_macros::AsRefStr;
use thiserror::Error;

#[derive(Debug, Serialize)]
pub struct PrettyError {
#[serde(rename = "type")]
pub type_: String,
voximity marked this conversation as resolved.
Show resolved Hide resolved
pub error: String,
}

impl<E> From<&E> for PrettyError
where
E: std::error::Error + AsRef<str>,
{
fn from(error: &E) -> Self {
Self {
type_: error.as_ref().to_string(),
error: error.to_string(),
}
}
}

#[derive(Debug, Error, Serialize, Deserialize, AsRefStr)]
pub enum AgentError {
#[error("invalid agent state")]
InvalidState,
#[error("failed to parse json")]
FailedToParseJson,
#[error("failed to make a request")]
FailedToMakeRequest,
#[error("failed to spawn a process")]
FailedToSpawnProcess,
#[error("process failed")]
ProcessFailed,
}

#[derive(Debug, Error, Serialize, Deserialize, AsRefStr)]
pub enum ResolveError {
#[error("source agent not found")]
SourceAgentNotFound,
#[error("agent has no addresses")]
AgentHasNoAddresses,
}

#[derive(Debug, Error, Serialize, Deserialize, AsRefStr)]
pub enum ReconcileError {
#[error("aborted by a more recent reconcilation request")]
Aborted,
#[error("failed to download the specified storage")]
StorageAcquireError,
#[error("failed to resolve addresses of stated peers")]
ResolveAddrError(ResolveError),
#[error("agent did not provide a local private key")]
NoLocalPrivateKey,
#[error("unknown error")]
Unknown,
}
1 change: 1 addition & 0 deletions crates/snot-common/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use tokio::sync::mpsc;

pub mod agent;
pub mod control;
pub mod error;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MuxMessage<Control, Agent> {
Expand Down
2 changes: 2 additions & 0 deletions crates/snot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ reqwest = { workspace = true, features = ["stream", "json"] }
serde.workspace = true
serde_json.workspace = true
serde_yaml.workspace = true
serde_with = "3.7"
sha2 = "0.10.8"
snot-common = { path = "../snot-common" }
strum_macros = "0.26"
surrealdb = { version = "1.3", default-features = false, features = [
"kv-rocksdb",
] }
Expand Down
37 changes: 24 additions & 13 deletions crates/snot/src/cannon/authorized.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::path::PathBuf;

use anyhow::{ensure, Result};
use tokio::process::Command;

use super::error::{AuthorizeError, CannonError};
use crate::error::CommandError;

#[derive(Clone, Debug)]
pub enum Authorize {
TransferPublic {
Expand All @@ -14,7 +16,7 @@ pub enum Authorize {
}

impl Authorize {
pub async fn run(self, bin: &PathBuf) -> Result<serde_json::Value> {
pub async fn run(self, bin: &PathBuf) -> Result<serde_json::Value, CannonError> {
let mut command = Command::new(bin);
command
.stdout(std::io::stdout())
Expand Down Expand Up @@ -43,23 +45,32 @@ impl Authorize {

command.arg("--broadcast");

let res = command.output().await?;
let res = command.output().await.map_err(|e| {
AuthorizeError::Command(CommandError::action("output", "aot authorize", e))
})?;

if !res.status.success() {
return Err(anyhow::anyhow!(
"command failed with status {}: {}",
Err(AuthorizeError::Command(CommandError::status(
"aot authorize",
res.status,
String::from_utf8_lossy(&res.stderr)
));
String::from_utf8_lossy(&res.stderr).to_string(),
)))?;
}

let blob: serde_json::Value = serde_json::from_slice(&res.stdout)?;
let blob: serde_json::Value =
serde_json::from_slice(&res.stdout).map_err(AuthorizeError::Json)?;

// TODO consider making a type for this json object
if !blob.is_object() {
Err(AuthorizeError::JsonNotObject)?;
}

ensure!(blob.is_object(), "expected JSON object in response");
ensure!(
blob.get("function").is_some() && blob.get("broadcast").is_some(),
"expected function, fee, and broadcast fields in response"
);
if blob.get("function").is_none()
|| blob.get("broadcast").is_none()
|| blob.get("fee").is_none()
{
Err(AuthorizeError::InvalidJson)?;
}

Ok(blob)
}
Expand Down
Loading