From 00752873022ab0c6b1bda38159d9f738848cda04 Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Wed, 27 Nov 2024 17:20:58 +0100 Subject: [PATCH 1/2] fix(near): handle request timeout (#989) --- .../config/src/client/protocol/near.rs | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/crates/context/config/src/client/protocol/near.rs b/crates/context/config/src/client/protocol/near.rs index 8fa40fca1..6454853c3 100644 --- a/crates/context/config/src/client/protocol/near.rs +++ b/crates/context/config/src/client/protocol/near.rs @@ -4,6 +4,9 @@ use std::{time, vec}; pub use near_crypto::SecretKey; use near_crypto::{InMemorySigner, PublicKey, Signer}; +use near_jsonrpc_client::errors::{ + JsonRpcError, JsonRpcServerError, JsonRpcServerResponseStatusError, +}; use near_jsonrpc_client::methods::query::{RpcQueryRequest, RpcQueryResponse}; use near_jsonrpc_client::methods::send_tx::RpcSendTransactionRequest; use near_jsonrpc_client::methods::tx::RpcTransactionStatusRequest; @@ -298,12 +301,24 @@ impl Network { match response { Ok(response) => break response, Err(err) => { - let Some(RpcTransactionError::TimeoutError) = err.handler_error() else { - return Err(NearError::Custom { - operation: ErrorOperation::Mutate, - reason: err.to_string(), - }); - }; + #[expect( + clippy::wildcard_enum_match_arm, + reason = "quite terse, these variants" + )] + match err { + JsonRpcError::ServerError( + JsonRpcServerError::ResponseStatusError( + JsonRpcServerResponseStatusError::TimeoutError, + ) + | JsonRpcServerError::HandlerError(RpcTransactionError::TimeoutError), + ) => {} + _ => { + return Err(NearError::Custom { + operation: ErrorOperation::Mutate, + reason: err.to_string(), + }); + } + } if sent_at.elapsed().as_secs() > 60 { return Err(NearError::TransactionTimeout); From 31d56aaeef5a7093ea0fb01366b22cf2a8082a38 Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Wed, 27 Nov 2024 17:23:02 +0100 Subject: [PATCH 2/2] feat: nuke proxy when erasing context config (#990) --- contracts/context-config/src/sys.rs | 12 ++++++++++-- contracts/proxy-lib/src/lib.rs | 1 - contracts/proxy-lib/src/mutate.rs | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/contracts/context-config/src/sys.rs b/contracts/context-config/src/sys.rs index 00fb9121f..e59b2e1da 100644 --- a/contracts/context-config/src/sys.rs +++ b/contracts/context-config/src/sys.rs @@ -5,7 +5,7 @@ use calimero_context_config::repr::Repr; use calimero_context_config::types::{Application, ContextId, ContextIdentity, SignerId}; use calimero_context_config::{SystemRequest, Timestamp}; use near_sdk::store::{IterableMap, IterableSet}; -use near_sdk::{env, near}; +use near_sdk::{env, near, Gas, NearToken, Promise}; use crate::{parse_input, Config, ContextConfigs, ContextConfigsExt}; @@ -36,9 +36,17 @@ impl ContextConfigs { for (_, context) in self.contexts.drain() { let _ignored = context.application.into_inner(); context.members.into_inner().clear(); - let _ignored = context.proxy.into_inner(); + let proxy = context.proxy.into_inner(); + + let _is_sent_on_drop = Promise::new(proxy).function_call( + "nuke".to_owned(), + vec![], + NearToken::default(), + Gas::from_tgas(1), + ); } + self.next_proxy_id = 0; self.proxy_code.set(None); env::log_str(&format!( diff --git a/contracts/proxy-lib/src/lib.rs b/contracts/proxy-lib/src/lib.rs index 1207cfc28..7425d2783 100644 --- a/contracts/proxy-lib/src/lib.rs +++ b/contracts/proxy-lib/src/lib.rs @@ -102,7 +102,6 @@ impl ProxyContract { &self, proposal_id: Repr, ) -> Option>> { - let approvals_for_proposal = self.approvals.get(&proposal_id); let approvals = self.approvals.get(&proposal_id)?; Some(approvals.iter().flat_map(|a| a.rt()).collect()) } diff --git a/contracts/proxy-lib/src/mutate.rs b/contracts/proxy-lib/src/mutate.rs index ae415a974..8aec79d60 100644 --- a/contracts/proxy-lib/src/mutate.rs +++ b/contracts/proxy-lib/src/mutate.rs @@ -40,6 +40,7 @@ impl ProxyContract { } } } + #[near] impl ProxyContract { #[private] @@ -226,6 +227,26 @@ impl ProxyContract { ) } + fn erase(&mut self) { + // if this is going to be exposed, it should be a proposal + self.proposals.clear(); + self.approvals.clear(); + self.num_proposals_pk.clear(); + self.context_storage.clear(); + } + + pub fn nuke(&mut self) -> Promise { + require!( + env::predecessor_account_id() == self.context_config_account_id, + "Only the context config contract can nuke the proxy" + ); + + self.erase(); + + Promise::new(env::current_account_id()) + .delete_account(self.context_config_account_id.clone()) + } + #[private] pub fn update_contract_callback( &mut self,