Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
303 changes: 153 additions & 150 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,16 @@ snops-common = { path = "./crates/common" }

## Comment to use version-pinned or local dependencies

snarkos-account = { git = "https://github.com/ProvableHQ/snarkOS", rev = "a1e4a28" }
snarkos-node = { git = "https://github.com/ProvableHQ/snarkOS", rev = "a1e4a28" }
snarkos-node-metrics = { git = "https://github.com/ProvableHQ/snarkOS", rev = "a1e4a28" }
snarkos-account = { git = "https://github.com/ProvableHQ/snarkOS", rev = "c7390bd" }
snarkos-node = { git = "https://github.com/ProvableHQ/snarkOS", rev = "c7390bd" }
snarkos-node-metrics = { git = "https://github.com/ProvableHQ/snarkOS", rev = "c7390bd" }
[workspace.dependencies.snarkvm]
## The following anchors are used by the `update_snarkos_dep.sh` script.
## Everything in-between the anchors is copied from the snarkos Cargo.toml
## CODEGEN_START
#path = "../snarkVM"
git = "https://github.com/ProvableHQ/snarkVM.git"
rev = "a296d35"
#version = "=1.4.0"
rev = "629cccc"
version = "=1.6.0"
## CODEGEN_END
features = ["rocks"]
5 changes: 4 additions & 1 deletion crates/agent/src/reconcile/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,11 @@ impl Reconcile<(), ReconcileError> for AgentStateReconciler {

let rec = if node_status.is_started() {
ReconcileStatus::default()
} else {
} else if node_status.is_stopped() {
// Terminate looping after some kind of failure
ReconcileStatus::empty()
} else {
ReconcileStatus::empty().requeue_after(Duration::from_secs(5))
};

return Ok(rec.add_scope(format!("agent_state/node/{}", node_status.label())));
Expand Down
2 changes: 1 addition & 1 deletion crates/aot/src/auth/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl<N: Network> From<ProxyAuthorization<N>> for Authorization<N> {
fn from(auth: ProxyAuthorization<N>) -> Self {
let new_auth = Authorization::try_from((vec![], vec![])).unwrap();
for req in auth.requests {
new_auth.push(req);
let _ = new_auth.push(req);
}
for transition in auth.transitions {
let _ = new_auth.insert_transition(transition);
Expand Down
5 changes: 3 additions & 2 deletions crates/aot/src/ledger/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use anyhow::bail;
use rand::{SeedableRng, thread_rng};
use rand_chacha::ChaChaRng;
use snarkvm::{
algorithms::snark::varuna::VarunaVersion,
circuit::Aleo,
console::{
account::{PrivateKey, ViewKey},
Expand Down Expand Up @@ -43,7 +44,7 @@ pub fn prove_credits<N: Network, C: ConsensusStorage<N>, A: Aleo<Network = N>>(
// assemble the proof
let (_, mut trace) = vm.process().read().execute::<A, _>(auth, rng)?;
trace.prepare(Query::from(vm.block_store()).clone())?;
trace.prove_execution::<A, _>(&format!("credits.aleo/{locator}"), rng)
trace.prove_execution::<A, _>(&format!("credits.aleo/{locator}"), VarunaVersion::V1, rng)
}

pub fn prove_fee<N: Network, C: ConsensusStorage<N>, A: Aleo<Network = N>>(
Expand All @@ -60,7 +61,7 @@ pub fn prove_fee<N: Network, C: ConsensusStorage<N>, A: Aleo<Network = N>>(
// assemble the proof
let (_, mut trace) = vm.process().read().execute::<A, _>(auth, rng)?;
trace.prepare(Query::from(vm.block_store()).clone())?;
trace.prove_fee::<A, _>(rng)
trace.prove_fee::<A, _>(VarunaVersion::V1, rng)
}

pub fn public_transaction<N: Network, C: ConsensusStorage<N>, A: Aleo<Network = N>>(
Expand Down
7 changes: 7 additions & 0 deletions crates/common/src/state/snarkos_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ impl SnarkOSStatus {
matches!(self, SnarkOSStatus::Started)
}

pub fn is_stopped(&self) -> bool {
matches!(
self,
SnarkOSStatus::Halted(_) | SnarkOSStatus::LedgerFailure(_)
)
}

pub fn label(&self) -> &'static str {
match self {
SnarkOSStatus::Starting => "starting",
Expand Down
2 changes: 2 additions & 0 deletions crates/controlplane/src/cannon/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub enum SourceError {
CouldNotSelect(&'static str),
#[error("error fetching state root from `{0}`: {1}")]
FailedToGetStateRoot(String, #[source] reqwest::Error),
#[error("error fetching latest height from `{0}`: {1}")]
FailedToGetHeight(String, #[source] reqwest::Error),
#[error("error jsonifying `{0}`: {1}")]
Json(&'static str, #[source] serde_json::Error),
#[error("no agents available to execute `{0}`")]
Expand Down
30 changes: 30 additions & 0 deletions crates/controlplane/src/cannon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,36 @@ impl CannonInstance {
}
}

/// Called by axum to forward /cannon/<id>/<network>/block/height/latest
pub async fn proxy_latest_height(&self) -> Result<u32, CannonError> {
let cannon_id = self.id;
let env_id = self.env_id;
let network = self.network;

match &self.source.query {
QueryTarget::Local(qs) => {
if let Some(port) = self.query_port {
qs.get_latest_height(network, port).await
} else {
Err(CannonInstanceError::MissingQueryPort(cannon_id).into())
}
}
QueryTarget::Node(target) => {
// shortcut to cached state root if the target is all nodes
if target.is_all() {
if let Some(info) = self.global_state.get_env_block_info(env_id) {
return Ok(info.height);
}
}

Ok(self
.global_state
.snarkos_get::<u32>(env_id, "/block/height/latest", target)
.await?)
}
}
}

/// Called by axum to forward /cannon/<id>/<network>/transaction/broadcast
/// to the desired sink
pub fn proxy_broadcast(
Expand Down
46 changes: 46 additions & 0 deletions crates/controlplane/src/cannon/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub(crate) fn redirect_cannon_routes() -> Router<AppState> {
"/:cannon/:network/find/blockHash/:tx",
get(get_tx_blockhash),
)
.route(
"/:cannon/:network/block/height/latest",
get(get_latest_height),
)
.route("/:cannon/:network/block/:height_or_hash", get(get_block))
.route("/:cannon/:network/program/:program", get(get_program_json))
.route(
Expand Down Expand Up @@ -84,6 +88,48 @@ async fn state_root(
}
}

async fn get_latest_height(
Path((env_id, cannon_id, network)): Path<(String, String, NetworkId)>,
state: State<AppState>,
) -> Response {
let (Some(env_id), Some(cannon_id)) = (id_or_none(&env_id), id_or_none(&cannon_id)) else {
return ServerError::NotFound("unknown cannon or environment".to_owned()).into_response();
};

let Some(env) = state.get_env(env_id) else {
return ServerError::NotFound("environment not found".to_owned()).into_response();
};

if env.network != network {
return ServerError::NotFound("network mismatch".to_owned()).into_response();
}

let Some(cannon) = env.get_cannon(cannon_id) else {
return ServerError::NotFound("cannon not found".to_owned()).into_response();
};

// TODO: lock this with a mutex or something so that multiple route callers
// can't bombard the cannon with proxy_state_root call attempts
let mut attempts = 0;
loop {
attempts += 1;
match cannon.proxy_latest_height().await {
Ok(height) => break Json(height).into_response(),

Err(e) if attempts > 5 => {
break (
StatusCode::REQUEST_TIMEOUT,
Json(json!({ "error": "non-responsive query node", "inner": format!("{e}") })),
)
.into_response();
}

_ => attempts += 1,
}
tokio::time::sleep(Duration::from_secs(1)).await;
}
}

async fn get_program_json(
Path((env_id, cannon_id, network, program)): Path<(String, String, NetworkId, String)>,
state: State<AppState>,
Expand Down
20 changes: 19 additions & 1 deletion crates/controlplane/src/cannon/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,25 @@ impl LocalService {
network: NetworkId,
port: u16,
) -> Result<String, CannonError> {
let url = format!("http://127.0.0.1:{port}/{network}/latest/stateRoot");
let url = format!("http://127.0.0.1:{port}/{network}/stateRoot/latest");
let response = reqwest::get(&url)
.await
.map_err(|e| SourceError::FailedToGetStateRoot(url, e))?;
Ok(response
.json()
.await
.map_err(SourceError::StateRootInvalidJson)?)
}

// TODO: cache this when sync_from is false
/// Fetch the state root from the local query service
/// (non-cached)
pub async fn get_latest_height(
&self,
network: NetworkId,
port: u16,
) -> Result<u32, CannonError> {
let url = format!("http://127.0.0.1:{port}/{network}/block/height/latest");
let response = reqwest::get(&url)
.await
.map_err(|e| SourceError::FailedToGetStateRoot(url, e))?;
Expand Down
Loading