diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fc971af41..028bfc3ab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,12 @@ # UNRELEASED -## Dependencies - -## Fixes - ### fix: correct `dfx sns` example commands in documentation Fixed incorrect commands `dfx sns config create` and `dfx sns config validate` in the `dfx sns` CLI reference examples. The correct commands are `dfx sns create` and `dfx sns validate`. +### fix: Failure to query an asset canister's API version no longer gets misinterpreted as the canister being outdated + ### Motoko Updated Motoko to [1.2.0](https://github.com/dfinity/motoko/releases/tag/1.2.0) diff --git a/src/canisters/frontend/ic-asset/src/canister_api/methods/api_version.rs b/src/canisters/frontend/ic-asset/src/canister_api/methods/api_version.rs index 1c9a139a86..81396992b4 100644 --- a/src/canisters/frontend/ic-asset/src/canister_api/methods/api_version.rs +++ b/src/canisters/frontend/ic-asset/src/canister_api/methods/api_version.rs @@ -1,12 +1,25 @@ use crate::canister_api::methods::method_names::API_VERSION; +use ic_agent::AgentError; use ic_utils::Canister; use ic_utils::call::SyncCall; -pub(crate) async fn api_version(canister: &Canister<'_>) -> u16 { - canister - .query(API_VERSION) - .build() - .call() - .await - .map_or(0, |v: (u16,)| v.0) +const CANISTER_METHOD_NOT_FOUND: &str = "IC0536"; + +fn is_method_not_found(err: &AgentError) -> bool { + match err { + AgentError::CertifiedReject { reject, .. } + | AgentError::UncertifiedReject { reject, .. } => { + reject.error_code.as_deref() == Some(CANISTER_METHOD_NOT_FOUND) + } + _ => false, + } +} + +pub(crate) async fn api_version(canister: &Canister<'_>) -> Result { + match canister.query(API_VERSION).build().call().await { + Ok((version,)) => Ok(version), + // If the canister doesn't have the `api_version` method, it's an old version of the API. + Err(e) if is_method_not_found(&e) => Ok(0), + Err(e) => Err(e), + } } diff --git a/src/canisters/frontend/ic-asset/src/error/prepare_sync_for_proposal.rs b/src/canisters/frontend/ic-asset/src/error/prepare_sync_for_proposal.rs index a22a5dd871..8886cc4488 100644 --- a/src/canisters/frontend/ic-asset/src/error/prepare_sync_for_proposal.rs +++ b/src/canisters/frontend/ic-asset/src/error/prepare_sync_for_proposal.rs @@ -5,6 +5,10 @@ use thiserror::Error; /// Errors related to preparing synchronization operations for a proposal. #[derive(Error, Debug)] pub enum PrepareSyncForProposalError { + /// Failed when querying the asset canister for its API version. + #[error("Failed to query asset canister API version")] + ApiVersionQueryFailed(#[source] AgentError), + /// Failed while requesting that the asset canister compute evidence. #[error("Failed to compute evidence")] ComputeEvidence(#[source] AgentError), diff --git a/src/canisters/frontend/ic-asset/src/error/sync.rs b/src/canisters/frontend/ic-asset/src/error/sync.rs index b93f0d251c..104f7f8b89 100644 --- a/src/canisters/frontend/ic-asset/src/error/sync.rs +++ b/src/canisters/frontend/ic-asset/src/error/sync.rs @@ -6,6 +6,10 @@ use thiserror::Error; /// Errors related to the sync process. #[derive(Error, Debug)] pub enum SyncError { + /// Failed when querying the asset canister for its API version. + #[error("Failed to query asset canister API version")] + ApiVersionQueryFailed(#[source] AgentError), + /// Failed when calling commit_batch #[error("Failed to commit batch")] CommitBatchFailed(#[source] AgentError), diff --git a/src/canisters/frontend/ic-asset/src/error/upload.rs b/src/canisters/frontend/ic-asset/src/error/upload.rs index d9277c483c..f085bdda64 100644 --- a/src/canisters/frontend/ic-asset/src/error/upload.rs +++ b/src/canisters/frontend/ic-asset/src/error/upload.rs @@ -7,6 +7,10 @@ use thiserror::Error; /// Errors encountered during the upload process. #[derive(Error, Debug)] pub enum UploadError { + /// Failed when querying the asset canister for its API version. + #[error("Failed to query asset canister API version")] + ApiVersionQueryFailed(#[source] AgentError), + /// Failed when calling commit_batch. #[error("Commit batch failed")] CommitBatchFailed(#[source] AgentError), diff --git a/src/canisters/frontend/ic-asset/src/sync.rs b/src/canisters/frontend/ic-asset/src/sync.rs index 521719e4a2..76e5b0b95d 100644 --- a/src/canisters/frontend/ic-asset/src/sync.rs +++ b/src/canisters/frontend/ic-asset/src/sync.rs @@ -28,7 +28,7 @@ use crate::error::GatherAssetDescriptorsError::{ }; use crate::error::PrepareSyncForProposalError; use crate::error::SyncError; -use crate::error::SyncError::CommitBatchFailed; +use crate::error::SyncError::{ApiVersionQueryFailed, CommitBatchFailed}; use crate::error::UploadContentError; use crate::error::UploadContentError::{CreateBatchFailed, ListAssetsFailed}; use crate::progress::{AssetSyncProgressRenderer, AssetSyncState}; @@ -155,7 +155,7 @@ pub async fn sync( logger: &Logger, progress: Option<&dyn AssetSyncProgressRenderer>, ) -> Result<(), SyncError> { - let canister_api_version = api_version(canister).await; + let canister_api_version = api_version(canister).await.map_err(ApiVersionQueryFailed)?; let commit_batch_args = upload_content_and_assemble_sync_operations( canister, canister_api_version, @@ -296,7 +296,9 @@ pub async fn prepare_sync_for_proposal( logger: &Logger, progress: Option<&dyn AssetSyncProgressRenderer>, ) -> Result<(Nat, ByteBuf), PrepareSyncForProposalError> { - let canister_api_version = api_version(canister).await; + let canister_api_version = api_version(canister) + .await + .map_err(PrepareSyncForProposalError::ApiVersionQueryFailed)?; let arg = upload_content_and_assemble_sync_operations( canister, canister_api_version, diff --git a/src/canisters/frontend/ic-asset/src/upload.rs b/src/canisters/frontend/ic-asset/src/upload.rs index 2db6654072..e91c637554 100644 --- a/src/canisters/frontend/ic-asset/src/upload.rs +++ b/src/canisters/frontend/ic-asset/src/upload.rs @@ -14,7 +14,9 @@ use crate::canister_api::methods::{ }; use crate::canister_api::types::batch_upload::v0; use crate::error::CompatibilityError::DowngradeV1TOV0Failed; -use crate::error::UploadError::{self, CommitBatchFailed, CreateBatchFailed, ListAssetsFailed}; +use crate::error::UploadError::{ + self, ApiVersionQueryFailed, CommitBatchFailed, CreateBatchFailed, ListAssetsFailed, +}; use ic_utils::Canister; use slog::{Logger, info}; use std::collections::HashMap; @@ -41,7 +43,7 @@ pub async fn upload( info!(logger, "Starting batch."); let batch_id = create_batch(canister).await.map_err(CreateBatchFailed)?; - let canister_api_version = api_version(canister).await; + let canister_api_version = api_version(canister).await.map_err(ApiVersionQueryFailed)?; info!(logger, "Staging contents of new and changed assets:"); @@ -69,7 +71,7 @@ pub async fn upload( .await .map_err(UploadError::AssembleCommitBatchArgumentFailed)?; - let canister_api_version = api_version(canister).await; + let canister_api_version = api_version(canister).await.map_err(ApiVersionQueryFailed)?; info!(logger, "Committing batch."); match canister_api_version { 0 => {