From 945be8fca64354b4761471e94a4eaa6ecf943732 Mon Sep 17 00:00:00 2001 From: Fran Domovic Date: Fri, 20 Dec 2024 14:45:49 +0100 Subject: [PATCH 01/27] fix: remove timestamp from contracts --- contracts/icp/context-config/src/mutate.rs | 10 -- .../icp/context-config/tests/integration.rs | 136 +----------------- contracts/icp/context-proxy/src/query.rs | 1 - .../icp/context-proxy/tests/integration.rs | 16 --- contracts/near/context-config/src/mutate.rs | 6 - crates/context/config/src/icp.rs | 2 - crates/context/config/src/icp/types.rs | 6 - 7 files changed, 1 insertion(+), 176 deletions(-) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 910017621..10f8357ca 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -21,16 +21,6 @@ pub async fn mutate(signed_request: ICSigned) -> Result<(), String> { .parse(|r| *r.signer_id) .map_err(|e| format!("Failed to verify signature: {}", e))?; - // Add debug logging - let current_time = ic_cdk::api::time() / 1_000_000; - let time_diff = current_time.saturating_sub(request.timestamp_ms); - if time_diff > 1000 * 5 { - return Err(format!( - "request expired: diff={}ms, current={}, request={}", - time_diff, current_time, request.timestamp_ms - )); - } - match request.kind { ICRequestKind::Context(ICContextRequest { context_id, kind }) => match kind { ICContextRequestKind::Add { diff --git a/contracts/icp/context-config/tests/integration.rs b/contracts/icp/context-config/tests/integration.rs index 4aee2827d..dbd7f5134 100644 --- a/contracts/icp/context-config/tests/integration.rs +++ b/contracts/icp/context-config/tests/integration.rs @@ -1,5 +1,3 @@ -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ ICApplication, ICCapability, ICContextRequest, ICContextRequestKind, ICRequest, ICRequestKind, @@ -43,13 +41,6 @@ fn create_signed_request(signer_key: &SigningKey, request: ICRequest) -> ICSigne ICSigned::new(request, |bytes| signer_key.sign(bytes)).expect("Failed to create signed request") } -fn get_time_nanos(pic: &PocketIc) -> u64 { - pic.get_time() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos() as u64 -} - fn handle_response( response: Result, expected_success: bool, @@ -87,13 +78,6 @@ fn test_proxy_management() { let (pic, canister) = setup(); let mut rng = rand::thread_rng(); - // Advance IC time - let current_nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() as u64; - pic.advance_time(Duration::from_nanos(current_nanos)); - // Create test identities let context_sk = SigningKey::from_bytes(&rng.gen()); let context_pk = context_sk.verifying_key(); @@ -119,7 +103,6 @@ fn test_proxy_management() { }, }), signer_id: context_id.rt().expect("infallible conversion"), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -141,7 +124,6 @@ fn test_proxy_management() { kind: ICContextRequestKind::UpdateProxyContract, }), signer_id: bob_pk.rt().expect("infallible conversion"), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -161,7 +143,6 @@ fn test_proxy_management() { kind: ICContextRequestKind::UpdateProxyContract, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -180,22 +161,12 @@ fn test_mutate_success_cases() { let (pic, canister) = setup(); let mut rng = rand::thread_rng(); - // Advance IC time to current time - let current_nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() as u64; - pic.advance_time(Duration::from_nanos(current_nanos)); - // Create context keys and ID let context_sk = SigningKey::from_bytes(&rng.gen()); let context_pk = context_sk.verifying_key(); let context_id = context_pk.rt().expect("infallible conversion"); - // Get current IC time in nanoseconds - let current_time = get_time_nanos(&pic); - - // Create the request with IC time in nanoseconds + // Create the request let request = ICRequest { kind: ICRequestKind::Context(ICContextRequest { context_id, @@ -211,7 +182,6 @@ fn test_mutate_success_cases() { }, }), signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: current_time, nonce: 0, }; @@ -230,13 +200,6 @@ fn test_member_management() { let (pic, canister) = setup(); let mut rng = rand::thread_rng(); - // Advance IC time - let current_nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() as u64; - pic.advance_time(Duration::from_nanos(current_nanos)); - // Create test identities let context_sk = SigningKey::from_bytes(&rng.gen()); let context_pk = context_sk.verifying_key(); @@ -266,7 +229,6 @@ fn test_member_management() { }, }), signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -288,7 +250,6 @@ fn test_member_management() { }, }), signer_id: (alice_pk.rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -333,7 +294,6 @@ fn test_member_management() { }, }), signer_id: (alice_pk.rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -372,13 +332,6 @@ fn test_capability_management() { let (pic, canister) = setup(); let mut rng = rand::thread_rng(); - // Advance IC time - let current_nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() as u64; - pic.advance_time(Duration::from_nanos(current_nanos)); - // Create test identities let context_sk = SigningKey::from_bytes(&rng.gen()); let context_pk = context_sk.verifying_key(); @@ -408,7 +361,6 @@ fn test_capability_management() { }, }), signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -430,7 +382,6 @@ fn test_capability_management() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -452,7 +403,6 @@ fn test_capability_management() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -494,7 +444,6 @@ fn test_capability_management() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -530,13 +479,6 @@ fn test_application_update() { let (pic, canister) = setup(); let mut rng = rand::thread_rng(); - // Advance IC time - let current_nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() as u64; - pic.advance_time(Duration::from_nanos(current_nanos)); - // Create test identities let context_sk = SigningKey::from_bytes(&rng.gen()); let context_pk = context_sk.verifying_key(); @@ -570,7 +512,6 @@ fn test_application_update() { }, }), signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -628,7 +569,6 @@ fn test_application_update() { }, }), signer_id: (bob_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -681,7 +621,6 @@ fn test_application_update() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -751,7 +690,6 @@ fn test_edge_cases() { }, }), signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -771,7 +709,6 @@ fn test_edge_cases() { kind: ICContextRequestKind::AddMembers { members: vec![] }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -794,7 +731,6 @@ fn test_edge_cases() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -825,73 +761,6 @@ fn test_edge_cases() { } } -#[ignore = "we're deprecating timestamp checks, in favor of nonce checks"] -#[test] -fn test_timestamp_scenarios() { - let (pic, canister) = setup(); - let mut rng = rand::thread_rng(); - - // Setup initial context - let context_sk = SigningKey::from_bytes(&rng.gen()); - let context_pk = context_sk.verifying_key(); - let context_id = context_pk.to_bytes().rt().expect("infallible conversion"); - let alice_sk = SigningKey::from_bytes(&rng.gen()); - let alice_pk = alice_sk.verifying_key(); - let alice_id = alice_pk.to_bytes().rt().expect("infallible conversion"); - - // Create initial context with current timestamp - let current_time = get_time_nanos(&pic); - let create_request = ICRequest { - kind: ICRequestKind::Context(ICContextRequest { - context_id, - kind: ICContextRequestKind::Add { - author_id: alice_id, - application: ICApplication { - id: rng.gen::<[_; 32]>().rt().expect("infallible conversion"), - blob: rng.gen::<[_; 32]>().rt().expect("infallible conversion"), - size: 0, - source: String::new(), - metadata: vec![], - }, - }, - }), - signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: current_time, - nonce: 0, - }; - - let signed_request = create_signed_request(&context_sk, create_request); - let response = pic.update_call( - canister, - Principal::anonymous(), - "mutate", - candid::encode_one(signed_request).unwrap(), - ); - handle_response(response, true, "Context creation"); - - // Try with expired timestamp (more than 5 seconds old) - let expired_request = ICRequest { - kind: ICRequestKind::Context(ICContextRequest { - context_id, - kind: ICContextRequestKind::AddMembers { - members: vec![rng.gen::<[_; 32]>().rt().expect("infallible conversion")], - }, - }), - signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: current_time - 6_000_000_000, // 6 seconds ago - nonce: 0, - }; - - let signed_request = create_signed_request(&alice_sk, expired_request); - let response = pic.update_call( - canister, - Principal::anonymous(), - "mutate", - candid::encode_one(signed_request).unwrap(), - ); - handle_response(response, false, "Expired timestamp request"); -} - #[test] fn test_concurrent_operations() { let (pic, canister) = setup(); @@ -921,7 +790,6 @@ fn test_concurrent_operations() { }, }), signer_id: (context_id.as_bytes().rt().expect("infallible conversion")), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -935,7 +803,6 @@ fn test_concurrent_operations() { .expect("Context creation should succeed"); // Create multiple member additions with same timestamp - let timestamp = get_time_nanos(&pic); let mut requests = Vec::new(); for _ in 0..3 { let new_member = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -947,7 +814,6 @@ fn test_concurrent_operations() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - timestamp_ms: timestamp, nonce: 0, }; requests.push(create_signed_request(&alice_sk, request)); diff --git a/contracts/icp/context-proxy/src/query.rs b/contracts/icp/context-proxy/src/query.rs index eb644b9b9..ff2c36912 100644 --- a/contracts/icp/context-proxy/src/query.rs +++ b/contracts/icp/context-proxy/src/query.rs @@ -72,7 +72,6 @@ pub fn get_proposal_approvals_with_signer( .map(|signer_id| ICProposalApprovalWithSigner { proposal_id: proposal_id.clone(), signer_id: signer_id.clone(), - added_timestamp: 0, // TODO: We need to store approval timestamps }) .collect() } else { diff --git a/contracts/icp/context-proxy/tests/integration.rs b/contracts/icp/context-proxy/tests/integration.rs index d7f74f21d..0f553b3a3 100644 --- a/contracts/icp/context-proxy/tests/integration.rs +++ b/contracts/icp/context-proxy/tests/integration.rs @@ -1,5 +1,4 @@ use std::cell::RefCell; -use std::time::UNIX_EPOCH; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ @@ -37,13 +36,6 @@ fn create_signed_context_request( ICSigned::new(request, |bytes| signer_key.sign(bytes)).expect("Failed to create signed request") } -fn get_time_nanos(pic: &PocketIc) -> u64 { - pic.get_time() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos() as u64 -} - // Helper function to create a proposal and verify response fn create_and_verify_proposal( pic: &PocketIc, @@ -196,7 +188,6 @@ fn create_context_with_proxy( }, }), signer_id: context_id.rt().expect("infallible conversion"), - timestamp_ms: get_time_nanos(pic), nonce: 0, }; @@ -254,7 +245,6 @@ fn add_members_to_context( kind: ICContextRequestKind::AddMembers { members }, }), signer_id: author_pk.rt().expect("infallible conversion"), - timestamp_ms: get_time_nanos(pic), nonce: 0, }; @@ -346,7 +336,6 @@ fn test_update_proxy_contract() { kind: ICContextRequestKind::UpdateProxyContract, }), signer_id: author_pk.rt().expect("infallible conversion"), - timestamp_ms: get_time_nanos(&pic), nonce: 0, }; @@ -639,7 +628,6 @@ fn test_approve_own_proposal() { let approval = ICProposalApprovalWithSigner { signer_id: author_id, proposal_id, - added_timestamp: get_time_nanos(&pic), }; let request = ICProxyMutateRequest::Approve { approval }; @@ -683,7 +671,6 @@ fn test_approve_non_existent_proposal() { let approval = ICProposalApprovalWithSigner { signer_id, proposal_id, - added_timestamp: get_time_nanos(&pic), }; let request = ICProxyMutateRequest::Approve { approval }; @@ -878,7 +865,6 @@ fn test_proposal_execution_transfer() { let approval = ICProposalApprovalWithSigner { signer_id, proposal_id, - added_timestamp: get_time_nanos(&pic), }; let request = ICProxyMutateRequest::Approve { approval }; @@ -1023,7 +1009,6 @@ fn test_proposal_execution_external_call() { let approval = ICProposalApprovalWithSigner { signer_id, proposal_id, - added_timestamp: get_time_nanos(&pic), }; let request = ICProxyMutateRequest::Approve { approval }; @@ -1164,7 +1149,6 @@ fn test_proposal_execution_external_call_with_deposit() { let approval = ICProposalApprovalWithSigner { signer_id, proposal_id, - added_timestamp: get_time_nanos(&pic), }; let request = ICProxyMutateRequest::Approve { approval }; diff --git a/contracts/near/context-config/src/mutate.rs b/contracts/near/context-config/src/mutate.rs index b84845479..07476002b 100644 --- a/contracts/near/context-config/src/mutate.rs +++ b/contracts/near/context-config/src/mutate.rs @@ -23,12 +23,6 @@ impl ContextConfigs { .parse(|i| *i.signer_id) .expect("failed to parse input"); - require!( - env::block_timestamp_ms().saturating_sub(request.timestamp_ms) - <= self.config.validity_threshold_ms, - "request expired" - ); - match request.kind { RequestKind::Context(ContextRequest { context_id, kind, .. diff --git a/crates/context/config/src/icp.rs b/crates/context/config/src/icp.rs index 0fc859c98..25b5b948a 100644 --- a/crates/context/config/src/icp.rs +++ b/crates/context/config/src/icp.rs @@ -161,7 +161,6 @@ impl From for ProposalWithApprovals { pub struct ICProposalApprovalWithSigner { pub proposal_id: ICRepr, pub signer_id: ICRepr, - pub added_timestamp: u64, } #[derive(CandidType, Deserialize, Clone, Debug)] @@ -194,7 +193,6 @@ impl TryFrom for ICProxyMutateRequest { approval: ICProposalApprovalWithSigner { proposal_id: approval.proposal_id.rt().map_err(|e| e.to_string())?, signer_id: approval.signer_id.rt().map_err(|e| e.to_string())?, - added_timestamp: approval.added_timestamp, }, }, }; diff --git a/crates/context/config/src/icp/types.rs b/crates/context/config/src/icp/types.rs index 41749f698..935dc6c0f 100644 --- a/crates/context/config/src/icp/types.rs +++ b/crates/context/config/src/icp/types.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::marker::PhantomData; -use std::time::{SystemTime, UNIX_EPOCH}; use candid::CandidType; use ed25519_dalek::{Verifier, VerifyingKey}; @@ -160,7 +159,6 @@ impl<'a> From> for ICRequestKind { pub struct ICRequest { pub kind: ICRequestKind, pub signer_id: ICRepr, - pub timestamp_ms: u64, pub nonce: u64, } @@ -169,10 +167,6 @@ impl ICRequest { Self { signer_id: ICRepr::new(signer_id), kind, - timestamp_ms: SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_millis() as u64, nonce, } } From bbd07ee3de9d19e3888064522f7c04eb70f1fc00 Mon Sep 17 00:00:00 2001 From: Fran Domovic Date: Fri, 20 Dec 2024 15:17:09 +0100 Subject: [PATCH 02/27] fix: tests 2 --- .../near/context-config/tests/sandbox.rs | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/contracts/near/context-config/tests/sandbox.rs b/contracts/near/context-config/tests/sandbox.rs index e8a734db1..73f9112ee 100644 --- a/contracts/near/context-config/tests/sandbox.rs +++ b/contracts/near/context-config/tests/sandbox.rs @@ -823,45 +823,6 @@ async fn main() -> eyre::Result<()> { assert_eq!(res.logs(), ["Set validity threshold to `5s`"]); - let req = node1.call(contract.id(), "mutate").args_json(Signed::new( - &{ - let kind = RequestKind::Context(ContextRequest::new( - context_id, - ContextRequestKind::RemoveMembers { - members: vec![carol_cx_id].into(), - }, - )); - - Request::new( - alice_cx_id.rt()?, - kind, - *nonces.get(&Member::Alice).unwrap(), - ) - }, - |p| alice_cx_sk.sign(p), - )?); - - assert_eq!( - fetch_nonce(&contract, context_id, alice_cx_id) - .await? - .unwrap(), - 4, - "Alice: Nonce should be 4 after request reverted - expired" - ); - - time::sleep(time::Duration::from_secs(5)).await; - - let res = req - .transact() - .await? - .raw_bytes() - .expect_err("request should've expired"); - - { - let err = res.to_string(); - assert!(err.contains("request expired"), "{}", err); - } - let res: Vec> = contract .view("members") .args_json(json!({ From 964fa46321c95e21dffb1269c8d63c357acaf59d Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 15:40:42 +0100 Subject: [PATCH 03/27] fix: removed prints in mock contract, optimized proxy contract deployment, added tracking cycle spending in proxy tests --- contracts/icp/context-config/src/mutate.rs | 2 +- .../icp/context-proxy/mock/ledger/src/lib.rs | 12 +- .../icp/context-proxy/tests/integration.rs | 130 +++++++++++++++++- 3 files changed, 132 insertions(+), 12 deletions(-) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 10f8357ca..4971ad6d7 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -106,7 +106,7 @@ async fn deploy_proxy_contract(context_id: ICRepr) -> Result; #[ic_cdk::update] fn transfer(args: TransferArgs) -> TransferResult { - ic_cdk::println!( - "Mock ledger received transfer: to={:?}, amount={}", - args.to, - args.amount - ); + // ic_cdk::println!( + // "Mock ledger received transfer: to={:?}, amount={}", + // args.to, + // args.amount + // ); // Verify fee if args.fee.e8s() != 10_000 { @@ -40,7 +40,7 @@ fn transfer(args: TransferArgs) -> TransferResult { *bal = bal.saturating_sub(amount_e8s); *bal = bal.saturating_sub(args.fee.e8s()); - ic_cdk::println!("New balance: {}", *bal); + // ic_cdk::println!("New balance: {}", *bal); // Return mock block index Ok(1) diff --git a/contracts/icp/context-proxy/tests/integration.rs b/contracts/icp/context-proxy/tests/integration.rs index 0f553b3a3..19bc71571 100644 --- a/contracts/icp/context-proxy/tests/integration.rs +++ b/contracts/icp/context-proxy/tests/integration.rs @@ -163,6 +163,9 @@ fn create_context_with_proxy( ) -> Result<(Principal, ICRepr), String> { let mut rng = rand::thread_rng(); + // Get initial cycle balance + let initial_cycle_balance = pic.cycle_balance(context_canister); + // Generate context ID let context_sk = SigningKey::from_bytes(&rng.gen()); let context_pk = context_sk.verifying_key(); @@ -218,7 +221,7 @@ fn create_context_with_proxy( candid::encode_one(context_id).unwrap(), ); - match query_response { + let result = match query_response { Ok(WasmResult::Reply(bytes)) => { let proxy_canister: Principal = candid::decode_one(&bytes) .map_err(|e| format!("Failed to decode proxy canister ID: {}", e))?; @@ -226,7 +229,14 @@ fn create_context_with_proxy( } Ok(WasmResult::Reject(msg)) => Err(format!("Query rejected: {}", msg)), Err(e) => Err(format!("Query failed: {}", e)), - } + }; + + // Get final cycle balance and calculate usage + let final_cycle_balance = pic.cycle_balance(context_canister); + let cycles_used = initial_cycle_balance - final_cycle_balance; + println!("Cycles used in create_context_with_proxy: {}", cycles_used); + + result } // Helper function to add members to context @@ -392,6 +402,9 @@ fn test_create_proposal_transfer() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -407,6 +420,11 @@ fn test_create_proposal_transfer() { create_and_verify_proposal(&pic, proxy_canister, &author_sk, proposal) .expect("Transfer proposal creation should succeed"); + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -420,6 +438,9 @@ fn test_create_proposal_external_call() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -437,6 +458,11 @@ fn test_create_proposal_external_call() { create_and_verify_proposal(&pic, proxy_canister, &author_sk, proposal) .expect("External call proposal creation should succeed"); + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -450,6 +476,9 @@ fn test_create_proposal_set_context() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -465,6 +494,11 @@ fn test_create_proposal_set_context() { create_and_verify_proposal(&pic, proxy_canister, &author_sk, proposal) .expect("Setting context value should succeed"); + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -478,6 +512,9 @@ fn test_create_proposal_multiple_actions() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -495,6 +532,11 @@ fn test_create_proposal_multiple_actions() { create_and_verify_proposal(&pic, proxy_canister, &author_sk, proposal) .expect("Multiple actions proposal creation should succeed"); + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -508,6 +550,9 @@ fn test_create_proposal_invalid_transfer_amount() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -547,6 +592,11 @@ fn test_create_proposal_invalid_transfer_amount() { panic!("Failed to call canister: {}", err); } } + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -560,6 +610,9 @@ fn test_create_proposal_invalid_method_name() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -598,6 +651,11 @@ fn test_create_proposal_invalid_method_name() { panic!("Failed to call canister: {}", err); } } + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -611,6 +669,9 @@ fn test_approve_own_proposal() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -651,6 +712,11 @@ fn test_approve_own_proposal() { } _ => panic!("Unexpected response type"), } + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -664,6 +730,9 @@ fn test_approve_non_existent_proposal() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let signer_pk = signer_sk.verifying_key(); let signer_id = signer_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -694,6 +763,11 @@ fn test_approve_non_existent_proposal() { } _ => panic!("Unexpected response type"), } + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -707,6 +781,9 @@ fn test_create_proposal_empty_actions() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); @@ -739,6 +816,11 @@ fn test_create_proposal_empty_actions() { } _ => panic!("Unexpected response type"), } + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -752,6 +834,9 @@ fn test_create_proposal_exceeds_limit() { .. } = setup(); + // Get initial cycle balance + let initial_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); @@ -798,6 +883,11 @@ fn test_create_proposal_exceeds_limit() { } _ => panic!("Unexpected response type"), } + + // Get new cycle balance and calculate usage + let new_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_balance - new_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -815,7 +905,9 @@ fn test_proposal_execution_transfer() { .. } = setup(); - let initial_balance = MOCK_LEDGER_BALANCE.with(|b| *b.borrow()); + // Get initial cycle balance + let initial_cycle_balance = pic.cycle_balance(proxy_canister); + let initial_ledger_balance = MOCK_LEDGER_BALANCE.with(|b| *b.borrow()); // Setup signers let author_pk = author_sk.verifying_key(); @@ -833,7 +925,6 @@ fn test_proposal_execution_transfer() { let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); - // let receiver_id = Principal::from_text("bnz7o-iuaaa-aaaaa-qaaaa-cai").unwrap(); // Create transfer proposal let proposal = ICProposal { id: proposal_id, @@ -938,7 +1029,7 @@ fn test_proposal_execution_transfer() { // Verify the transfer was executed assert_eq!( final_balance, - initial_balance + initial_ledger_balance .saturating_sub(transfer_amount as u64) .saturating_sub(10_000), // Subtract both transfer amount and fee "Transfer amount should be deducted from ledger balance" @@ -946,6 +1037,11 @@ fn test_proposal_execution_transfer() { } _ => panic!("Unexpected response type"), } + + // Get final cycle balance and calculate usage + let final_cycle_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_cycle_balance - final_cycle_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -962,6 +1058,9 @@ fn test_proposal_execution_external_call() { .. } = setup(); + // Get initial cycle balance + let initial_cycle_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); @@ -1084,6 +1183,11 @@ fn test_proposal_execution_external_call() { } _ => panic!("Unexpected response type"), } + + // Get final cycle balance and calculate usage + let final_cycle_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_cycle_balance - final_cycle_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -1101,6 +1205,9 @@ fn test_proposal_execution_external_call_with_deposit() { .. } = setup(); + // Get initial cycle balance + let initial_cycle_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); @@ -1245,6 +1352,11 @@ fn test_proposal_execution_external_call_with_deposit() { } _ => panic!("Unexpected response type"), } + + // Get final cycle balance and calculate usage + let final_cycle_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_cycle_balance - final_cycle_balance; + println!("Cycles used: {}", cycles_used); } #[test] @@ -1258,6 +1370,9 @@ fn test_delete_proposal() { .. } = setup(); + // Get initial cycle balance + let initial_cycle_balance = pic.cycle_balance(proxy_canister); + let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); @@ -1318,4 +1433,9 @@ fn test_delete_proposal() { } WasmResult::Reject(msg) => panic!("Query rejected: {}", msg), } + + // Get final cycle balance and calculate usage + let final_cycle_balance = pic.cycle_balance(proxy_canister); + let cycles_used = initial_cycle_balance - final_cycle_balance; + println!("Cycles used: {}", cycles_used); } From 9bbc038a70261bd7f829eb0ee95287352e0d13cf Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 16:34:21 +0100 Subject: [PATCH 04/27] feat: introduced nonces in icp context contract --- .../res/calimero_context_config_icp.did | 1 + contracts/icp/context-config/src/lib.rs | 1 + contracts/icp/context-config/src/mutate.rs | 70 +++++++--- contracts/icp/context-config/src/query.rs | 14 ++ .../icp/context-config/tests/integration.rs | 120 +++++++++++++++++- 5 files changed, 185 insertions(+), 21 deletions(-) diff --git a/contracts/icp/context-config/res/calimero_context_config_icp.did b/contracts/icp/context-config/res/calimero_context_config_icp.did index 51f18aa22..6d536a811 100644 --- a/contracts/icp/context-config/res/calimero_context_config_icp.did +++ b/contracts/icp/context-config/res/calimero_context_config_icp.did @@ -11,6 +11,7 @@ type Result = variant { Ok; Err : text }; service : () -> { application : (blob) -> (ICApplication) query; application_revision : (blob) -> (nat64) query; + fetch_nonce : (blob, blob) -> (opt nat64) query; has_member : (blob, blob) -> (bool) query; members : (blob, nat64, nat64) -> (vec blob) query; members_revision : (blob) -> (nat64) query; diff --git a/contracts/icp/context-config/src/lib.rs b/contracts/icp/context-config/src/lib.rs index 744b4c810..40cb300c1 100644 --- a/contracts/icp/context-config/src/lib.rs +++ b/contracts/icp/context-config/src/lib.rs @@ -23,6 +23,7 @@ pub struct Context { pub application: Guard, pub members: Guard>>, pub proxy: Guard, + pub member_nonces: BTreeMap, u64>, } #[derive(CandidType, Deserialize, Debug)] diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 4971ad6d7..1c0d6d8e6 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -1,4 +1,5 @@ use std::ops::Deref; +use std::collections::BTreeMap; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ @@ -28,22 +29,22 @@ pub async fn mutate(signed_request: ICSigned) -> Result<(), String> { application, } => add_context(&request.signer_id, context_id, *author_id, application).await, ICContextRequestKind::UpdateApplication { application } => { - update_application(&request.signer_id, &context_id, application) + update_application(&request.signer_id, &context_id, request.nonce, application) } ICContextRequestKind::AddMembers { members } => { - add_members(&request.signer_id, &context_id, members) + add_members(&request.signer_id, &context_id, request.nonce, members) } ICContextRequestKind::RemoveMembers { members } => { - remove_members(&request.signer_id, &context_id, members) + remove_members(&request.signer_id, &context_id, request.nonce, members) } ICContextRequestKind::Grant { capabilities } => { - grant(&request.signer_id, &context_id, capabilities) + grant(&request.signer_id, &context_id, request.nonce, capabilities) } ICContextRequestKind::Revoke { capabilities } => { - revoke(&request.signer_id, &context_id, capabilities) + revoke(&request.signer_id, &context_id, request.nonce, capabilities) } ICContextRequestKind::UpdateProxyContract => { - update_proxy_contract(&request.signer_id, context_id).await + update_proxy_contract(&request.signer_id, context_id, request.nonce).await } }, } @@ -65,7 +66,7 @@ async fn add_context( with_state_mut(|configs| { // Create context with guards - let context = Context { + let mut context = Context { application: Guard::new(author_id.rt().expect("infallible conversion"), application), members: Guard::new( author_id.rt().expect("infallible conversion"), @@ -75,8 +76,12 @@ async fn add_context( author_id.rt().expect("infallible conversion"), proxy_canister_id, ), + member_nonces: BTreeMap::new(), }; + // Initialize the author's nonce + context.member_nonces.insert(author_id.rt().expect("infallible conversion"), 0); + // Store context if configs.contexts.insert(context_id, context).is_some() { return Err("context already exists".into()); @@ -133,23 +138,24 @@ async fn deploy_proxy_contract(context_id: ICRepr) -> Result Result<(), String> { with_state_mut(|configs| { - // Get the context or return error if it doesn't exist let context = configs .contexts .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Get mutable access to the application through the Guard + // Add nonce check + check_and_increment_nonce(context, nonce, signer_id)?; + + // Original implementation continues unchanged let guard_ref = context .application .get(signer_id) .map_err(|e| e.to_string())?; let mut app_ref = guard_ref.get_mut(); - - // Replace the application with the new one *app_ref = application; Ok(()) @@ -159,22 +165,25 @@ fn update_application( fn add_members( signer_id: &SignerId, context_id: &ContextId, + nonce: u64, members: Vec>, ) -> Result<(), String> { with_state_mut(|configs| { - // Get the context or return error if it doesn't exist let context = configs .contexts .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Get mutable access to the members through the Guard + // Check nonce + check_and_increment_nonce(context, nonce, signer_id)?; + + // Rest of the function... let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; let mut ctx_members = guard_ref.get_mut(); - // Add each member for member in members { ctx_members.insert(member); + context.member_nonces.insert(member, 0); } Ok(()) @@ -184,15 +193,18 @@ fn add_members( fn remove_members( signer_id: &SignerId, context_id: &ContextId, + nonce: u64, members: Vec>, ) -> Result<(), String> { with_state_mut(|configs| { - // Get the context or return error if it doesn't exist let context = configs .contexts .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; + // Check nonce + check_and_increment_nonce(context, nonce, signer_id)?; + // Get mutable access to the members through the Guard let mut ctx_members = context .members @@ -220,6 +232,7 @@ fn remove_members( fn grant( signer_id: &SignerId, context_id: &ContextId, + nonce: u64, capabilities: Vec<(ICRepr, ICCapability)>, ) -> Result<(), String> { with_state_mut(|configs| { @@ -228,6 +241,9 @@ fn grant( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; + // Check nonce + check_and_increment_nonce(context, nonce, signer_id)?; + for (identity, capability) in capabilities { let is_member = context.members.deref().contains(&identity); @@ -270,6 +286,7 @@ fn grant( fn revoke( signer_id: &SignerId, context_id: &ContextId, + nonce: u64, capabilities: Vec<(ICRepr, ICCapability)>, ) -> Result<(), String> { with_state_mut(|configs| { @@ -278,6 +295,9 @@ fn revoke( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; + // Check nonce + check_and_increment_nonce(context, nonce, signer_id)?; + for (identity, capability) in capabilities { match capability { ICCapability::ManageApplication => { @@ -314,6 +334,7 @@ fn revoke( async fn update_proxy_contract( signer_id: &SignerId, context_id: ICRepr, + nonce: u64, ) -> Result<(), String> { let (proxy_canister_id, proxy_code) = with_state_mut(|configs| { let context = configs @@ -321,6 +342,9 @@ async fn update_proxy_contract( .get_mut(&context_id) .ok_or_else(|| "context does not exist".to_string())?; + // Check nonce + check_and_increment_nonce(context, nonce, signer_id)?; + let proxy_cannister = *context .proxy .get(signer_id) @@ -346,3 +370,19 @@ async fn update_proxy_contract( Ok(()) } + +fn check_and_increment_nonce( + context: &mut Context, + nonce: u64, + signer_id: &SignerId, +) -> Result<(), String> { + let context_identity = signer_id.rt().expect("infallible conversion"); + let current_nonce = *context.member_nonces.get(&context_identity).unwrap_or(&0); + + if current_nonce != nonce { + return Err("invalid nonce".into()); + } + + context.member_nonces.insert(context_identity, nonce + 1); + Ok(()) +} diff --git a/contracts/icp/context-config/src/query.rs b/contracts/icp/context-config/src/query.rs index 0c5f534a9..cf9845e5d 100644 --- a/contracts/icp/context-config/src/query.rs +++ b/contracts/icp/context-config/src/query.rs @@ -134,3 +134,17 @@ fn privileges( privileges }) } + +#[ic_cdk::query] +fn fetch_nonce( + context_id: ICRepr, + member_id: ICRepr, +) -> Option { + with_state(|configs| { + configs + .contexts + .get(&context_id) + .and_then(|context| context.member_nonces.get(&member_id)) + .copied() + }) +} diff --git a/contracts/icp/context-config/tests/integration.rs b/contracts/icp/context-config/tests/integration.rs index dbd7f5134..4613e31a9 100644 --- a/contracts/icp/context-config/tests/integration.rs +++ b/contracts/icp/context-config/tests/integration.rs @@ -294,7 +294,7 @@ fn test_member_management() { }, }), signer_id: (alice_pk.rt().expect("infallible conversion")), - nonce: 0, + nonce: 1, }; let signed_request = create_signed_request(&alice_sk, remove_member_request); @@ -403,7 +403,7 @@ fn test_capability_management() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - nonce: 0, + nonce: 1, }; let signed_request = create_signed_request(&alice_sk, grant_request); @@ -444,7 +444,7 @@ fn test_capability_management() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - nonce: 0, + nonce: 2, }; let signed_request = create_signed_request(&alice_sk, revoke_request); @@ -731,7 +731,7 @@ fn test_edge_cases() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - nonce: 0, + nonce: 1, }; let signed_request = create_signed_request(&alice_sk, add_duplicate_members); @@ -804,7 +804,7 @@ fn test_concurrent_operations() { // Create multiple member additions with same timestamp let mut requests = Vec::new(); - for _ in 0..3 { + for i in 0..3 { let new_member = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); let request = ICRequest { kind: ICRequestKind::Context(ICContextRequest { @@ -814,7 +814,7 @@ fn test_concurrent_operations() { }, }), signer_id: (alice_pk.to_bytes().rt().expect("infallible conversion")), - nonce: 0, + nonce: i as u64, }; requests.push(create_signed_request(&alice_sk, request)); } @@ -855,3 +855,111 @@ fn test_concurrent_operations() { ); } } + +#[test] +fn test_nonce_management() { + let (pic, canister) = setup(); + let mut rng = rand::thread_rng(); + + // Create test identities + let context_sk = SigningKey::from_bytes(&rng.gen()); + let context_pk = context_sk.verifying_key(); + let context_id = context_pk.rt().expect("infallible conversion"); + + let alice_sk = SigningKey::from_bytes(&rng.gen()); + let alice_pk = alice_sk.verifying_key(); + let alice_id = alice_pk.rt().expect("infallible conversion"); + + // Create initial context + let create_request = ICRequest { + kind: ICRequestKind::Context(ICContextRequest { + context_id, + kind: ICContextRequestKind::Add { + author_id: alice_id, + application: ICApplication { + id: rng.gen::<[_; 32]>().rt().expect("infallible conversion"), + blob: rng.gen::<[_; 32]>().rt().expect("infallible conversion"), + size: 0, + source: String::new(), + metadata: vec![], + }, + }, + }), + signer_id: context_id.rt().expect("infallible conversion"), + nonce: 0, + }; + + let signed_request = create_signed_request(&context_sk, create_request); + let response = pic.update_call( + canister, + Principal::anonymous(), + "mutate", + candid::encode_one(signed_request).unwrap(), + ); + handle_response(response, true, "Context creation"); + + // Test sequential nonce increment + for i in 0..3 { + let request = ICRequest { + kind: ICRequestKind::Context(ICContextRequest { + context_id, + kind: ICContextRequestKind::AddMembers { + members: vec![rng.gen::<[_; 32]>().rt().expect("infallible conversion")], + }, + }), + signer_id: alice_id.rt().expect("infallible conversion"), + nonce: i as u64, + }; + + let signed_request = create_signed_request(&alice_sk, request); + let response = pic.update_call( + canister, + Principal::anonymous(), + "mutate", + candid::encode_one(signed_request).unwrap(), + ); + handle_response(response, true, &format!("Member addition {}", i)); + + // Verify nonce was incremented + let query_response = pic.query_call( + canister, + Principal::anonymous(), + "fetch_nonce", + candid::encode_args((context_id, alice_id)).unwrap(), + ); + + let current_nonce = if let Ok(WasmResult::Reply(bytes)) = query_response { + candid::decode_one::>(&bytes) + .expect("Failed to decode nonce") + } else { + panic!("Failed to fetch nonce"); + }; + + assert_eq!( + current_nonce.unwrap(), + i + 1, + "Nonce should be incremented after operation" + ); + } + + // Test invalid nonce rejection + let invalid_nonce_request = ICRequest { + kind: ICRequestKind::Context(ICContextRequest { + context_id, + kind: ICContextRequestKind::AddMembers { + members: vec![rng.gen::<[_; 32]>().rt().expect("infallible conversion")], + }, + }), + signer_id: alice_id.rt().expect("infallible conversion"), + nonce: 0, // Using old nonce + }; + + let signed_request = create_signed_request(&alice_sk, invalid_nonce_request); + let response = pic.update_call( + canister, + Principal::anonymous(), + "mutate", + candid::encode_one(signed_request).unwrap(), + ); + handle_response(response, false, "Invalid nonce rejection"); +} From 545b72d82cddee9bb32cd75e3915b51db6be5353 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 16:35:56 +0100 Subject: [PATCH 05/27] fix: lint --- contracts/icp/context-config/src/mutate.rs | 10 ++++++---- contracts/icp/context-config/src/query.rs | 5 +---- contracts/icp/context-config/tests/integration.rs | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 1c0d6d8e6..b00f43102 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -1,5 +1,5 @@ -use std::ops::Deref; use std::collections::BTreeMap; +use std::ops::Deref; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ @@ -80,7 +80,9 @@ async fn add_context( }; // Initialize the author's nonce - context.member_nonces.insert(author_id.rt().expect("infallible conversion"), 0); + context + .member_nonces + .insert(author_id.rt().expect("infallible conversion"), 0); // Store context if configs.contexts.insert(context_id, context).is_some() { @@ -378,11 +380,11 @@ fn check_and_increment_nonce( ) -> Result<(), String> { let context_identity = signer_id.rt().expect("infallible conversion"); let current_nonce = *context.member_nonces.get(&context_identity).unwrap_or(&0); - + if current_nonce != nonce { return Err("invalid nonce".into()); } - + context.member_nonces.insert(context_identity, nonce + 1); Ok(()) } diff --git a/contracts/icp/context-config/src/query.rs b/contracts/icp/context-config/src/query.rs index cf9845e5d..fc2b84140 100644 --- a/contracts/icp/context-config/src/query.rs +++ b/contracts/icp/context-config/src/query.rs @@ -136,10 +136,7 @@ fn privileges( } #[ic_cdk::query] -fn fetch_nonce( - context_id: ICRepr, - member_id: ICRepr, -) -> Option { +fn fetch_nonce(context_id: ICRepr, member_id: ICRepr) -> Option { with_state(|configs| { configs .contexts diff --git a/contracts/icp/context-config/tests/integration.rs b/contracts/icp/context-config/tests/integration.rs index 4613e31a9..32b596910 100644 --- a/contracts/icp/context-config/tests/integration.rs +++ b/contracts/icp/context-config/tests/integration.rs @@ -929,8 +929,7 @@ fn test_nonce_management() { ); let current_nonce = if let Ok(WasmResult::Reply(bytes)) = query_response { - candid::decode_one::>(&bytes) - .expect("Failed to decode nonce") + candid::decode_one::>(&bytes).expect("Failed to decode nonce") } else { panic!("Failed to fetch nonce"); }; From 39e5c26e8b0c37eb26f8acdfd17c47a7d7eda101 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 16:36:28 +0100 Subject: [PATCH 06/27] fix: check the transfer result before doing cross contract call --- .../res/calimero_context_proxy_icp.did | 1 - contracts/icp/context-proxy/src/mutate.rs | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/contracts/icp/context-proxy/res/calimero_context_proxy_icp.did b/contracts/icp/context-proxy/res/calimero_context_proxy_icp.did index 7dd442d89..566c10fff 100644 --- a/contracts/icp/context-proxy/res/calimero_context_proxy_icp.did +++ b/contracts/icp/context-proxy/res/calimero_context_proxy_icp.did @@ -17,7 +17,6 @@ type ICProposalAction = variant { }; }; type ICProposalApprovalWithSigner = record { - added_timestamp : nat64; signer_id : blob; proposal_id : blob; }; diff --git a/contracts/icp/context-proxy/src/mutate.rs b/contracts/icp/context-proxy/src/mutate.rs index b9ab239f2..1c9e721c5 100644 --- a/contracts/icp/context-proxy/src/mutate.rs +++ b/contracts/icp/context-proxy/src/mutate.rs @@ -106,13 +106,24 @@ async fn execute_proposal(proposal_id: &ProposalId) -> Result<(), String> { created_at_time: None, }; - let _: (Result,) = + // Call transfer and explicitly handle the result + let transfer_result: (Result,) = ic_cdk::call(Principal::from(ledger_id), "transfer", (transfer_args,)) .await - .map_err(|e| format!("Transfer failed: {:?}", e))?; + .map_err(|e| format!("Transfer call failed: {:?}", e))?; + + // Check if the transfer was successful + match transfer_result.0 { + Ok(_block_height) => { + // Transfer succeeded, proceed with cross-contract call + } + Err(transfer_error) => { + return Err(format!("Transfer failed: {:?}", transfer_error)); + } + } } - // Then make the actual cross-contract call + // Proceed with cross-contract call only if there was no deposit or transfer succeeded let args_bytes = candid::encode_one(args) .map_err(|e| format!("Failed to encode args: {}", e))?; From 2fa86acfaa9521330857311cd0d637ba0aa2a60a Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 17:43:29 +0100 Subject: [PATCH 07/27] fix: resolved PR comments --- contracts/icp/context-config/src/lib.rs | 5 ++-- contracts/icp/context-config/src/mutate.rs | 30 ++++++++++------------ contracts/icp/context-config/src/query.rs | 9 ++++--- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/contracts/icp/context-config/src/lib.rs b/contracts/icp/context-config/src/lib.rs index 40cb300c1..c1795e755 100644 --- a/contracts/icp/context-config/src/lib.rs +++ b/contracts/icp/context-config/src/lib.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ICApplication, ICCapability, ICRequest, ICSigned}; @@ -21,9 +21,8 @@ thread_local! { #[derive(CandidType, Deserialize, Debug)] pub struct Context { pub application: Guard, - pub members: Guard>>, + pub members: Guard, u64>>, pub proxy: Guard, - pub member_nonces: BTreeMap, u64>, } #[derive(CandidType, Deserialize, Debug)] diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index b00f43102..ce4dd339c 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -66,24 +66,18 @@ async fn add_context( with_state_mut(|configs| { // Create context with guards - let mut context = Context { + let context = Context { application: Guard::new(author_id.rt().expect("infallible conversion"), application), members: Guard::new( author_id.rt().expect("infallible conversion"), - [author_id.rt().expect("infallible conversion")].into(), + [(author_id.rt().expect("infallible conversion"), 0)].into_iter().collect(), ), proxy: Guard::new( author_id.rt().expect("infallible conversion"), proxy_canister_id, ), - member_nonces: BTreeMap::new(), }; - // Initialize the author's nonce - context - .member_nonces - .insert(author_id.rt().expect("infallible conversion"), 0); - // Store context if configs.contexts.insert(context_id, context).is_some() { return Err("context already exists".into()); @@ -113,7 +107,7 @@ async fn deploy_proxy_contract(context_id: ICRepr) -> Result Result<(), String> { let context_identity = signer_id.rt().expect("infallible conversion"); - let current_nonce = *context.member_nonces.get(&context_identity).unwrap_or(&0); - + let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; + let mut members = guard_ref.get_mut(); + + let current_nonce = members.get(&context_identity).copied().unwrap_or(0); + if current_nonce != nonce { return Err("invalid nonce".into()); } - - context.member_nonces.insert(context_identity, nonce + 1); + + members.insert(context_identity, nonce + 1); Ok(()) } diff --git a/contracts/icp/context-config/src/query.rs b/contracts/icp/context-config/src/query.rs index fc2b84140..6ba5d7c24 100644 --- a/contracts/icp/context-config/src/query.rs +++ b/contracts/icp/context-config/src/query.rs @@ -1,4 +1,5 @@ use std::collections::BTreeMap; +use std::ops::Deref; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ICApplication, ICCapability}; @@ -56,8 +57,8 @@ fn members( .get(&context_id) .expect("context does not exist"); - let members = &*context.members; - members.iter().skip(offset).take(length).cloned().collect() + let members = context.members.deref(); + members.keys().skip(offset).take(length).cloned().collect() }) } @@ -69,7 +70,7 @@ fn has_member(context_id: ICRepr, identity: ICRepr) .get(&context_id) .expect("context does not exist"); - context.members.contains(&identity) + context.members.deref().contains_key(&identity) }) } @@ -141,7 +142,7 @@ fn fetch_nonce(context_id: ICRepr, member_id: ICRepr configs .contexts .get(&context_id) - .and_then(|context| context.member_nonces.get(&member_id)) + .and_then(|context| context.members.deref().get(&member_id)) .copied() }) } From d3d22a7256b137b11bf5c947f061d86a22e1efd5 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 17:43:51 +0100 Subject: [PATCH 08/27] fix:lint --- contracts/icp/context-config/src/mutate.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index ce4dd339c..7ac479c7c 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -70,7 +70,9 @@ async fn add_context( application: Guard::new(author_id.rt().expect("infallible conversion"), application), members: Guard::new( author_id.rt().expect("infallible conversion"), - [(author_id.rt().expect("infallible conversion"), 0)].into_iter().collect(), + [(author_id.rt().expect("infallible conversion"), 0)] + .into_iter() + .collect(), ), proxy: Guard::new( author_id.rt().expect("infallible conversion"), @@ -179,7 +181,7 @@ fn add_members( for member in members { if !ctx_members.contains_key(&member) { - ctx_members.insert(member, 0); // Only insert if member doesn't exist + ctx_members.insert(member, 0); // Only insert if member doesn't exist } } @@ -376,13 +378,13 @@ fn check_and_increment_nonce( let context_identity = signer_id.rt().expect("infallible conversion"); let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; let mut members = guard_ref.get_mut(); - + let current_nonce = members.get(&context_identity).copied().unwrap_or(0); - + if current_nonce != nonce { return Err("invalid nonce".into()); } - + members.insert(context_identity, nonce + 1); Ok(()) } From fcd5b3ad36043e77f6c4cd4e8fd20312ce0fabd4 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 18:09:06 +0100 Subject: [PATCH 09/27] fix: reverted back grouping of members and nonces --- contracts/icp/context-config/src/lib.rs | 4 +- contracts/icp/context-config/src/mutate.rs | 45 ++++++++-------------- contracts/icp/context-config/src/query.rs | 9 ++--- 3 files changed, 22 insertions(+), 36 deletions(-) diff --git a/contracts/icp/context-config/src/lib.rs b/contracts/icp/context-config/src/lib.rs index c1795e755..b278d9b48 100644 --- a/contracts/icp/context-config/src/lib.rs +++ b/contracts/icp/context-config/src/lib.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::collections::BTreeMap; +use std::collections::BTreeSet; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ICApplication, ICCapability, ICRequest, ICSigned}; @@ -21,8 +22,9 @@ thread_local! { #[derive(CandidType, Deserialize, Debug)] pub struct Context { pub application: Guard, - pub members: Guard, u64>>, + pub members: Guard>>, pub proxy: Guard, + pub member_nonces: BTreeMap, u64>, } #[derive(CandidType, Deserialize, Debug)] diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 7ac479c7c..321ac2878 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::ops::Deref; use calimero_context_config::icp::repr::ICRepr; @@ -70,14 +69,15 @@ async fn add_context( application: Guard::new(author_id.rt().expect("infallible conversion"), application), members: Guard::new( author_id.rt().expect("infallible conversion"), - [(author_id.rt().expect("infallible conversion"), 0)] - .into_iter() - .collect(), + [author_id.rt().expect("infallible conversion")].into_iter().collect(), ), proxy: Guard::new( author_id.rt().expect("infallible conversion"), proxy_canister_id, ), + member_nonces: [(author_id.rt().expect("infallible conversion"), 0)] + .into_iter() + .collect(), }; // Store context @@ -175,13 +175,13 @@ fn add_members( // Check nonce check_and_increment_nonce(context, nonce, signer_id)?; - // Rest of the function... let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; let mut ctx_members = guard_ref.get_mut(); for member in members { - if !ctx_members.contains_key(&member) { - ctx_members.insert(member, 0); // Only insert if member doesn't exist + if !ctx_members.contains(&member) { + ctx_members.insert(member); + let _ignored = context.member_nonces.entry(member).or_default(); } } @@ -204,24 +204,12 @@ fn remove_members( // Check nonce check_and_increment_nonce(context, nonce, signer_id)?; - // Get mutable access to the members through the Guard - let mut ctx_members = context - .members - .get(signer_id) - .map_err(|e| e.to_string())? - .get_mut(); + let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; + let mut ctx_members = guard_ref.get_mut(); for member in members { ctx_members.remove(&member); - - // Revoke privileges - ctx_members - .privileges() - .revoke(&member.rt().expect("infallible conversion")); - context - .application - .privileges() - .revoke(&member.rt().expect("infallible conversion")); + context.member_nonces.remove(&member); } Ok(()) @@ -244,7 +232,7 @@ fn grant( check_and_increment_nonce(context, nonce, signer_id)?; for (identity, capability) in capabilities { - let is_member = context.members.deref().contains_key(&identity); + let is_member = context.members.deref().contains(&identity); if !is_member { return Err("unable to grant privileges to non-member".to_string()); @@ -376,15 +364,12 @@ fn check_and_increment_nonce( signer_id: &SignerId, ) -> Result<(), String> { let context_identity = signer_id.rt().expect("infallible conversion"); - let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; - let mut members = guard_ref.get_mut(); - - let current_nonce = members.get(&context_identity).copied().unwrap_or(0); - + let current_nonce = context.member_nonces.get(&context_identity).copied().unwrap_or(0); + if current_nonce != nonce { return Err("invalid nonce".into()); } - - members.insert(context_identity, nonce + 1); + + context.member_nonces.insert(context_identity, nonce + 1); Ok(()) } diff --git a/contracts/icp/context-config/src/query.rs b/contracts/icp/context-config/src/query.rs index 6ba5d7c24..fc2b84140 100644 --- a/contracts/icp/context-config/src/query.rs +++ b/contracts/icp/context-config/src/query.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::ops::Deref; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ICApplication, ICCapability}; @@ -57,8 +56,8 @@ fn members( .get(&context_id) .expect("context does not exist"); - let members = context.members.deref(); - members.keys().skip(offset).take(length).cloned().collect() + let members = &*context.members; + members.iter().skip(offset).take(length).cloned().collect() }) } @@ -70,7 +69,7 @@ fn has_member(context_id: ICRepr, identity: ICRepr) .get(&context_id) .expect("context does not exist"); - context.members.deref().contains_key(&identity) + context.members.contains(&identity) }) } @@ -142,7 +141,7 @@ fn fetch_nonce(context_id: ICRepr, member_id: ICRepr configs .contexts .get(&context_id) - .and_then(|context| context.members.deref().get(&member_id)) + .and_then(|context| context.member_nonces.get(&member_id)) .copied() }) } From 14db1bb58d5758c0d8ebe1df7b4aafc147fc615a Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 18:09:28 +0100 Subject: [PATCH 10/27] fix: lint --- contracts/icp/context-config/src/lib.rs | 3 +-- contracts/icp/context-config/src/mutate.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/contracts/icp/context-config/src/lib.rs b/contracts/icp/context-config/src/lib.rs index b278d9b48..40cb300c1 100644 --- a/contracts/icp/context-config/src/lib.rs +++ b/contracts/icp/context-config/src/lib.rs @@ -1,6 +1,5 @@ use std::cell::RefCell; -use std::collections::BTreeMap; -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ICApplication, ICCapability, ICRequest, ICSigned}; diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 321ac2878..88aba9622 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -69,7 +69,9 @@ async fn add_context( application: Guard::new(author_id.rt().expect("infallible conversion"), application), members: Guard::new( author_id.rt().expect("infallible conversion"), - [author_id.rt().expect("infallible conversion")].into_iter().collect(), + [author_id.rt().expect("infallible conversion")] + .into_iter() + .collect(), ), proxy: Guard::new( author_id.rt().expect("infallible conversion"), @@ -364,12 +366,16 @@ fn check_and_increment_nonce( signer_id: &SignerId, ) -> Result<(), String> { let context_identity = signer_id.rt().expect("infallible conversion"); - let current_nonce = context.member_nonces.get(&context_identity).copied().unwrap_or(0); - + let current_nonce = context + .member_nonces + .get(&context_identity) + .copied() + .unwrap_or(0); + if current_nonce != nonce { return Err("invalid nonce".into()); } - + context.member_nonces.insert(context_identity, nonce + 1); Ok(()) } From bc99546d26b7a743842ace4ea9c39c9e43968021 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Fri, 20 Dec 2024 18:22:19 +0100 Subject: [PATCH 11/27] fix: resolved PR comments --- contracts/icp/context-config/src/mutate.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 88aba9622..c08c33971 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -181,8 +181,7 @@ fn add_members( let mut ctx_members = guard_ref.get_mut(); for member in members { - if !ctx_members.contains(&member) { - ctx_members.insert(member); + if ctx_members.insert(member) { // returns true if the value was newly inserted let _ignored = context.member_nonces.entry(member).or_default(); } } @@ -376,6 +375,8 @@ fn check_and_increment_nonce( return Err("invalid nonce".into()); } - context.member_nonces.insert(context_identity, nonce + 1); + if let Some(stored_nonce) = context.member_nonces.get_mut(&context_identity) { + *stored_nonce += 1; + } Ok(()) } From 244aab0422c0ee340c672f0d1590e0d56ea0f587 Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Fri, 20 Dec 2024 18:46:14 +0100 Subject: [PATCH 12/27] simplify nonce validation --- contracts/icp/context-config/src/mutate.rs | 121 +++++++++------------ 1 file changed, 53 insertions(+), 68 deletions(-) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index c08c33971..d265ffde1 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -21,31 +21,39 @@ pub async fn mutate(signed_request: ICSigned) -> Result<(), String> { .parse(|r| *r.signer_id) .map_err(|e| format!("Failed to verify signature: {}", e))?; - match request.kind { - ICRequestKind::Context(ICContextRequest { context_id, kind }) => match kind { - ICContextRequestKind::Add { - author_id, - application, - } => add_context(&request.signer_id, context_id, *author_id, application).await, - ICContextRequestKind::UpdateApplication { application } => { - update_application(&request.signer_id, &context_id, request.nonce, application) - } - ICContextRequestKind::AddMembers { members } => { - add_members(&request.signer_id, &context_id, request.nonce, members) - } - ICContextRequestKind::RemoveMembers { members } => { - remove_members(&request.signer_id, &context_id, request.nonce, members) - } - ICContextRequestKind::Grant { capabilities } => { - grant(&request.signer_id, &context_id, request.nonce, capabilities) - } - ICContextRequestKind::Revoke { capabilities } => { - revoke(&request.signer_id, &context_id, request.nonce, capabilities) - } - ICContextRequestKind::UpdateProxyContract => { - update_proxy_contract(&request.signer_id, context_id, request.nonce).await - } - }, + let (context_id, kind) = match request.kind { + ICRequestKind::Context(ICContextRequest { context_id, kind }) => (context_id, kind), + }; + + check_and_increment_nonce( + *context_id, + request.signer_id.rt().expect("infallible conversion"), + request.nonce, + )?; + + match kind { + ICContextRequestKind::Add { + author_id, + application, + } => add_context(&request.signer_id, context_id, *author_id, application).await, + ICContextRequestKind::UpdateApplication { application } => { + update_application(&request.signer_id, &context_id, application) + } + ICContextRequestKind::AddMembers { members } => { + add_members(&request.signer_id, &context_id, members) + } + ICContextRequestKind::RemoveMembers { members } => { + remove_members(&request.signer_id, &context_id, members) + } + ICContextRequestKind::Grant { capabilities } => { + grant(&request.signer_id, &context_id, capabilities) + } + ICContextRequestKind::Revoke { capabilities } => { + revoke(&request.signer_id, &context_id, capabilities) + } + ICContextRequestKind::UpdateProxyContract => { + update_proxy_contract(&request.signer_id, context_id).await + } } } @@ -138,7 +146,6 @@ async fn deploy_proxy_contract(context_id: ICRepr) -> Result Result<(), String> { with_state_mut(|configs| { @@ -147,9 +154,6 @@ fn update_application( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Add nonce check - check_and_increment_nonce(context, nonce, signer_id)?; - // Original implementation continues unchanged let guard_ref = context .application @@ -165,7 +169,6 @@ fn update_application( fn add_members( signer_id: &SignerId, context_id: &ContextId, - nonce: u64, members: Vec>, ) -> Result<(), String> { with_state_mut(|configs| { @@ -174,16 +177,12 @@ fn add_members( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Check nonce - check_and_increment_nonce(context, nonce, signer_id)?; - let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; let mut ctx_members = guard_ref.get_mut(); for member in members { - if ctx_members.insert(member) { // returns true if the value was newly inserted - let _ignored = context.member_nonces.entry(member).or_default(); - } + ctx_members.insert(member); + let _ignored = context.member_nonces.entry(member).or_default(); } Ok(()) @@ -193,7 +192,6 @@ fn add_members( fn remove_members( signer_id: &SignerId, context_id: &ContextId, - nonce: u64, members: Vec>, ) -> Result<(), String> { with_state_mut(|configs| { @@ -202,9 +200,6 @@ fn remove_members( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Check nonce - check_and_increment_nonce(context, nonce, signer_id)?; - let guard_ref = context.members.get(signer_id).map_err(|e| e.to_string())?; let mut ctx_members = guard_ref.get_mut(); @@ -220,7 +215,6 @@ fn remove_members( fn grant( signer_id: &SignerId, context_id: &ContextId, - nonce: u64, capabilities: Vec<(ICRepr, ICCapability)>, ) -> Result<(), String> { with_state_mut(|configs| { @@ -229,9 +223,6 @@ fn grant( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Check nonce - check_and_increment_nonce(context, nonce, signer_id)?; - for (identity, capability) in capabilities { let is_member = context.members.deref().contains(&identity); @@ -274,7 +265,6 @@ fn grant( fn revoke( signer_id: &SignerId, context_id: &ContextId, - nonce: u64, capabilities: Vec<(ICRepr, ICCapability)>, ) -> Result<(), String> { with_state_mut(|configs| { @@ -283,9 +273,6 @@ fn revoke( .get_mut(context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Check nonce - check_and_increment_nonce(context, nonce, signer_id)?; - for (identity, capability) in capabilities { match capability { ICCapability::ManageApplication => { @@ -322,7 +309,6 @@ fn revoke( async fn update_proxy_contract( signer_id: &SignerId, context_id: ICRepr, - nonce: u64, ) -> Result<(), String> { let (proxy_canister_id, proxy_code) = with_state_mut(|configs| { let context = configs @@ -330,9 +316,6 @@ async fn update_proxy_contract( .get_mut(&context_id) .ok_or_else(|| "context does not exist".to_string())?; - // Check nonce - check_and_increment_nonce(context, nonce, signer_id)?; - let proxy_cannister = *context .proxy .get(signer_id) @@ -360,23 +343,25 @@ async fn update_proxy_contract( } fn check_and_increment_nonce( - context: &mut Context, + context_id: ContextId, + member_id: ContextIdentity, nonce: u64, - signer_id: &SignerId, ) -> Result<(), String> { - let context_identity = signer_id.rt().expect("infallible conversion"); - let current_nonce = context - .member_nonces - .get(&context_identity) - .copied() - .unwrap_or(0); - - if current_nonce != nonce { - return Err("invalid nonce".into()); - } + with_state_mut(|configs| { + let Some(context) = configs.contexts.get_mut(&context_id) else { + return Ok(()); + }; - if let Some(stored_nonce) = context.member_nonces.get_mut(&context_identity) { - *stored_nonce += 1; - } - Ok(()) + let Some(current_nonce) = context.member_nonces.get_mut(&member_id) else { + return Ok(()); + }; + + if *current_nonce != nonce { + return Err("invalid nonce".into()); + } + + *current_nonce += 1; + + Ok(()) + }) } From 0182e2647d73fed586f8fe839c53d2f0c50cee88 Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Fri, 20 Dec 2024 19:02:37 +0100 Subject: [PATCH 13/27] prevent spurious proxy deployment for existing context --- contracts/icp/context-config/src/mutate.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index d265ffde1..56c53605d 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -67,6 +67,10 @@ async fn add_context( return Err("context addition must be signed by the context itself".into()); } + if with_state(|configs| configs.contexts.contains_key(&context_id)) { + return Err("context already exists".to_owned()); + } + let proxy_canister_id = deploy_proxy_contract(context_id) .await .unwrap_or_else(|e| panic!("Failed to deploy proxy contract: {}", e)); From 647192c32f8c287344344361ad9312b16aff325c Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 10:48:04 +0100 Subject: [PATCH 14/27] pulled latest changes --- contracts/icp/context-config/.env | 3 +- contracts/icp/context-config/deploy_devnet.sh | 35 ++++++++++++++++--- contracts/icp/context-config/dfx.json | 19 +++++++++- contracts/icp/context-config/src/mutate.rs | 6 ++-- contracts/icp/context-proxy/dfx.json | 9 +++++ 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/contracts/icp/context-config/.env b/contracts/icp/context-config/.env index a649e815c..63dae3118 100644 --- a/contracts/icp/context-config/.env +++ b/contracts/icp/context-config/.env @@ -1,7 +1,8 @@ # DFX CANISTER ENVIRONMENT VARIABLES -DFX_VERSION='0.24.2' +DFX_VERSION='0.24.3' DFX_NETWORK='local' +CANISTER_ID_LEDGER='bd3sg-teaaa-aaaaa-qaaba-cai' CANISTER_ID_CONTEXT_CONTRACT='bkyz2-fmaaa-aaaaa-qaaaq-cai' CANISTER_ID='bkyz2-fmaaa-aaaaa-qaaaq-cai' CANISTER_CANDID_PATH='/Users/alen/www/calimero/core/contracts/icp/context-config/./res/calimero_context_config_icp.did' diff --git a/contracts/icp/context-config/deploy_devnet.sh b/contracts/icp/context-config/deploy_devnet.sh index 51b77ea92..09fe336db 100755 --- a/contracts/icp/context-config/deploy_devnet.sh +++ b/contracts/icp/context-config/deploy_devnet.sh @@ -1,13 +1,38 @@ #!/bin/bash +set -e -# Build the contract +# Build both contracts +echo "Building contracts..." +cd "$(dirname $0)" ./build.sh +cd ../context-proxy +./build.sh +cd ../context-config -# Stop the replica +# Stop and start dfx +echo "Restarting dfx..." dfx stop +dfx start --background --clean -# Start the replica -dfx start --background +# Force remove existing canisters if they exist +echo "Cleaning up old canisters..." +dfx canister delete context_contract || true +dfx canister delete ledger || true -# Deploy the contract +# Create and deploy canisters +echo "Deploying contracts..." +dfx canister create --all --force dfx deploy + +# Get the proxy wasm +echo "Reading proxy WASM..." +PROXY_WASM=$(xxd -p ../context-proxy/res/calimero_context_proxy_icp.wasm | tr -d '\n') + +# Set proxy code in context config +echo "Setting proxy code in context config..." +dfx canister call context_contract set_proxy_code "( + vec {$(echo $PROXY_WASM | sed 's/\([0-9a-f]\{2\}\)/0x\1;/g')}, + principal \"$LEDGER_ID\" +)" + +echo "Deployment complete!" diff --git a/contracts/icp/context-config/dfx.json b/contracts/icp/context-config/dfx.json index c429488ba..1672662da 100644 --- a/contracts/icp/context-config/dfx.json +++ b/contracts/icp/context-config/dfx.json @@ -4,6 +4,18 @@ "package": "calimero-context-config-icp", "candid": "./res/calimero_context_config_icp.did", "type": "rust" + }, + "ledger": { + "type": "custom", + "wasm": "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz", + "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did", + "remote": { + "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did", + "id": { + "ic": "ryjl3-tyaaa-aaaaa-aaaba-cai" + } + }, + "init_arg": "(variant { Init = record { minting_account = \"62c39e7c2484a1a9aa0864f9fb402558537111c3e6db3c37f793ab460f137ae4\"; initial_values = vec {}; send_whitelist = vec {}; token_name = opt \"Internet Computer\"; token_symbol = opt \"ICP\"; transfer_fee = opt record { e8s = 10_000 }; archive_options = opt record { trigger_threshold = 2_000_000; num_blocks_to_archive = 1_000_000; controller_id = principal \"aaaaa-aa\"; cycles_for_archive_creation = opt (0 : nat64); node_max_memory_size_bytes = null; max_message_size_bytes = null }}})" } }, "defaults": { @@ -12,6 +24,11 @@ "packtool": "" } }, - "output_env_file": ".env", + "networks": { + "local": { + "bind": "127.0.0.1:8080", + "type": "persistent" + } + }, "version": 1 } diff --git a/contracts/icp/context-config/src/mutate.rs b/contracts/icp/context-config/src/mutate.rs index 56c53605d..5fb1899d8 100644 --- a/contracts/icp/context-config/src/mutate.rs +++ b/contracts/icp/context-config/src/mutate.rs @@ -185,8 +185,10 @@ fn add_members( let mut ctx_members = guard_ref.get_mut(); for member in members { - ctx_members.insert(member); - let _ignored = context.member_nonces.entry(member).or_default(); + if ctx_members.insert(member) { + // returns true if the value was newly inserted + let _ignored = context.member_nonces.entry(member).or_default(); + } } Ok(()) diff --git a/contracts/icp/context-proxy/dfx.json b/contracts/icp/context-proxy/dfx.json index bea695add..fb8692c84 100644 --- a/contracts/icp/context-proxy/dfx.json +++ b/contracts/icp/context-proxy/dfx.json @@ -24,6 +24,15 @@ "packtool": "" } }, + "networks": { + "local": { + "bind": "127.0.0.1:8080", + "type": "persistent", + "replica": { + "subnet_type": "system" + } + } + }, "output_env_file": ".env", "version": 1 } From f44021454e4c1d01783c866c2d1e31f481966e7a Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 13:18:50 +0100 Subject: [PATCH 15/27] fix: removed mock_ledger from Cargo --- Cargo.lock | 679 +++++++++++++----- Cargo.toml | 1 - contracts/icp/context-proxy/Cargo.toml | 2 + contracts/icp/context-proxy/dfx.json | 6 - .../context-proxy/mock/external/Cargo.toml | 1 + .../res/calimero_mock_external_icp.did | 7 +- .../context-proxy/mock/external/src/lib.rs | 63 +- .../icp/context-proxy/mock/ledger/Cargo.toml | 14 - .../icp/context-proxy/mock/ledger/build.sh | 22 - .../ledger/res/calimero_mock_ledger_icp.did | 23 - .../icp/context-proxy/mock/ledger/src/lib.rs | 60 -- contracts/icp/context-proxy/src/mutate.rs | 89 ++- .../icp/context-proxy/tests/integration.rs | 263 ++++--- 13 files changed, 791 insertions(+), 439 deletions(-) delete mode 100644 contracts/icp/context-proxy/mock/ledger/Cargo.toml delete mode 100755 contracts/icp/context-proxy/mock/ledger/build.sh delete mode 100644 contracts/icp/context-proxy/mock/ledger/res/calimero_mock_ledger_icp.did delete mode 100644 contracts/icp/context-proxy/mock/ledger/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6ab88042b..e280dc8d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,7 +330,7 @@ checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener", "event-listener-strategy", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -341,7 +341,7 @@ checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -372,11 +372,11 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-sink", "futures-util", "memchr", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -385,11 +385,11 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-sink", "futures-util", "memchr", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -435,19 +435,19 @@ dependencies = [ "async-trait", "axum-core", "base64 0.22.1", - "bytes", + "bytes 1.9.0", "futures-util", "http 1.1.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", "hyper-util", - "itoa", + "itoa 1.0.14", "matchit", "memchr", "mime", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.15", "rustversion", "serde", "serde_json", @@ -455,7 +455,7 @@ dependencies = [ "serde_urlencoded", "sha1", "sync_wrapper 1.0.2", - "tokio", + "tokio 1.41.1", "tokio-tungstenite", "tower 0.5.1", "tower-layer", @@ -470,13 +470,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", - "bytes", + "bytes 1.9.0", "futures-util", "http 1.1.0", "http-body 1.0.1", "http-body-util", "mime", - "pin-project-lite", + "pin-project-lite 0.2.15", "rustversion", "sync_wrapper 1.0.2", "tower-layer", @@ -491,17 +491,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ad46c3ec4e12f4a4b6835e173ba21c25e484c9d02b49770bf006ce5367c036" dependencies = [ "arc-swap", - "bytes", + "bytes 1.9.0", "futures-util", "http 1.1.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", "hyper-util", - "pin-project-lite", + "pin-project-lite 0.2.15", "rustls 0.21.12", "rustls-pemfile 2.2.0", - "tokio", + "tokio 1.41.1", "tokio-rustls 0.24.1", "tower 0.4.13", "tower-service", @@ -514,13 +514,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ea4cd08ae2a5f075d28fa31190163c8106a1d2d3189442494bae22b39040a0d" dependencies = [ "axum-server", - "bytes", + "bytes 1.9.0", "http 1.1.0", "http-body-util", "pin-project", - "tokio", + "tokio 1.41.1", "tokio-rustls 0.24.1", - "tokio-util", + "tokio-util 0.7.12", "tower-layer", "tower-service", ] @@ -795,6 +795,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "bytes" version = "1.9.0" @@ -857,8 +863,8 @@ dependencies = [ "serde", "sha2 0.10.8", "thiserror 1.0.69", - "tokio", - "tokio-util", + "tokio 1.41.1", + "tokio-util 0.7.12", ] [[package]] @@ -893,8 +899,8 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.9", "serde", - "tokio", - "tokio-util", + "tokio 1.41.1", + "tokio-util 0.7.12", "tracing", ] @@ -954,7 +960,7 @@ dependencies = [ "near-workspaces", "rand 0.8.5", "serde_json", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -965,12 +971,14 @@ dependencies = [ "calimero-context-config", "candid", "ed25519-dalek", + "flate2", "hex", "ic-cdk 0.16.0", "ic-cdk-macros 0.16.0", "ic-ledger-types", "pocket-ic", "rand 0.8.5", + "reqwest 0.10.10", "serde", "thiserror 1.0.69", ] @@ -989,7 +997,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -1007,28 +1015,18 @@ dependencies = [ [[package]] name = "calimero-mock-external-icp" version = "0.1.0" -dependencies = [ - "candid", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.16.0", -] - -[[package]] -name = "calimero-mock-ledger-icp" -version = "0.1.0" dependencies = [ "candid", "ic-cdk 0.16.0", "ic-cdk-macros 0.16.0", "ic-ledger-types", - "serde", ] [[package]] name = "calimero-network" version = "0.1.0" dependencies = [ - "bytes", + "bytes 1.9.0", "calimero-primitives", "eyre", "futures-util", @@ -1038,9 +1036,9 @@ dependencies = [ "owo-colors", "serde", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tokio-test", - "tokio-util", + "tokio-util 0.7.12", "tracing", ] @@ -1067,7 +1065,7 @@ dependencies = [ "owo-colors", "rand 0.8.5", "serde_json", - "tokio", + "tokio 1.41.1", "tracing", "url", ] @@ -1080,7 +1078,7 @@ dependencies = [ "calimero-runtime", "serde", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -1108,7 +1106,7 @@ dependencies = [ "near-workspaces", "semver", "serde_json", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -1206,7 +1204,7 @@ dependencies = [ "starknet", "starknet-crypto 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tower 0.4.13", "tower-http", "tower-sessions", @@ -1286,7 +1284,7 @@ dependencies = [ "eyre", "near-sdk", "near-workspaces", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -2067,7 +2065,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2106,7 +2104,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -2376,7 +2374,7 @@ checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -2386,7 +2384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -2537,7 +2535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2555,6 +2553,22 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.3.2", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "funty" version = "2.0.0" @@ -2627,7 +2641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "futures-core", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -2704,7 +2718,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite", + "pin-project-lite 0.2.15", "pin-utils", "slab", ] @@ -2804,13 +2818,33 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 1.9.3", + "slab", + "tokio 0.2.25", + "tokio-util 0.3.1", + "tracing", + "tracing-futures", +] + [[package]] name = "h2" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ - "bytes", + "bytes 1.9.0", "fnv", "futures-core", "futures-sink", @@ -2818,8 +2852,8 @@ dependencies = [ "http 0.2.12", "indexmap 2.6.0", "slab", - "tokio", - "tokio-util", + "tokio 1.41.1", + "tokio-util 0.7.12", "tracing", ] @@ -2830,15 +2864,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", - "bytes", + "bytes 1.9.0", "fnv", "futures-core", "futures-sink", "http 1.1.0", "indexmap 2.6.0", "slab", - "tokio", - "tokio-util", + "tokio 1.41.1", + "tokio-util 0.7.12", "tracing", ] @@ -2885,10 +2919,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ "base64 0.21.7", - "bytes", + "bytes 1.9.0", "headers-core", "http 0.2.12", - "httpdate", + "httpdate 1.0.3", "mime", "sha1", ] @@ -2958,10 +2992,10 @@ dependencies = [ "ipnet", "once_cell", "rand 0.8.5", - "socket2", + "socket2 0.5.8", "thiserror 1.0.69", "tinyvec", - "tokio", + "tokio 1.41.1", "tracing", "url", ] @@ -2983,7 +3017,7 @@ dependencies = [ "resolv-conf", "smallvec", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tracing", ] @@ -3022,7 +3056,7 @@ checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" dependencies = [ "libc", "match_cfg", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3031,9 +3065,9 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ - "bytes", + "bytes 1.9.0", "fnv", - "itoa", + "itoa 1.0.14", ] [[package]] @@ -3042,9 +3076,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ - "bytes", + "bytes 1.9.0", "fnv", - "itoa", + "itoa 1.0.14", +] + +[[package]] +name = "http-body" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +dependencies = [ + "bytes 0.5.6", + "http 0.2.12", ] [[package]] @@ -3053,9 +3097,9 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ - "bytes", + "bytes 1.9.0", "http 0.2.12", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -3064,7 +3108,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes", + "bytes 1.9.0", "http 1.1.0", ] @@ -3074,11 +3118,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-util", "http 1.1.0", "http-body 1.0.1", - "pin-project-lite", + "pin-project-lite 0.2.15", ] [[package]] @@ -3093,19 +3137,49 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.13.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" +dependencies = [ + "bytes 0.5.6", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.2.7", + "http 0.2.12", + "http-body 0.3.1", + "httparse", + "httpdate 0.3.2", + "itoa 0.4.8", + "pin-project", + "socket2 0.3.19", + "tokio 0.2.25", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-channel", "futures-core", "futures-util", @@ -3113,11 +3187,11 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", + "httpdate 1.0.3", + "itoa 1.0.14", + "pin-project-lite 0.2.15", + "socket2 0.5.8", + "tokio 1.41.1", "tower-service", "tracing", "want", @@ -3129,18 +3203,18 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-channel", "futures-util", "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "httparse", - "httpdate", - "itoa", - "pin-project-lite", + "httpdate 1.0.3", + "itoa 1.0.14", + "pin-project-lite 0.2.15", "smallvec", - "tokio", + "tokio 1.41.1", "want", ] @@ -3154,7 +3228,7 @@ dependencies = [ "http 0.2.12", "hyper 0.14.31", "rustls 0.21.12", - "tokio", + "tokio 1.41.1", "tokio-rustls 0.24.1", ] @@ -3171,22 +3245,35 @@ dependencies = [ "rustls 0.23.19", "rustls-native-certs", "rustls-pki-types", - "tokio", + "tokio 1.41.1", "tokio-rustls 0.26.0", "tower-service", "webpki-roots 0.26.7", ] +[[package]] +name = "hyper-tls" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +dependencies = [ + "bytes 0.5.6", + "hyper 0.13.10", + "native-tls", + "tokio 0.2.25", + "tokio-tls", +] + [[package]] name = "hyper-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes", + "bytes 1.9.0", "hyper 0.14.31", "native-tls", - "tokio", + "tokio 1.41.1", "tokio-native-tls", ] @@ -3196,12 +3283,12 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "bytes", + "bytes 1.9.0", "http-body-util", "hyper 1.5.1", "hyper-util", "native-tls", - "tokio", + "tokio 1.41.1", "tokio-native-tls", "tower-service", ] @@ -3212,15 +3299,15 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", "hyper 1.5.1", - "pin-project-lite", - "socket2", - "tokio", + "pin-project-lite 0.2.15", + "socket2 0.5.8", + "tokio 1.41.1", "tower-service", "tracing", ] @@ -3287,7 +3374,7 @@ dependencies = [ "simple_asn1", "thiserror 1.0.69", "time", - "tokio", + "tokio 1.41.1", "tower-service", "url", ] @@ -3724,7 +3811,7 @@ dependencies = [ "netlink-sys", "rtnetlink", "system-configuration 0.6.1", - "tokio", + "tokio 1.41.1", "windows", ] @@ -3736,13 +3823,13 @@ checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" dependencies = [ "async-trait", "attohttpc", - "bytes", + "bytes 1.9.0", "futures", "http 0.2.12", "hyper 0.14.31", "log", "rand 0.8.5", - "tokio", + "tokio 1.41.1", "url", "xmltree", ] @@ -3851,16 +3938,25 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + [[package]] name = "ipconfig" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2", + "socket2 0.5.8", "widestring", "windows-sys 0.48.0", - "winreg", + "winreg 0.50.0", ] [[package]] @@ -3875,7 +3971,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3902,6 +3998,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.14" @@ -4008,6 +4110,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "kqueue" version = "1.0.8" @@ -4102,7 +4214,7 @@ version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681fb3f183edfbedd7a57d32ebe5dcdc0b9f94061185acf3c30249349cc6fc99" dependencies = [ - "bytes", + "bytes 1.9.0", "either", "futures", "futures-timer", @@ -4235,7 +4347,7 @@ dependencies = [ "asynchronous-codec 0.7.0", "base64 0.21.7", "byteorder", - "bytes", + "bytes 1.9.0", "either", "fnv", "futures", @@ -4307,7 +4419,7 @@ checksum = "5cc5767727d062c4eac74dd812c998f0e488008e82cce9c33b463d38423f9ad2" dependencies = [ "arrayvec 0.7.6", "asynchronous-codec 0.7.0", - "bytes", + "bytes 1.9.0", "either", "fnv", "futures", @@ -4343,8 +4455,8 @@ dependencies = [ "libp2p-swarm", "rand 0.8.5", "smallvec", - "socket2", - "tokio", + "socket2 0.5.8", + "tokio 1.41.1", "tracing", "void", ] @@ -4377,7 +4489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecd0545ce077f6ea5434bcb76e8d0fe942693b4380aaad0d34a358c2bd05793" dependencies = [ "asynchronous-codec 0.7.0", - "bytes", + "bytes 1.9.0", "curve25519-dalek", "futures", "libp2p-core", @@ -4420,7 +4532,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c67296ad4e092e23f92aea3d2bdb6f24eab79c0929ed816dfb460ea2f4567d2b" dependencies = [ - "bytes", + "bytes 1.9.0", "futures", "futures-timer", "if-watch", @@ -4432,9 +4544,9 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustls 0.23.19", - "socket2", + "socket2 0.5.8", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tracing", ] @@ -4445,7 +4557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d1c667cfabf3dd675c8e3cea63b7b98434ecf51721b7894cbb01d29983a6a9b" dependencies = [ "asynchronous-codec 0.7.0", - "bytes", + "bytes 1.9.0", "either", "futures", "futures-bounded", @@ -4541,7 +4653,7 @@ dependencies = [ "once_cell", "rand 0.8.5", "smallvec", - "tokio", + "tokio 1.41.1", "tracing", "void", ] @@ -4570,8 +4682,8 @@ dependencies = [ "libc", "libp2p-core", "libp2p-identity", - "socket2", - "tokio", + "socket2 0.5.8", + "tokio 1.41.1", "tracing", ] @@ -4624,7 +4736,7 @@ dependencies = [ "igd-next", "libp2p-core", "libp2p-swarm", - "tokio", + "tokio 1.41.1", "tracing", "void", ] @@ -4849,7 +4961,7 @@ dependencies = [ "serde", "serde_json", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tokio-tungstenite", "url", ] @@ -4882,7 +4994,7 @@ dependencies = [ "near-crypto", "rand 0.8.5", "starknet", - "tokio", + "tokio 1.41.1", "toml_edit", "tracing", "tracing-subscriber", @@ -4929,6 +5041,25 @@ dependencies = [ "adler2", ] +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + [[package]] name = "mio" version = "0.8.11" @@ -4953,6 +5084,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + [[package]] name = "more-asserts" version = "0.2.2" @@ -5005,7 +5148,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" dependencies = [ - "bytes", + "bytes 1.9.0", "futures", "log", "pin-project", @@ -5239,7 +5382,7 @@ dependencies = [ "base64 0.21.7", "bitvec", "borsh", - "bytes", + "bytes 1.9.0", "bytesize", "cfg-if 1.0.0", "chrono", @@ -5302,7 +5445,7 @@ dependencies = [ "binary-install", "fs2", "home", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -5462,7 +5605,7 @@ dependencies = [ "sha2 0.10.8", "tempfile", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tokio-retry", "tracing", "url", @@ -5520,6 +5663,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "net2" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + [[package]] name = "netlink-packet-core" version = "0.7.0" @@ -5563,13 +5717,13 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" dependencies = [ - "bytes", + "bytes 1.9.0", "futures", "log", "netlink-packet-core", "netlink-sys", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -5578,11 +5732,11 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ - "bytes", + "bytes 1.9.0", "futures", "libc", "log", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -5650,7 +5804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -6019,6 +6173,12 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "pin-project-lite" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -6069,7 +6229,7 @@ dependencies = [ "strum 0.26.3", "strum_macros 0.26.4", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "tracing", "tracing-appender", "tracing-subscriber", @@ -6085,7 +6245,7 @@ dependencies = [ "cfg-if 1.0.0", "concurrent-queue", "hermit-abi 0.4.0", - "pin-project-lite", + "pin-project-lite 0.2.15", "rustix", "tracing", "windows-sys 0.59.0", @@ -6254,7 +6414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", - "itoa", + "itoa 1.0.14", "parking_lot", "prometheus-client-derive-encode", ] @@ -6321,7 +6481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" dependencies = [ "asynchronous-codec 0.6.2", - "bytes", + "bytes 1.9.0", "quick-protobuf", "thiserror 1.0.69", "unsigned-varint 0.7.2", @@ -6334,7 +6494,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" dependencies = [ "asynchronous-codec 0.7.0", - "bytes", + "bytes 1.9.0", "quick-protobuf", "thiserror 1.0.69", "unsigned-varint 0.8.0", @@ -6346,16 +6506,16 @@ version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-io", - "pin-project-lite", + "pin-project-lite 0.2.15", "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", "rustls 0.23.19", - "socket2", + "socket2 0.5.8", "thiserror 2.0.3", - "tokio", + "tokio 1.41.1", "tracing", ] @@ -6365,7 +6525,7 @@ version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ - "bytes", + "bytes 1.9.0", "getrandom", "rand 0.8.5", "ring 0.17.8", @@ -6388,7 +6548,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.5.8", "tracing", "windows-sys 0.59.0", ] @@ -6418,7 +6578,7 @@ dependencies = [ "libc", "rand_core 0.3.1", "rdrand", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -6622,7 +6782,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -6634,6 +6794,41 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "reqwest" +version = "0.10.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" +dependencies = [ + "base64 0.13.1", + "bytes 0.5.6", + "encoding_rs", + "futures-core", + "futures-util", + "http 0.2.12", + "http-body 0.3.1", + "hyper 0.13.10", + "hyper-tls 0.4.3", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding", + "pin-project-lite 0.2.15", + "serde", + "serde_urlencoded", + "tokio 0.2.25", + "tokio-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.7.0", +] + [[package]] name = "reqwest" version = "0.11.27" @@ -6641,7 +6836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", - "bytes", + "bytes 1.9.0", "encoding_rs", "futures-core", "futures-util", @@ -6658,7 +6853,7 @@ dependencies = [ "native-tls", "once_cell", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.15", "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", @@ -6666,7 +6861,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 0.1.2", "system-configuration 0.5.1", - "tokio", + "tokio 1.41.1", "tokio-native-tls", "tokio-rustls 0.24.1", "tower-service", @@ -6675,7 +6870,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.25.4", - "winreg", + "winreg 0.50.0", ] [[package]] @@ -6685,7 +6880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", - "bytes", + "bytes 1.9.0", "encoding_rs", "futures-channel", "futures-core", @@ -6706,7 +6901,7 @@ dependencies = [ "native-tls", "once_cell", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.15", "quinn", "rustls 0.23.19", "rustls-native-certs", @@ -6717,11 +6912,11 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.2", "system-configuration 0.6.1", - "tokio", + "tokio 1.41.1", "tokio-native-tls", "tokio-rustls 0.26.0", "tokio-socks", - "tokio-util", + "tokio-util 0.7.12", "tower-service", "url", "wasm-bindgen", @@ -6764,7 +6959,7 @@ dependencies = [ "spin 0.5.2", "untrusted 0.7.1", "web-sys", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -6799,7 +6994,7 @@ checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", - "bytes", + "bytes 1.9.0", "hashbrown 0.12.3", "indexmap 1.9.3", "ptr_meta", @@ -6827,7 +7022,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ - "bytes", + "bytes 1.9.0", "rustc-hex", ] @@ -6856,7 +7051,7 @@ dependencies = [ "netlink-sys", "nix 0.26.4", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -7292,7 +7487,7 @@ version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "itoa", + "itoa 1.0.14", "memchr", "ryu", "serde", @@ -7304,7 +7499,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62212da9872ca2a0cad0093191ee33753eddff9266cbbc1b4a602d13a3a768db" dependencies = [ - "itoa", + "itoa 1.0.14", "ryu", "serde", ] @@ -7315,7 +7510,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ - "itoa", + "itoa 1.0.14", "serde", ] @@ -7358,7 +7553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa", + "itoa 1.0.14", "ryu", "serde", ] @@ -7400,7 +7595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap 2.6.0", - "itoa", + "itoa 1.0.14", "ryu", "serde", "unsafe-libyaml", @@ -7479,7 +7674,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" dependencies = [ - "bytes", + "bytes 1.9.0", "memmap2", ] @@ -7590,6 +7785,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", +] + [[package]] name = "socket2" version = "0.5.8" @@ -7607,7 +7813,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ "base64 0.13.1", - "bytes", + "bytes 1.9.0", "futures", "httparse", "log", @@ -8145,7 +8351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", - "itoa", + "itoa 1.0.14", "num-conv", "powerfmt", "serde", @@ -8203,6 +8409,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "iovec", + "lazy_static", + "memchr", + "mio 0.6.23", + "num_cpus", + "pin-project-lite 0.1.12", + "slab", +] + [[package]] name = "tokio" version = "1.41.1" @@ -8210,13 +8434,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", - "bytes", + "bytes 1.9.0", "libc", "mio 1.0.2", "parking_lot", - "pin-project-lite", + "pin-project-lite 0.2.15", "signal-hook-registry", - "socket2", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -8239,7 +8463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -8250,7 +8474,7 @@ checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" dependencies = [ "pin-project", "rand 0.8.5", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -8260,7 +8484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls 0.21.12", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -8271,7 +8495,7 @@ checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls 0.23.19", "rustls-pki-types", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -8283,7 +8507,7 @@ dependencies = [ "either", "futures-util", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", ] [[package]] @@ -8293,8 +8517,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.15", + "tokio 1.41.1", ] [[package]] @@ -8304,12 +8528,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" dependencies = [ "async-stream", - "bytes", + "bytes 1.9.0", "futures-core", - "tokio", + "tokio 1.41.1", "tokio-stream", ] +[[package]] +name = "tokio-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" +dependencies = [ + "native-tls", + "tokio 0.2.25", +] + [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -8318,22 +8552,36 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "tokio", + "tokio 1.41.1", "tungstenite", ] +[[package]] +name = "tokio-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +dependencies = [ + "bytes 0.5.6", + "futures-core", + "futures-sink", + "log", + "pin-project-lite 0.1.12", + "tokio 0.2.25", +] + [[package]] name = "tokio-util" version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ - "bytes", + "bytes 1.9.0", "futures-core", "futures-io", "futures-sink", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.15", + "tokio 1.41.1", ] [[package]] @@ -8379,7 +8627,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project", - "pin-project-lite", + "pin-project-lite 0.2.15", "tower-layer", "tower-service", "tracing", @@ -8393,9 +8641,9 @@ checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" dependencies = [ "futures-core", "futures-util", - "pin-project-lite", + "pin-project-lite 0.2.15", "sync_wrapper 0.1.2", - "tokio", + "tokio 1.41.1", "tower-layer", "tower-service", "tracing", @@ -8413,7 +8661,7 @@ dependencies = [ "futures-util", "http 1.1.0", "parking_lot", - "pin-project-lite", + "pin-project-lite 0.2.15", "tower-layer", "tower-service", ] @@ -8425,19 +8673,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "bitflags 2.6.0", - "bytes", + "bytes 1.9.0", "futures-util", "http 1.1.0", "http-body 1.0.1", "http-body-util", "http-range-header", - "httpdate", + "httpdate 1.0.3", "mime", "mime_guess", "percent-encoding", - "pin-project-lite", - "tokio", - "tokio-util", + "pin-project-lite 0.2.15", + "tokio 1.41.1", + "tokio-util 0.7.12", "tower-layer", "tower-service", "tracing", @@ -8464,7 +8712,7 @@ dependencies = [ "async-trait", "http 1.1.0", "time", - "tokio", + "tokio 1.41.1", "tower-cookies", "tower-layer", "tower-service", @@ -8490,7 +8738,7 @@ dependencies = [ "serde_json", "thiserror 1.0.69", "time", - "tokio", + "tokio 1.41.1", "tracing", ] @@ -8502,7 +8750,7 @@ checksum = "cec5f88eeef0f036e6900217034efbce733cbdf0528a85204eaaed90bc34c354" dependencies = [ "async-trait", "time", - "tokio", + "tokio 1.41.1", "tower-sessions-core", ] @@ -8513,7 +8761,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", - "pin-project-lite", + "pin-project-lite 0.2.15", "tracing-attributes", "tracing-core", ] @@ -8561,6 +8809,16 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -8631,7 +8889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", - "bytes", + "bytes 1.9.0", "data-encoding", "http 1.1.0", "httparse", @@ -8728,7 +8986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" dependencies = [ "asynchronous-codec 0.6.2", - "bytes", + "bytes 1.9.0", ] [[package]] @@ -8922,6 +9180,8 @@ checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if 1.0.0", "once_cell", + "serde", + "serde_json", "wasm-bindgen-macro", ] @@ -9009,7 +9269,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d920d06243e9f456c336c428a34560357dedf59d9febaae14f1995ac120cff6" dependencies = [ - "bytes", + "bytes 1.9.0", "cfg-if 1.0.0", "derivative", "indexmap 1.9.3", @@ -9039,7 +9299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e01832173aa52345e480965f18c638a8a5a9e5e4d85a48675bdf1964147dc7f" dependencies = [ "backtrace", - "bytes", + "bytes 1.9.0", "cfg-if 1.0.0", "enum-iterator", "enumset", @@ -9200,7 +9460,7 @@ checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" dependencies = [ "arrayvec 0.7.6", "base64 0.21.7", - "bytes", + "bytes 1.9.0", "derive_more", "ethabi", "ethereum-types", @@ -9221,9 +9481,9 @@ dependencies = [ "serde_json", "soketto", "tiny-keccak", - "tokio", + "tokio 1.41.1", "tokio-stream", - "tokio-util", + "tokio-util 0.7.12", "url", "web3-async-native-tls", ] @@ -9236,7 +9496,7 @@ checksum = "1f6d8d1636b2627fe63518d5a9b38a569405d9c9bc665c43c9c341de57227ebb" dependencies = [ "native-tls", "thiserror 1.0.69", - "tokio", + "tokio 1.41.1", "url", ] @@ -9264,7 +9524,7 @@ dependencies = [ "cfg-if 0.1.10", "libc", "memory_units", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -9273,6 +9533,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -9283,6 +9549,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -9572,6 +9844,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winreg" version = "0.50.0" @@ -9594,6 +9875,16 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "wslpath" version = "0.0.2" diff --git a/Cargo.toml b/Cargo.toml index 4013dd509..111625350 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,6 @@ members = [ "./contracts/icp/context-config", "./contracts/icp/context-proxy", - "./contracts/icp/context-proxy/mock/ledger", "./contracts/icp/context-proxy/mock/external", "./e2e-tests", diff --git a/contracts/icp/context-proxy/Cargo.toml b/contracts/icp/context-proxy/Cargo.toml index 6152e076d..cd81472b7 100644 --- a/contracts/icp/context-proxy/Cargo.toml +++ b/contracts/icp/context-proxy/Cargo.toml @@ -21,3 +21,5 @@ thiserror.workspace = true [dev-dependencies] pocket-ic = "6.0.0" rand = "0.8" +reqwest = { version = "0.10.10", features = ["blocking"] } +flate2 = "1.0.35" diff --git a/contracts/icp/context-proxy/dfx.json b/contracts/icp/context-proxy/dfx.json index fb8692c84..da878d82d 100644 --- a/contracts/icp/context-proxy/dfx.json +++ b/contracts/icp/context-proxy/dfx.json @@ -5,12 +5,6 @@ "candid": "./res/calimero_context_proxy_icp.did", "type": "rust" }, - "mock_ledger": { - "type": "rust", - "package": "calimero-mock-ledger-icp", - "candid": "./mock/ledger/res/calimero_mock_ledger_icp.did", - "path": "mock/ledger" - }, "mock_external": { "type": "rust", "package": "calimero-mock-external-icp", diff --git a/contracts/icp/context-proxy/mock/external/Cargo.toml b/contracts/icp/context-proxy/mock/external/Cargo.toml index 8a6b5993f..4dd47bcb8 100644 --- a/contracts/icp/context-proxy/mock/external/Cargo.toml +++ b/contracts/icp/context-proxy/mock/external/Cargo.toml @@ -10,3 +10,4 @@ crate-type = ["cdylib"] candid = "0.10" ic-cdk = "0.16" ic-cdk-macros = "0.16" +ic-ledger-types = "0.14.0" diff --git a/contracts/icp/context-proxy/mock/external/res/calimero_mock_external_icp.did b/contracts/icp/context-proxy/mock/external/res/calimero_mock_external_icp.did index 4057d383d..0aad69bcc 100644 --- a/contracts/icp/context-proxy/mock/external/res/calimero_mock_external_icp.did +++ b/contracts/icp/context-proxy/mock/external/res/calimero_mock_external_icp.did @@ -1 +1,6 @@ -service : { get_calls : () -> (vec blob) query; test_method : (blob) -> (blob) } +service : (principal) -> { + clear_state : () -> (); + get_calls : () -> (vec blob) query; + test_method : (blob) -> (blob); + test_method_no_transfer : (blob) -> (blob); +} diff --git a/contracts/icp/context-proxy/mock/external/src/lib.rs b/contracts/icp/context-proxy/mock/external/src/lib.rs index ca10b9152..f2886be72 100644 --- a/contracts/icp/context-proxy/mock/external/src/lib.rs +++ b/contracts/icp/context-proxy/mock/external/src/lib.rs @@ -1,15 +1,66 @@ use std::cell::RefCell; +use candid::Principal; +use ic_ledger_types::{AccountIdentifier, Subaccount, Tokens, TransferArgs, Memo, TransferError}; thread_local! { static CALLS: RefCell>> = RefCell::new(Vec::new()); + static LEDGER_ID: RefCell> = RefCell::new(None); +} + +#[ic_cdk::init] +fn init(ledger_id: Principal) { + LEDGER_ID.with(|id| { + *id.borrow_mut() = Some(ledger_id); + }); } #[ic_cdk::update] -fn test_method(args: Vec) -> Vec { +async fn test_method(args: Vec) -> Vec { + let self_id = ic_cdk::id(); + let caller = ic_cdk::caller(); + + let ledger_id = LEDGER_ID.with(|id| { + id.borrow().expect("Ledger ID not initialized") + }); + + // Prepare transfer args to move the approved tokens + let transfer_args = TransferArgs { + memo: Memo(0), + amount: Tokens::from_e8s(100_000_000), // Example amount, in practice this would be parsed from args + fee: Tokens::from_e8s(10_000), + from_subaccount: Some(Subaccount::from(caller)), + to: AccountIdentifier::new(&self_id, &Subaccount([0; 32])), + created_at_time: None, + }; + + // Execute the transfer with proper type annotations + let transfer_result: Result<(Result,), _> = + ic_cdk::call(ledger_id, "transfer", (transfer_args,)).await; + + match transfer_result { + Ok((Ok(_block_height),)) => { + // Transfer successful, record the call + CALLS.with(|calls| { + calls.borrow_mut().push(args.clone()); + }); + args // Return the same args back + }, + Ok((Err(transfer_error),)) => { + ic_cdk::trap(&format!("Transfer failed: {:?}", transfer_error)); + }, + Err(e) => { + ic_cdk::trap(&format!("Call to ledger failed: {:?}", e)); + } + } +} + +#[ic_cdk::update] +async fn test_method_no_transfer(args: Vec) -> Vec { + // Simply record the call and return CALLS.with(|calls| { calls.borrow_mut().push(args.clone()); - args // Return the same args back - }) + }); + args } #[ic_cdk::query] @@ -17,4 +68,10 @@ fn get_calls() -> Vec> { CALLS.with(|calls| calls.borrow().clone()) } +// Clear state (useful for testing) +#[ic_cdk::update] +fn clear_state() { + CALLS.with(|calls| calls.borrow_mut().clear()); +} + ic_cdk::export_candid!(); diff --git a/contracts/icp/context-proxy/mock/ledger/Cargo.toml b/contracts/icp/context-proxy/mock/ledger/Cargo.toml deleted file mode 100644 index df65c8b1d..000000000 --- a/contracts/icp/context-proxy/mock/ledger/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "calimero-mock-ledger-icp" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -candid = "0.10" -serde = { version = "1.0", features = ["derive"] } -ic-cdk = "0.16" -ic-cdk-macros = "0.16" -ic-ledger-types = "0.14.0" diff --git a/contracts/icp/context-proxy/mock/ledger/build.sh b/contracts/icp/context-proxy/mock/ledger/build.sh deleted file mode 100755 index d9d74e1ef..000000000 --- a/contracts/icp/context-proxy/mock/ledger/build.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -set -e - -cd "$(dirname $0)" - -TARGET="${CARGO_TARGET_DIR:-../../../../../target}" - -rustup target add wasm32-unknown-unknown - -cargo build --target wasm32-unknown-unknown --profile app-release - -mkdir -p res - -cp $TARGET/wasm32-unknown-unknown/app-release/calimero_mock_ledger_icp.wasm ./res/ - -if command -v wasm-opt > /dev/null; then - wasm-opt -Oz ./res/calimero_mock_ledger_icp.wasm -o ./res/calimero_mock_ledger_icp.wasm -fi - -if command -v candid-extractor > /dev/null; then - candid-extractor ./res/calimero_mock_ledger_icp.wasm > ./res/calimero_mock_ledger_icp.did -fi diff --git a/contracts/icp/context-proxy/mock/ledger/res/calimero_mock_ledger_icp.did b/contracts/icp/context-proxy/mock/ledger/res/calimero_mock_ledger_icp.did deleted file mode 100644 index 3b3ac2fd5..000000000 --- a/contracts/icp/context-proxy/mock/ledger/res/calimero_mock_ledger_icp.did +++ /dev/null @@ -1,23 +0,0 @@ -type AccountBalanceArgs = record { account : blob }; -type Result = variant { Ok : nat64; Err : TransferError }; -type Timestamp = record { timestamp_nanos : nat64 }; -type Tokens = record { e8s : nat64 }; -type TransferArgs = record { - to : blob; - fee : Tokens; - memo : nat64; - from_subaccount : opt blob; - created_at_time : opt Timestamp; - amount : Tokens; -}; -type TransferError = variant { - TxTooOld : record { allowed_window_nanos : nat64 }; - BadFee : record { expected_fee : Tokens }; - TxDuplicate : record { duplicate_of : nat64 }; - TxCreatedInFuture; - InsufficientFunds : record { balance : Tokens }; -}; -service : { - account_balance : (AccountBalanceArgs) -> (Tokens) query; - transfer : (TransferArgs) -> (Result); -} diff --git a/contracts/icp/context-proxy/mock/ledger/src/lib.rs b/contracts/icp/context-proxy/mock/ledger/src/lib.rs deleted file mode 100644 index e59ac3a83..000000000 --- a/contracts/icp/context-proxy/mock/ledger/src/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::cell::RefCell; - -use candid::{CandidType, Deserialize}; -use ic_ledger_types::{AccountIdentifier, BlockIndex, Tokens, TransferArgs, TransferError}; - -thread_local! { - static BALANCE: RefCell = RefCell::new(1_000_000_000); -} - -type TransferResult = Result; - -#[ic_cdk::update] -fn transfer(args: TransferArgs) -> TransferResult { - // ic_cdk::println!( - // "Mock ledger received transfer: to={:?}, amount={}", - // args.to, - // args.amount - // ); - - // Verify fee - if args.fee.e8s() != 10_000 { - return Err(TransferError::BadFee { - expected_fee: Tokens::from_e8s(10_000), - }); - } - - let amount_e8s = args.amount.e8s(); - - BALANCE.with(|balance| { - let mut bal = balance.borrow_mut(); - - // Check if we have enough balance - if amount_e8s > *bal { - return Err(TransferError::InsufficientFunds { - balance: Tokens::from_e8s(*bal), - }); - } - - // Subtract amount and fee - *bal = bal.saturating_sub(amount_e8s); - *bal = bal.saturating_sub(args.fee.e8s()); - - // ic_cdk::println!("New balance: {}", *bal); - - // Return mock block index - Ok(1) - }) -} - -#[ic_cdk::query] -fn account_balance(_args: AccountBalanceArgs) -> Tokens { - BALANCE.with(|balance| Tokens::from_e8s(*balance.borrow())) -} - -#[derive(CandidType, Deserialize)] -struct AccountBalanceArgs { - account: AccountIdentifier, -} - -ic_cdk::export_candid!(); diff --git a/contracts/icp/context-proxy/src/mutate.rs b/contracts/icp/context-proxy/src/mutate.rs index 1c9e721c5..7a85c2097 100644 --- a/contracts/icp/context-proxy/src/mutate.rs +++ b/contracts/icp/context-proxy/src/mutate.rs @@ -7,9 +7,9 @@ use calimero_context_config::icp::{ ICProxyMutateRequest, }; use calimero_context_config::types::{ProposalId, SignerId}; -use candid::Principal; +use candid::{Nat, Principal}; use ic_cdk::api::call::CallResult; -use ic_ledger_types::{AccountIdentifier, Memo, Subaccount, Tokens, TransferArgs, TransferError}; +use ic_ledger_types::{AccountIdentifier, Memo, Subaccount, Timestamp, Tokens, TransferArgs, TransferError}; use crate::{with_state, with_state_mut, ICProxyContract}; @@ -89,47 +89,74 @@ async fn execute_proposal(proposal_id: &ProposalId) -> Result<(), String> { args, deposit, } => { - // If there's a deposit, transfer it first if deposit > 0 { let ledger_id = with_state(|contract| contract.ledger_id.clone()); - let transfer_args = TransferArgs { - memo: Memo(0), - amount: Tokens::from_e8s( - deposit - .try_into() - .map_err(|e| format!("Amount conversion error: {}", e))?, - ), - fee: Tokens::from_e8s(10_000), // Standard fee is 0.0001 ICP - from_subaccount: None, - to: AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), - created_at_time: None, - }; - - // Call transfer and explicitly handle the result - let transfer_result: (Result,) = - ic_cdk::call(Principal::from(ledger_id), "transfer", (transfer_args,)) + // 1. First approve 0 + let approve_args = ( + None::, // from_subaccount + AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender + 0_u128, // amount (0) + None::, // expected_allowance + None::, // expires_at + None::, // memo + None::, // created_at_time + ); + + let (approve_result,): (Result,) = + ic_cdk::call(Principal::from(ledger_id), "icrc2_approve", approve_args) .await - .map_err(|e| format!("Transfer call failed: {:?}", e))?; - - // Check if the transfer was successful - match transfer_result.0 { - Ok(_block_height) => { - // Transfer succeeded, proceed with cross-contract call - } - Err(transfer_error) => { - return Err(format!("Transfer failed: {:?}", transfer_error)); - } - } + .map_err(|e| format!("Initial approve(0) failed: {:?}", e))?; + + approve_result.map_err(|e| format!("Initial approve(0) rejected: {}", e))?; + + // 2. Approve the deposit amount + let approve_args = ( + None::, // from_subaccount + AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender + deposit as u128, // amount + None::, // expected_allowance + None::, // expires_at + None::, // memo + None::, // created_at_time + ); + + let (approve_result,): (Result,) = + ic_cdk::call(Principal::from(ledger_id), "icrc2_approve", approve_args) + .await + .map_err(|e| format!("Approve deposit failed: {:?}", e))?; + + approve_result.map_err(|e| format!("Approve deposit rejected: {}", e))?; } - // Proceed with cross-contract call only if there was no deposit or transfer succeeded + // 3. Make the cross-contract call let args_bytes = candid::encode_one(args) .map_err(|e| format!("Failed to encode args: {}", e))?; let _: () = ic_cdk::call(receiver_id, method_name.as_str(), (args_bytes,)) .await .map_err(|e| format!("Inter-canister call failed: {:?}", e))?; + + // 4. Final approve(0) only if we did initial approvals + if deposit > 0 { + let ledger_id = with_state(|contract| contract.ledger_id.clone()); + let approve_args = ( + None::, // from_subaccount + AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender + 0_u128, // amount (0) + None::, // expected_allowance + None::, // expires_at + None::, // memo + None::, // created_at_time + ); + + let (approve_result,): (Result,) = + ic_cdk::call(Principal::from(ledger_id), "icrc2_approve", approve_args) + .await + .map_err(|e| format!("Approve deposit failed: {:?}", e))?; + + approve_result.map_err(|e| format!("Approve deposit rejected: {}", e))?; + } } ICProposalAction::Transfer { receiver_id, diff --git a/contracts/icp/context-proxy/tests/integration.rs b/contracts/icp/context-proxy/tests/integration.rs index 19bc71571..a84e2429f 100644 --- a/contracts/icp/context-proxy/tests/integration.rs +++ b/contracts/icp/context-proxy/tests/integration.rs @@ -10,11 +10,14 @@ use calimero_context_config::icp::{ }; use calimero_context_config::repr::ReprTransmute; use calimero_context_config::types::{ContextId, ContextIdentity}; -use candid::Principal; +use candid::{CandidType, Principal}; use ed25519_dalek::{Signer, SigningKey}; -use ic_ledger_types::{AccountBalanceArgs, AccountIdentifier, Subaccount, Tokens}; +use ic_ledger_types::{AccountBalanceArgs, AccountIdentifier, Memo, Subaccount, Tokens, TransferArgs, TransferError}; use pocket_ic::{PocketIc, WasmResult}; use rand::Rng; +use reqwest; +use flate2::read::GzDecoder; +use std::io::Read; // Mock canister states thread_local! { @@ -78,12 +81,79 @@ struct ProxyTestContext { mock_external: Principal, author_sk: SigningKey, context_id: ICRepr, + test_user: Principal, +} + +#[derive(CandidType)] +enum LedgerCanisterInit { + Init(LedgerCanisterInitPayload), +} + +#[derive(CandidType)] +struct LedgerCanisterInitPayload { + minting_account: String, + initial_values: Vec<(String, Tokens)>, + send_whitelist: Vec, + transfer_fee: Option, + token_symbol: Option, + token_name: Option, + archive_options: Option, +} + +#[derive(CandidType)] +struct ArchiveOptions { + trigger_threshold: u64, + num_blocks_to_archive: u64, + controller_id: Principal, } fn setup() -> ProxyTestContext { let pic = PocketIc::new(); let mut rng = rand::thread_rng(); + // Create test user principal first + let test_user = Principal::from_text( + "rrkah-fqaaa-aaaaa-aaaaq-cai" + ).unwrap(); + + // Setup ledger canister + let mock_ledger = pic.create_canister(); + pic.add_cycles(mock_ledger, 100_000_000_000_000_000); + + // Download the compressed ledger wasm + let compressed_wasm = reqwest::blocking::get( + "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz" + ).expect("Failed to download ledger wasm") + .bytes().expect("Failed to read ledger wasm bytes"); + + // Decompress the wasm file + let mut decoder = GzDecoder::new(&compressed_wasm[..]); + let mut ledger_wasm = Vec::new(); + decoder.read_to_end(&mut ledger_wasm).expect("Failed to decompress ledger wasm"); + + // Initialize ledger with the same args as in dfx.json + let init_args = LedgerCanisterInit::Init(LedgerCanisterInitPayload { + minting_account: "e8478037d13e48f9d43d28136328d0642e4ed680c8be9f08f0da98791740203c".to_string(), + initial_values: vec![( + AccountIdentifier::new(&test_user, &Subaccount([0; 32])).to_string(), + Tokens::from_e8s(100_000_000_000), + )], + send_whitelist: vec![test_user], // Add test_user to whitelist + transfer_fee: Some(Tokens::from_e8s(10_000)), + token_symbol: Some("LICP".to_string()), + token_name: Some("Local Internet Computer Protocol Token".to_string()), + archive_options: Some(ArchiveOptions { + trigger_threshold: 2000, + num_blocks_to_archive: 1000, + controller_id: Principal::from_text( + "bwmrp-pfufw-yvlwr-nwbuh-4ko7l-2fz7x-kt6gq-4d3mc-hzqsi-pfwmp-kqe" + ).unwrap(), + }), + }); + + let init_args = candid::encode_one(init_args).expect("Failed to encode ledger init args"); + pic.install_canister(mock_ledger, ledger_wasm, init_args, None); + // Setup context contract first let context_canister = pic.create_canister(); pic.add_cycles(context_canister, 100_000_000_000_000_000); @@ -91,22 +161,18 @@ fn setup() -> ProxyTestContext { .expect("failed to read context wasm"); pic.install_canister(context_canister, context_wasm, vec![], None); - // Setup mock ledger - let mock_ledger = pic.create_canister(); - pic.add_cycles(mock_ledger, 100_000_000_000_000); - let mock_ledger_wasm = std::fs::read("mock/ledger/res/calimero_mock_ledger_icp.wasm") - .expect("failed to read mock ledger wasm"); - pic.install_canister(mock_ledger, mock_ledger_wasm, vec![], None); - // Set proxy code in context contract set_proxy_code(&pic, context_canister, mock_ledger).expect("Failed to set proxy code"); - // Setup mock external + // Setup mock external with ledger ID let mock_external = pic.create_canister(); pic.add_cycles(mock_external, 100_000_000_000_000); let mock_external_wasm = std::fs::read("mock/external/res/calimero_mock_external_icp.wasm") .expect("failed to read mock external wasm"); - pic.install_canister(mock_external, mock_external_wasm, vec![], None); + + // Pass ledger ID during initialization + let init_args = candid::encode_one(mock_ledger).expect("Failed to encode ledger ID"); + pic.install_canister(mock_external, mock_external_wasm, init_args, None); // Create initial author key let author_sk = SigningKey::from_bytes(&rng.gen()); @@ -124,6 +190,7 @@ fn setup() -> ProxyTestContext { mock_external, author_sk, context_id, + test_user, } } @@ -450,7 +517,7 @@ fn test_create_proposal_external_call() { author_id, actions: vec![ICProposalAction::ExternalFunctionCall { receiver_id: Principal::anonymous(), - method_name: "test_method".to_string(), + method_name: "test_method_no_transfer".to_string(), args: "deadbeef".to_string(), deposit: 0, }], @@ -902,12 +969,45 @@ fn test_proposal_execution_transfer() { author_sk, context_canister, context_id, + test_user, .. } = setup(); + // First, seed the proxy with tokens + let seed_amount = 1_000_000; + let transfer_args = TransferArgs { + memo: Memo(0), + amount: Tokens::from_e8s(seed_amount), + fee: Tokens::from_e8s(10_000), + from_subaccount: None, + to: AccountIdentifier::new(&proxy_canister, &Subaccount([0; 32])), + created_at_time: None, + }; + + // Use test_user for the transfer since it has the tokens + let response = pic + .update_call( + mock_ledger, + test_user, + "transfer", + candid::encode_one(transfer_args).unwrap(), + ) + .expect("Failed to call transfer"); + + match response { + WasmResult::Reply(bytes) => { + let result: Result = + candid::decode_one(&bytes).expect("Failed to decode transfer result"); + match result { + Ok(block_height) => println!("Transfer successful at block height: {}", block_height), + Err(e) => panic!("Transfer failed: {:?}", e), + } + } + WasmResult::Reject(msg) => panic!("Transfer rejected: {}", msg), + } + // Get initial cycle balance let initial_cycle_balance = pic.cycle_balance(proxy_canister); - let initial_ledger_balance = MOCK_LEDGER_BALANCE.with(|b| *b.borrow()); // Setup signers let author_pk = author_sk.verifying_key(); @@ -1010,7 +1110,7 @@ fn test_proposal_execution_transfer() { } let args = AccountBalanceArgs { - account: AccountIdentifier::new(&Principal::anonymous(), &Subaccount([0; 32])), + account: AccountIdentifier::new(&mock_external, &Subaccount([0; 32])), }; let response = pic @@ -1026,13 +1126,11 @@ fn test_proposal_execution_transfer() { WasmResult::Reply(bytes) => { let balance: Tokens = candid::decode_one(&bytes).expect("Failed to decode balance"); let final_balance = balance.e8s(); - // Verify the transfer was executed + // Verify the transfer was executed - mock_external should have received exactly transfer_amount assert_eq!( final_balance, - initial_ledger_balance - .saturating_sub(transfer_amount as u64) - .saturating_sub(10_000), // Subtract both transfer amount and fee - "Transfer amount should be deducted from ledger balance" + u64::try_from(transfer_amount).unwrap(), // mock_external should have exactly the amount we transferred + "Receiver should have received the transfer amount" ); } _ => panic!("Unexpected response type"), @@ -1081,7 +1179,7 @@ fn test_proposal_execution_external_call() { author_id, actions: vec![ICProposalAction::ExternalFunctionCall { receiver_id: mock_external, - method_name: "test_method".to_string(), + method_name: "test_method_no_transfer".to_string(), args: test_args.clone(), deposit: 0, }], @@ -1205,8 +1303,8 @@ fn test_proposal_execution_external_call_with_deposit() { .. } = setup(); - // Get initial cycle balance let initial_cycle_balance = pic.cycle_balance(proxy_canister); + let initial_ledger_balance = MOCK_LEDGER_BALANCE.with(|b| *b.borrow()); let author_pk = author_sk.verifying_key(); let author_id = author_pk.rt().expect("infallible conversion"); @@ -1221,9 +1319,9 @@ fn test_proposal_execution_external_call_with_deposit() { let proposal_id = rng.gen::<[_; 32]>().rt().expect("infallible conversion"); - // Create external call proposal + // Create external call proposal with deposit let deposit_amount = 1_000_000; - let test_args = "01020304".to_string(); // Test arguments as string + let test_args = "01020304".to_string(); let proposal = ICProposal { id: proposal_id, author_id, @@ -1261,22 +1359,20 @@ fn test_proposal_execution_external_call_with_deposit() { let request = ICProxyMutateRequest::Approve { approval }; let signed_request = create_signed_request(&signer_sk, request); - let response = pic - .update_call( - proxy_canister, - Principal::anonymous(), - "mutate", - candid::encode_one(signed_request).unwrap(), - ) - .expect("Failed to approve proposal"); + let response = pic.update_call( + proxy_canister, + Principal::anonymous(), + "mutate", + candid::encode_one(signed_request).unwrap(), + ); match response { - WasmResult::Reply(bytes) => { + Ok(WasmResult::Reply(bytes)) => { let result: Result, String> = candid::decode_one(&bytes).expect("Failed to decode response"); - + if let Ok(None) = result { - // Proposal was executed, verify it's gone + // Verify proposal was executed and removed let query_response = pic .query_call( proxy_canister, @@ -1288,8 +1384,8 @@ fn test_proposal_execution_external_call_with_deposit() { match query_response { WasmResult::Reply(bytes) => { - let stored_proposal: Option = candid::decode_one(&bytes) - .expect("Failed to decode stored proposal"); + let stored_proposal: Option = + candid::decode_one(&bytes).expect("Failed to decode stored proposal"); assert!( stored_proposal.is_none(), "Proposal should be removed after execution" @@ -1297,63 +1393,62 @@ fn test_proposal_execution_external_call_with_deposit() { } WasmResult::Reject(msg) => panic!("Query rejected: {}", msg), } - } - } - WasmResult::Reject(msg) => panic!("Approval rejected: {}", msg), - } - } - // Verify the transfer was executed by checking mock ledger balance - let args = AccountBalanceArgs { - account: AccountIdentifier::new(&mock_external, &Subaccount([0; 32])), - }; + // Verify the external call was executed + let calls_response = pic + .query_call( + mock_external, + Principal::anonymous(), + "get_calls", + candid::encode_args(()).unwrap(), + ) + .expect("Query failed"); - let response = pic - .query_call( - mock_ledger, - Principal::anonymous(), - "account_balance", - candid::encode_one(args).unwrap(), - ) - .expect("Failed to query balance"); + match calls_response { + WasmResult::Reply(bytes) => { + let calls: Vec> = candid::decode_one(&bytes).expect("Failed to decode calls"); + assert_eq!(calls.len(), 1, "Should have exactly one call"); - match response { - WasmResult::Reply(bytes) => { - let balance: Tokens = candid::decode_one(&bytes).expect("Failed to decode balance"); - let gas_fee = 10_000; - assert_eq!( - balance.e8s(), - MOCK_LEDGER_BALANCE.with(|b| *b.borrow()) - deposit_amount as u64 - gas_fee as u64, - "External contract should have received the deposit" - ); - } - WasmResult::Reject(msg) => panic!("Balance query rejected: {}", msg), - } + let received_args: String = + candid::decode_one(&calls[0]).expect("Failed to decode call arguments"); + assert_eq!(received_args, test_args, "Call arguments should match"); + } + _ => panic!("Unexpected response type"), + } - // Verify the external call was executed - let response = pic - .query_call( - mock_external, - Principal::anonymous(), - "get_calls", - candid::encode_args(()).unwrap(), - ) - .expect("Query failed"); + // Verify the ledger balance changes + // The mock external contract should have received the deposit + let balance_args = AccountBalanceArgs { + account: AccountIdentifier::new(&mock_external, &Subaccount([0; 32])), + }; - match response { - WasmResult::Reply(bytes) => { - let calls: Vec> = candid::decode_one(&bytes).expect("Failed to decode calls"); - assert_eq!(calls.len(), 1, "Should have exactly one call"); + let balance_response = pic + .query_call( + mock_ledger, + Principal::anonymous(), + "account_balance", + candid::encode_one(balance_args).unwrap(), + ) + .expect("Failed to query balance"); - // Decode the Candid-encoded argument - let received_args: String = - candid::decode_one(&calls[0]).expect("Failed to decode call arguments"); - assert_eq!(received_args, test_args, "Call arguments should match"); + match balance_response { + WasmResult::Reply(bytes) => { + let balance: Tokens = candid::decode_one(&bytes).expect("Failed to decode balance"); + let expected_balance = initial_ledger_balance + deposit_amount as u64; + assert_eq!( + balance.e8s(), + expected_balance, + "External contract should have received the deposit" + ); + } + _ => panic!("Unexpected response type"), + } + } + } + _ => panic!("Unexpected response type"), } - _ => panic!("Unexpected response type"), } - // Get final cycle balance and calculate usage let final_cycle_balance = pic.cycle_balance(proxy_canister); let cycles_used = initial_cycle_balance - final_cycle_balance; println!("Cycles used: {}", cycles_used); From dcac96140de5dd394f06ac2e17ee69374548f715 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 13:22:19 +0100 Subject: [PATCH 16/27] fix: lint --- .../context-proxy/mock/external/src/lib.rs | 15 +++-- contracts/icp/context-proxy/src/mutate.rs | 58 +++++++++--------- .../icp/context-proxy/tests/integration.rs | 60 +++++++++++-------- 3 files changed, 71 insertions(+), 62 deletions(-) diff --git a/contracts/icp/context-proxy/mock/external/src/lib.rs b/contracts/icp/context-proxy/mock/external/src/lib.rs index f2886be72..f230e9c3d 100644 --- a/contracts/icp/context-proxy/mock/external/src/lib.rs +++ b/contracts/icp/context-proxy/mock/external/src/lib.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; + use candid::Principal; -use ic_ledger_types::{AccountIdentifier, Subaccount, Tokens, TransferArgs, Memo, TransferError}; +use ic_ledger_types::{AccountIdentifier, Memo, Subaccount, Tokens, TransferArgs, TransferError}; thread_local! { static CALLS: RefCell>> = RefCell::new(Vec::new()); @@ -18,10 +19,8 @@ fn init(ledger_id: Principal) { async fn test_method(args: Vec) -> Vec { let self_id = ic_cdk::id(); let caller = ic_cdk::caller(); - - let ledger_id = LEDGER_ID.with(|id| { - id.borrow().expect("Ledger ID not initialized") - }); + + let ledger_id = LEDGER_ID.with(|id| id.borrow().expect("Ledger ID not initialized")); // Prepare transfer args to move the approved tokens let transfer_args = TransferArgs { @@ -34,7 +33,7 @@ async fn test_method(args: Vec) -> Vec { }; // Execute the transfer with proper type annotations - let transfer_result: Result<(Result,), _> = + let transfer_result: Result<(Result,), _> = ic_cdk::call(ledger_id, "transfer", (transfer_args,)).await; match transfer_result { @@ -44,10 +43,10 @@ async fn test_method(args: Vec) -> Vec { calls.borrow_mut().push(args.clone()); }); args // Return the same args back - }, + } Ok((Err(transfer_error),)) => { ic_cdk::trap(&format!("Transfer failed: {:?}", transfer_error)); - }, + } Err(e) => { ic_cdk::trap(&format!("Call to ledger failed: {:?}", e)); } diff --git a/contracts/icp/context-proxy/src/mutate.rs b/contracts/icp/context-proxy/src/mutate.rs index 7a85c2097..a0042d387 100644 --- a/contracts/icp/context-proxy/src/mutate.rs +++ b/contracts/icp/context-proxy/src/mutate.rs @@ -9,7 +9,9 @@ use calimero_context_config::icp::{ use calimero_context_config::types::{ProposalId, SignerId}; use candid::{Nat, Principal}; use ic_cdk::api::call::CallResult; -use ic_ledger_types::{AccountIdentifier, Memo, Subaccount, Timestamp, Tokens, TransferArgs, TransferError}; +use ic_ledger_types::{ + AccountIdentifier, Memo, Subaccount, Timestamp, Tokens, TransferArgs, TransferError, +}; use crate::{with_state, with_state_mut, ICProxyContract}; @@ -94,38 +96,38 @@ async fn execute_proposal(proposal_id: &ProposalId) -> Result<(), String> { // 1. First approve 0 let approve_args = ( - None::, // from_subaccount - AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender - 0_u128, // amount (0) - None::, // expected_allowance - None::, // expires_at - None::, // memo - None::, // created_at_time + None::, // from_subaccount + AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender + 0_u128, // amount (0) + None::, // expected_allowance + None::, // expires_at + None::, // memo + None::, // created_at_time ); - let (approve_result,): (Result,) = + let (approve_result,): (Result,) = ic_cdk::call(Principal::from(ledger_id), "icrc2_approve", approve_args) .await .map_err(|e| format!("Initial approve(0) failed: {:?}", e))?; - + approve_result.map_err(|e| format!("Initial approve(0) rejected: {}", e))?; // 2. Approve the deposit amount let approve_args = ( - None::, // from_subaccount - AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender - deposit as u128, // amount - None::, // expected_allowance - None::, // expires_at - None::, // memo - None::, // created_at_time + None::, // from_subaccount + AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender + deposit as u128, // amount + None::, // expected_allowance + None::, // expires_at + None::, // memo + None::, // created_at_time ); - let (approve_result,): (Result,) = + let (approve_result,): (Result,) = ic_cdk::call(Principal::from(ledger_id), "icrc2_approve", approve_args) .await .map_err(|e| format!("Approve deposit failed: {:?}", e))?; - + approve_result.map_err(|e| format!("Approve deposit rejected: {}", e))?; } @@ -141,20 +143,20 @@ async fn execute_proposal(proposal_id: &ProposalId) -> Result<(), String> { if deposit > 0 { let ledger_id = with_state(|contract| contract.ledger_id.clone()); let approve_args = ( - None::, // from_subaccount - AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender - 0_u128, // amount (0) - None::, // expected_allowance - None::, // expires_at - None::, // memo - None::, // created_at_time + None::, // from_subaccount + AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])), // spender + 0_u128, // amount (0) + None::, // expected_allowance + None::, // expires_at + None::, // memo + None::, // created_at_time ); - let (approve_result,): (Result,) = + let (approve_result,): (Result,) = ic_cdk::call(Principal::from(ledger_id), "icrc2_approve", approve_args) .await .map_err(|e| format!("Approve deposit failed: {:?}", e))?; - + approve_result.map_err(|e| format!("Approve deposit rejected: {}", e))?; } } diff --git a/contracts/icp/context-proxy/tests/integration.rs b/contracts/icp/context-proxy/tests/integration.rs index a84e2429f..e1683e6d3 100644 --- a/contracts/icp/context-proxy/tests/integration.rs +++ b/contracts/icp/context-proxy/tests/integration.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::io::Read; use calimero_context_config::icp::repr::ICRepr; use calimero_context_config::icp::types::{ @@ -12,12 +13,13 @@ use calimero_context_config::repr::ReprTransmute; use calimero_context_config::types::{ContextId, ContextIdentity}; use candid::{CandidType, Principal}; use ed25519_dalek::{Signer, SigningKey}; -use ic_ledger_types::{AccountBalanceArgs, AccountIdentifier, Memo, Subaccount, Tokens, TransferArgs, TransferError}; +use flate2::read::GzDecoder; +use ic_ledger_types::{ + AccountBalanceArgs, AccountIdentifier, Memo, Subaccount, Tokens, TransferArgs, TransferError, +}; use pocket_ic::{PocketIc, WasmResult}; use rand::Rng; use reqwest; -use flate2::read::GzDecoder; -use std::io::Read; // Mock canister states thread_local! { @@ -112,33 +114,34 @@ fn setup() -> ProxyTestContext { let mut rng = rand::thread_rng(); // Create test user principal first - let test_user = Principal::from_text( - "rrkah-fqaaa-aaaaa-aaaaq-cai" - ).unwrap(); - + let test_user = Principal::from_text("rrkah-fqaaa-aaaaa-aaaaq-cai").unwrap(); + // Setup ledger canister let mock_ledger = pic.create_canister(); pic.add_cycles(mock_ledger, 100_000_000_000_000_000); - + // Download the compressed ledger wasm let compressed_wasm = reqwest::blocking::get( "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz" ).expect("Failed to download ledger wasm") .bytes().expect("Failed to read ledger wasm bytes"); - + // Decompress the wasm file let mut decoder = GzDecoder::new(&compressed_wasm[..]); let mut ledger_wasm = Vec::new(); - decoder.read_to_end(&mut ledger_wasm).expect("Failed to decompress ledger wasm"); - + decoder + .read_to_end(&mut ledger_wasm) + .expect("Failed to decompress ledger wasm"); + // Initialize ledger with the same args as in dfx.json let init_args = LedgerCanisterInit::Init(LedgerCanisterInitPayload { - minting_account: "e8478037d13e48f9d43d28136328d0642e4ed680c8be9f08f0da98791740203c".to_string(), + minting_account: "e8478037d13e48f9d43d28136328d0642e4ed680c8be9f08f0da98791740203c" + .to_string(), initial_values: vec![( AccountIdentifier::new(&test_user, &Subaccount([0; 32])).to_string(), Tokens::from_e8s(100_000_000_000), )], - send_whitelist: vec![test_user], // Add test_user to whitelist + send_whitelist: vec![test_user], // Add test_user to whitelist transfer_fee: Some(Tokens::from_e8s(10_000)), token_symbol: Some("LICP".to_string()), token_name: Some("Local Internet Computer Protocol Token".to_string()), @@ -146,8 +149,9 @@ fn setup() -> ProxyTestContext { trigger_threshold: 2000, num_blocks_to_archive: 1000, controller_id: Principal::from_text( - "bwmrp-pfufw-yvlwr-nwbuh-4ko7l-2fz7x-kt6gq-4d3mc-hzqsi-pfwmp-kqe" - ).unwrap(), + "bwmrp-pfufw-yvlwr-nwbuh-4ko7l-2fz7x-kt6gq-4d3mc-hzqsi-pfwmp-kqe", + ) + .unwrap(), }), }); @@ -169,7 +173,7 @@ fn setup() -> ProxyTestContext { pic.add_cycles(mock_external, 100_000_000_000_000); let mock_external_wasm = std::fs::read("mock/external/res/calimero_mock_external_icp.wasm") .expect("failed to read mock external wasm"); - + // Pass ledger ID during initialization let init_args = candid::encode_one(mock_ledger).expect("Failed to encode ledger ID"); pic.install_canister(mock_external, mock_external_wasm, init_args, None); @@ -996,10 +1000,12 @@ fn test_proposal_execution_transfer() { match response { WasmResult::Reply(bytes) => { - let result: Result = + let result: Result = candid::decode_one(&bytes).expect("Failed to decode transfer result"); match result { - Ok(block_height) => println!("Transfer successful at block height: {}", block_height), + Ok(block_height) => { + println!("Transfer successful at block height: {}", block_height) + } Err(e) => panic!("Transfer failed: {:?}", e), } } @@ -1129,7 +1135,7 @@ fn test_proposal_execution_transfer() { // Verify the transfer was executed - mock_external should have received exactly transfer_amount assert_eq!( final_balance, - u64::try_from(transfer_amount).unwrap(), // mock_external should have exactly the amount we transferred + u64::try_from(transfer_amount).unwrap(), // mock_external should have exactly the amount we transferred "Receiver should have received the transfer amount" ); } @@ -1370,7 +1376,7 @@ fn test_proposal_execution_external_call_with_deposit() { Ok(WasmResult::Reply(bytes)) => { let result: Result, String> = candid::decode_one(&bytes).expect("Failed to decode response"); - + if let Ok(None) = result { // Verify proposal was executed and removed let query_response = pic @@ -1384,8 +1390,8 @@ fn test_proposal_execution_external_call_with_deposit() { match query_response { WasmResult::Reply(bytes) => { - let stored_proposal: Option = - candid::decode_one(&bytes).expect("Failed to decode stored proposal"); + let stored_proposal: Option = candid::decode_one(&bytes) + .expect("Failed to decode stored proposal"); assert!( stored_proposal.is_none(), "Proposal should be removed after execution" @@ -1406,11 +1412,12 @@ fn test_proposal_execution_external_call_with_deposit() { match calls_response { WasmResult::Reply(bytes) => { - let calls: Vec> = candid::decode_one(&bytes).expect("Failed to decode calls"); + let calls: Vec> = + candid::decode_one(&bytes).expect("Failed to decode calls"); assert_eq!(calls.len(), 1, "Should have exactly one call"); - let received_args: String = - candid::decode_one(&calls[0]).expect("Failed to decode call arguments"); + let received_args: String = candid::decode_one(&calls[0]) + .expect("Failed to decode call arguments"); assert_eq!(received_args, test_args, "Call arguments should match"); } _ => panic!("Unexpected response type"), @@ -1433,7 +1440,8 @@ fn test_proposal_execution_external_call_with_deposit() { match balance_response { WasmResult::Reply(bytes) => { - let balance: Tokens = candid::decode_one(&bytes).expect("Failed to decode balance"); + let balance: Tokens = + candid::decode_one(&bytes).expect("Failed to decode balance"); let expected_balance = initial_ledger_balance + deposit_amount as u64; assert_eq!( balance.e8s(), From af88a831eafa37f11d8ac511a72f12e556fc5594 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 13:55:35 +0100 Subject: [PATCH 17/27] fix: removed mock_ledger build process --- contracts/icp/context-proxy/build_contracts.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/icp/context-proxy/build_contracts.sh b/contracts/icp/context-proxy/build_contracts.sh index a8d9cecd8..df10a76df 100755 --- a/contracts/icp/context-proxy/build_contracts.sh +++ b/contracts/icp/context-proxy/build_contracts.sh @@ -6,9 +6,6 @@ cd "$(dirname $0)" echo "Building proxy contract..." ./build.sh -echo "Building mock ledger contract..." -./mock/ledger/build.sh - echo "Building mock external contract..." ./mock/external/build.sh From ba80769a6a6ed0e2871e79e90af1465031e45672 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 14:35:52 +0100 Subject: [PATCH 18/27] feat: added automated script for devnet deployment --- contracts/icp/context-config/deploy_devnet.sh | 107 ++++++++++++++---- contracts/icp/context-config/dfx.json | 13 +-- 2 files changed, 90 insertions(+), 30 deletions(-) diff --git a/contracts/icp/context-config/deploy_devnet.sh b/contracts/icp/context-config/deploy_devnet.sh index 09fe336db..9f1166036 100755 --- a/contracts/icp/context-config/deploy_devnet.sh +++ b/contracts/icp/context-config/deploy_devnet.sh @@ -1,7 +1,62 @@ #!/bin/bash set -e -# Build both contracts +# Function to generate a new identity and return its principal +generate_identity() { + local name=$1 + dfx identity new "$name" --storage-mode=plaintext || true + dfx identity use "$name" + dfx identity get-principal +} + +# Function to get account ID from principal +get_account_id() { + local principal=$1 + dfx ledger account-id --of-principal "$principal" +} + +# Generate minting account +dfx identity new minting --storage-mode=plaintext || true +dfx identity use minting +MINTING_PRINCIPAL=$(dfx identity get-principal) +MINTING_ACCOUNT=$(get_account_id "$MINTING_PRINCIPAL") + +# Generate initial account +dfx identity new initial --storage-mode=plaintext || true +dfx identity use initial +INITIAL_PRINCIPAL=$(dfx identity get-principal) +INITIAL_ACCOUNT=$(get_account_id "$INITIAL_PRINCIPAL") + +# Generate archive controller account +dfx identity new archive --storage-mode=plaintext || true +dfx identity use archive +ARCHIVE_PRINCIPAL=$(dfx identity get-principal) + +# Switch back to default identity +dfx identity use default + +# Stop dfx and clean up all state +dfx stop +sleep 2 +rm -rf .dfx +rm -rf ~/.config/dfx/replica-configuration/ +rm -rf ~/.cache/dfinity/ +rm canister_ids.json + +# Start dfx with clean state +dfx start --clean --background +sleep 5 + +# Define canister IDs +CONTEXT_ID="br5f7-7uaaa-aaaaa-qaaca-cai" +LEDGER_ID="be2us-64aaa-aaaaa-qaabq-cai" + +# Create canisters +echo "Creating canisters..." +dfx canister create context_contract --specified-id "$CONTEXT_ID" +dfx canister create ledger --specified-id "$LEDGER_ID" + +# Build contracts echo "Building contracts..." cd "$(dirname $0)" ./build.sh @@ -9,30 +64,40 @@ cd ../context-proxy ./build.sh cd ../context-config -# Stop and start dfx -echo "Restarting dfx..." -dfx stop -dfx start --background --clean - -# Force remove existing canisters if they exist -echo "Cleaning up old canisters..." -dfx canister delete context_contract || true -dfx canister delete ledger || true - -# Create and deploy canisters -echo "Deploying contracts..." -dfx canister create --all --force -dfx deploy +# Prepare ledger initialization argument +LEDGER_INIT_ARG="(variant { Init = record { + minting_account = \"${MINTING_ACCOUNT}\"; + initial_values = vec { + record { \"${INITIAL_ACCOUNT}\"; record { e8s = 100_000_000_000 } } + }; + send_whitelist = vec {}; + transfer_fee = opt record { e8s = 10_000 }; + token_symbol = opt \"LICP\"; + token_name = opt \"Local Internet Computer Protocol Token\"; + archive_options = opt record { + trigger_threshold = 2000; + num_blocks_to_archive = 1000; + controller_id = principal \"${ARCHIVE_PRINCIPAL}\" + }; +} })" -# Get the proxy wasm -echo "Reading proxy WASM..." -PROXY_WASM=$(xxd -p ../context-proxy/res/calimero_context_proxy_icp.wasm | tr -d '\n') +# Build and install canisters +dfx build +dfx canister install context_contract --mode=install +dfx canister install ledger --mode=install --argument "$LEDGER_INIT_ARG" # Set proxy code in context config -echo "Setting proxy code in context config..." dfx canister call context_contract set_proxy_code "( - vec {$(echo $PROXY_WASM | sed 's/\([0-9a-f]\{2\}\)/0x\1;/g')}, + blob \"../context-proxy/res/calimero_context_proxy_icp.wasm\", principal \"$LEDGER_ID\" )" -echo "Deployment complete!" +# Print all relevant information at the end +echo -e "\n=== Deployment Summary ===" +echo "Context Contract ID: ${CONTEXT_ID}" +echo "Ledger Contract ID: ${LEDGER_ID}" +echo -e "\nAccount Information:" +echo "Minting Account: ${MINTING_ACCOUNT}" +echo "Initial Account: ${INITIAL_ACCOUNT}" +echo "Archive Principal: ${ARCHIVE_PRINCIPAL}" +echo -e "\nDeployment completed successfully!" diff --git a/contracts/icp/context-config/dfx.json b/contracts/icp/context-config/dfx.json index 1672662da..df23e83b8 100644 --- a/contracts/icp/context-config/dfx.json +++ b/contracts/icp/context-config/dfx.json @@ -3,19 +3,14 @@ "context_contract": { "package": "calimero-context-config-icp", "candid": "./res/calimero_context_config_icp.did", - "type": "rust" + "type": "rust", + "id": "br5f7-7uaaa-aaaaa-qaaca-cai" }, "ledger": { "type": "custom", "wasm": "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz", "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did", - "remote": { - "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did", - "id": { - "ic": "ryjl3-tyaaa-aaaaa-aaaba-cai" - } - }, - "init_arg": "(variant { Init = record { minting_account = \"62c39e7c2484a1a9aa0864f9fb402558537111c3e6db3c37f793ab460f137ae4\"; initial_values = vec {}; send_whitelist = vec {}; token_name = opt \"Internet Computer\"; token_symbol = opt \"ICP\"; transfer_fee = opt record { e8s = 10_000 }; archive_options = opt record { trigger_threshold = 2_000_000; num_blocks_to_archive = 1_000_000; controller_id = principal \"aaaaa-aa\"; cycles_for_archive_creation = opt (0 : nat64); node_max_memory_size_bytes = null; max_message_size_bytes = null }}})" + "id": "be2us-64aaa-aaaaa-qaabq-cai" } }, "defaults": { @@ -26,7 +21,7 @@ }, "networks": { "local": { - "bind": "127.0.0.1:8080", + "bind": "127.0.0.1:4943", "type": "persistent" } }, From a5f839d2154230640730a86011e16af06ecf18f1 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 14:41:47 +0100 Subject: [PATCH 19/27] fix: resolved issue with NEAR nonce --- contracts/near/context-config/tests/sandbox.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/near/context-config/tests/sandbox.rs b/contracts/near/context-config/tests/sandbox.rs index 73f9112ee..a524d1590 100644 --- a/contracts/near/context-config/tests/sandbox.rs +++ b/contracts/near/context-config/tests/sandbox.rs @@ -1371,7 +1371,7 @@ async fn test_storage_usage_matches_code_size() -> eyre::Result<()> { context_id, ContextRequestKind::UpdateProxyContract, )); - Request::new(alice_cx_id.rt()?, kind, 0) + Request::new(alice_cx_id.rt()?, kind, 1) }, |p| alice_cx_sk.sign(p), )?) From 42a9528bd384b3b2b7497c350e5430e9d1f87645 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 14:43:10 +0100 Subject: [PATCH 20/27] feat: added container_ids.json file to gitignore --- contracts/icp/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/icp/.gitignore b/contracts/icp/.gitignore index 1eb29a7ed..96e52d091 100644 --- a/contracts/icp/.gitignore +++ b/contracts/icp/.gitignore @@ -28,3 +28,4 @@ dist/ pocket-ic !**/res/*.did +**/canister_ids.json From df5b56f30b5839f2d3e669c9a63d73804a286917 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 14:58:58 +0100 Subject: [PATCH 21/27] fix: check if canister_ids.json file exists before trying to delete it --- contracts/icp/context-config/deploy_devnet.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/icp/context-config/deploy_devnet.sh b/contracts/icp/context-config/deploy_devnet.sh index 9f1166036..69d608d9b 100755 --- a/contracts/icp/context-config/deploy_devnet.sh +++ b/contracts/icp/context-config/deploy_devnet.sh @@ -37,15 +37,16 @@ dfx identity use default # Stop dfx and clean up all state dfx stop -sleep 2 rm -rf .dfx rm -rf ~/.config/dfx/replica-configuration/ rm -rf ~/.cache/dfinity/ -rm canister_ids.json +# Remove canister_ids.json if it exists +if [ -f "canister_ids.json" ]; then + rm canister_ids.json +fi # Start dfx with clean state dfx start --clean --background -sleep 5 # Define canister IDs CONTEXT_ID="br5f7-7uaaa-aaaaa-qaaca-cai" From 84ff731ebbe39d3bc05f1e9baf1e17c69601be7a Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Mon, 23 Dec 2024 16:36:44 +0100 Subject: [PATCH 22/27] fix: fixed getting proxy contract wasm content --- contracts/icp/context-config/deploy_devnet.sh | 31 ++++++++++++++++--- contracts/icp/context-proxy/dfx.json | 7 ++--- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/contracts/icp/context-config/deploy_devnet.sh b/contracts/icp/context-config/deploy_devnet.sh index 69d608d9b..60ff1f17a 100755 --- a/contracts/icp/context-config/deploy_devnet.sh +++ b/contracts/icp/context-config/deploy_devnet.sh @@ -87,11 +87,32 @@ dfx build dfx canister install context_contract --mode=install dfx canister install ledger --mode=install --argument "$LEDGER_INIT_ARG" -# Set proxy code in context config -dfx canister call context_contract set_proxy_code "( - blob \"../context-proxy/res/calimero_context_proxy_icp.wasm\", - principal \"$LEDGER_ID\" -)" +# Get the directory where the script is located +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Build path relative to the script location +WASM_FILE="${SCRIPT_DIR}/../context-proxy/res/calimero_context_proxy_icp.wasm" + +# Verify file exists +if [ ! -f "$WASM_FILE" ]; then + echo "Error: WASM file not found at: $WASM_FILE" + exit 1 +fi + +# Then modify the script to use a consistent reading method +WASM_CONTENTS=$(xxd -p "$WASM_FILE" | tr -d '\n' | sed 's/\(..\)/\\\1/g') + +TEMP_CMD=$(mktemp) +echo "( + blob \"${WASM_CONTENTS}\", + principal \"${LEDGER_ID}\" +)" > "$TEMP_CMD" + +# Execute the command using the temporary file +dfx canister call context_contract set_proxy_code --argument-file "$TEMP_CMD" + +# Clean up +rm "$TEMP_CMD" # Print all relevant information at the end echo -e "\n=== Deployment Summary ===" diff --git a/contracts/icp/context-proxy/dfx.json b/contracts/icp/context-proxy/dfx.json index da878d82d..1a5ef2754 100644 --- a/contracts/icp/context-proxy/dfx.json +++ b/contracts/icp/context-proxy/dfx.json @@ -20,11 +20,8 @@ }, "networks": { "local": { - "bind": "127.0.0.1:8080", - "type": "persistent", - "replica": { - "subnet_type": "system" - } + "bind": "127.0.0.1:4943", + "type": "persistent" } }, "output_env_file": ".env", From f99d9096fc0f86901fbba35fd15bf9c2fa5dd4c0 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Tue, 24 Dec 2024 09:44:59 +0100 Subject: [PATCH 23/27] fix: fixed fetching nonce encoding --- .../config/src/client/env/config/query/fetch_nonce.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/context/config/src/client/env/config/query/fetch_nonce.rs b/crates/context/config/src/client/env/config/query/fetch_nonce.rs index 6b1acbb63..83dc11b82 100644 --- a/crates/context/config/src/client/env/config/query/fetch_nonce.rs +++ b/crates/context/config/src/client/env/config/query/fetch_nonce.rs @@ -87,9 +87,8 @@ impl Method for FetchNonceRequest { let context_id = ICRepr::new(*self.context_id); let member_id = ICRepr::new(*self.member_id); - let payload = (context_id, member_id); - - Encode!(&payload).map_err(Into::into) + // Encode arguments separately + Encode!(&context_id, &member_id).map_err(Into::into) } fn decode(response: Vec) -> eyre::Result { From 95d0d1d4e71ddaee1112a9a9c1655485fcc34dc8 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Thu, 26 Dec 2024 14:07:37 +0100 Subject: [PATCH 24/27] fix: updated script for devnet deployment, adjusted initial context contract principal, removed static IDs of canisters --- contracts/icp/context-config/deploy_devnet.sh | 76 ++++++++++++++----- contracts/icp/context-config/dfx.json | 10 ++- crates/merod/src/cli/init.rs | 2 +- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/contracts/icp/context-config/deploy_devnet.sh b/contracts/icp/context-config/deploy_devnet.sh index 60ff1f17a..877b66f3c 100755 --- a/contracts/icp/context-config/deploy_devnet.sh +++ b/contracts/icp/context-config/deploy_devnet.sh @@ -15,6 +15,27 @@ get_account_id() { dfx ledger account-id --of-principal "$principal" } +echo "Checking dependencies..." +command -v dfx >/dev/null 2>&1 || { echo "dfx is required but not installed. Aborting." >&2; exit 1; } +command -v cargo >/dev/null 2>&1 || { echo "cargo is required but not installed. Aborting." >&2; exit 1; } + +dfxvm default 0.24.3 + +# Stop dfx and clean up all state +dfx stop +rm -rf .dfx +rm -rf ~/.config/dfx/replica-configuration/ +rm -rf ~/.config/dfx/identity/minting +rm -rf ~/.config/dfx/identity/initial +rm -rf ~/.config/dfx/identity/archive +rm -rf ~/.cache/dfinity/ +rm -rf ~/.config/dfx/ +dfxvm default 0.24.3 +# Remove canister_ids.json if it exists +if [ -f "canister_ids.json" ]; then + rm canister_ids.json +fi + # Generate minting account dfx identity new minting --storage-mode=plaintext || true dfx identity use minting @@ -35,27 +56,38 @@ ARCHIVE_PRINCIPAL=$(dfx identity get-principal) # Switch back to default identity dfx identity use default -# Stop dfx and clean up all state -dfx stop -rm -rf .dfx -rm -rf ~/.config/dfx/replica-configuration/ -rm -rf ~/.cache/dfinity/ -# Remove canister_ids.json if it exists -if [ -f "canister_ids.json" ]; then - rm canister_ids.json -fi - # Start dfx with clean state dfx start --clean --background -# Define canister IDs -CONTEXT_ID="br5f7-7uaaa-aaaaa-qaaca-cai" -LEDGER_ID="be2us-64aaa-aaaaa-qaabq-cai" +dfx identity use default + +# Create initial identity if needed +dfx identity new --storage-mode=plaintext minting || true +# dfx identity use minting + +echo "Creating and deploying canister..." +dfx canister create context_contract +dfx canister create ledger -# Create canisters -echo "Creating canisters..." -dfx canister create context_contract --specified-id "$CONTEXT_ID" -dfx canister create ledger --specified-id "$LEDGER_ID" +# Get the context ID +CONTEXT_ID=$(dfx canister id context_contract) +echo "Context ID: $CONTEXT_ID" + +# Get the wallet ID and seed it +WALLET_ID=$(dfx identity get-wallet) +echo "Wallet ID: $WALLET_ID" + +# abricate cycles for the wallet +dfx ledger fabricate-cycles --canister $WALLET_ID --amount 200000 + +# Transfer cycles from wallet to context contract +dfx canister deposit-cycles 1000000000000000000 $CONTEXT_ID + +echo "Done! Cycles transferred to context contract: $CONTEXT_ID" + +# Get the IDs +CONTEXT_ID=$(dfx canister id context_contract) +LEDGER_ID=$(dfx canister id ledger) # Build contracts echo "Building contracts..." @@ -114,6 +146,16 @@ dfx canister call context_contract set_proxy_code --argument-file "$TEMP_CMD" # Clean up rm "$TEMP_CMD" +# # First top up the wallet with extra buffer +# dfx canister deposit-cycles 3000000000000000 $(dfx identity get-wallet) # 3000T cycles + +# # Then top up the context contract with enough for 100+ proxies +# dfx canister deposit-cycles 200000000000000 context_contract # 200T cycles + +# # Get the canister ID first +# CONTEXT_ID=$(dfx canister id context_contract) +# dfx canister deposit-cycles 1000000000000000 $CONTEXT_ID # 100T cycles + # Print all relevant information at the end echo -e "\n=== Deployment Summary ===" echo "Context Contract ID: ${CONTEXT_ID}" diff --git a/contracts/icp/context-config/dfx.json b/contracts/icp/context-config/dfx.json index df23e83b8..5b70ce5d6 100644 --- a/contracts/icp/context-config/dfx.json +++ b/contracts/icp/context-config/dfx.json @@ -3,14 +3,12 @@ "context_contract": { "package": "calimero-context-config-icp", "candid": "./res/calimero_context_config_icp.did", - "type": "rust", - "id": "br5f7-7uaaa-aaaaa-qaaca-cai" + "type": "rust" }, "ledger": { "type": "custom", "wasm": "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz", - "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did", - "id": "be2us-64aaa-aaaaa-qaabq-cai" + "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did" } }, "defaults": { @@ -25,5 +23,9 @@ "type": "persistent" } }, + "routing_table": { + "start_canister_id": "aaaaa-aa", + "end_canister_id": "zzzzz-zz" + }, "version": 1 } diff --git a/crates/merod/src/cli/init.rs b/crates/merod/src/cli/init.rs index 4d66d5c3b..9dbb00800 100644 --- a/crates/merod/src/cli/init.rs +++ b/crates/merod/src/cli/init.rs @@ -299,7 +299,7 @@ impl InitCommand { "0x1b991ee006e2d1e372ab96d0a957401fa200358f317b681df2948f30e17c29c" .parse()? } - ConfigProtocol::Icp => "br5f7-7uaaa-aaaaa-qaaca-cai".parse()?, + ConfigProtocol::Icp => "bkyz2-fmaaa-aaaaa-qaaaq-cai".parse()?, }, }, }, From 5fb103ddc6b910d094d090b78d146ba9ed4438c3 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Thu, 26 Dec 2024 14:32:24 +0100 Subject: [PATCH 25/27] feat: implemented endpoint for fetching proxy contract ID --- crates/context/src/lib.rs | 11 ++++++++++ crates/server/src/admin/handlers/proposals.rs | 21 +++++++++++++++++++ crates/server/src/admin/service.rs | 6 +++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/context/src/lib.rs b/crates/context/src/lib.rs index c322c4487..61c77ef37 100644 --- a/crates/context/src/lib.rs +++ b/crates/context/src/lib.rs @@ -1421,4 +1421,15 @@ impl ContextManager { .map_err(|err| eyre::eyre!("Failed to fetch context storage entries: {}", err))?; Ok(response) } + + pub async fn get_proxy_id(&self, context_id: ContextId) -> EyreResult { + let handle = self.store.handle(); + let Some(context_config) = handle.get(&ContextConfigKey::new(context_id))? else { + bail!("Context not found"); + }; + + let proxy_contract = context_config.proxy_contract.as_ref().into(); + + Ok(proxy_contract) + } } diff --git a/crates/server/src/admin/handlers/proposals.rs b/crates/server/src/admin/handlers/proposals.rs index a8e8e4e7f..2edec97b6 100644 --- a/crates/server/src/admin/handlers/proposals.rs +++ b/crates/server/src/admin/handlers/proposals.rs @@ -110,6 +110,12 @@ pub struct GetProposalResponse { pub data: ProposalConfig, } +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetProxyContractResponse { + pub data: String, +} + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct GetProposalsRequest { @@ -181,6 +187,21 @@ pub async fn get_proposal_handler( } } +pub async fn get_proxy_contract_handler( + Path(context_id): Path, + Extension(state): Extension>, +) -> impl IntoResponse { + match state.ctx_manager.get_proxy_id(context_id).await { + Ok(proxy_contract) => ApiResponse { + payload: GetProxyContractResponse { + data: proxy_contract, + }, + } + .into_response(), + Err(err) => parse_api_error(err).into_response(), + } +} + pub async fn get_context_value_handler( Path(context_id): Path, Extension(state): Extension>, diff --git a/crates/server/src/admin/service.rs b/crates/server/src/admin/service.rs index f31e31d1a..567df78e6 100644 --- a/crates/server/src/admin/service.rs +++ b/crates/server/src/admin/service.rs @@ -22,7 +22,7 @@ use super::handlers::did::delete_did_handler; use super::handlers::proposals::{ get_context_storage_entries_handler, get_context_value_handler, get_number_of_active_proposals_handler, get_number_of_proposal_approvals_handler, - get_proposal_approvers_handler, get_proposal_handler, get_proposals_handler, + get_proposal_approvers_handler, get_proposal_handler, get_proposals_handler, get_proxy_contract_handler, }; use super::storage::ssl::get_ssl; use crate::admin::handlers::add_client_key::{ @@ -173,6 +173,10 @@ pub(crate) fn setup( .route( "/contexts/:context_id/proposals/context-storage-entries", post(get_context_storage_entries_handler), + ) + .route( + "/contexts/:context_id/proxy-contract", + get(get_proxy_contract_handler), ); let dev_router = Router::new() From 5ee39c9caa2d7106fc5b4aee8db3d19133e16055 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Thu, 26 Dec 2024 14:32:43 +0100 Subject: [PATCH 26/27] fix: lint --- crates/server/src/admin/service.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/server/src/admin/service.rs b/crates/server/src/admin/service.rs index 567df78e6..215a612f6 100644 --- a/crates/server/src/admin/service.rs +++ b/crates/server/src/admin/service.rs @@ -22,7 +22,8 @@ use super::handlers::did::delete_did_handler; use super::handlers::proposals::{ get_context_storage_entries_handler, get_context_value_handler, get_number_of_active_proposals_handler, get_number_of_proposal_approvals_handler, - get_proposal_approvers_handler, get_proposal_handler, get_proposals_handler, get_proxy_contract_handler, + get_proposal_approvers_handler, get_proposal_handler, get_proposals_handler, + get_proxy_contract_handler, }; use super::storage::ssl::get_ssl; use crate::admin::handlers::add_client_key::{ From 8912db40668fe77d9c7301158630feedd89ed25f Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Thu, 26 Dec 2024 14:37:17 +0100 Subject: [PATCH 27/27] fix: cleaned deployment script and created test recipient account --- contracts/icp/context-config/deploy_devnet.sh | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/contracts/icp/context-config/deploy_devnet.sh b/contracts/icp/context-config/deploy_devnet.sh index 877b66f3c..ec6a63905 100755 --- a/contracts/icp/context-config/deploy_devnet.sh +++ b/contracts/icp/context-config/deploy_devnet.sh @@ -53,6 +53,11 @@ dfx identity new archive --storage-mode=plaintext || true dfx identity use archive ARCHIVE_PRINCIPAL=$(dfx identity get-principal) +# Generate test recipient account +dfx identity new recipient --storage-mode=plaintext || true +dfx identity use recipient +RECIPIENT_PRINCIPAL=$(dfx identity get-principal) + # Switch back to default identity dfx identity use default @@ -71,11 +76,8 @@ dfx canister create ledger # Get the context ID CONTEXT_ID=$(dfx canister id context_contract) -echo "Context ID: $CONTEXT_ID" - # Get the wallet ID and seed it WALLET_ID=$(dfx identity get-wallet) -echo "Wallet ID: $WALLET_ID" # abricate cycles for the wallet dfx ledger fabricate-cycles --canister $WALLET_ID --amount 200000 @@ -146,16 +148,6 @@ dfx canister call context_contract set_proxy_code --argument-file "$TEMP_CMD" # Clean up rm "$TEMP_CMD" -# # First top up the wallet with extra buffer -# dfx canister deposit-cycles 3000000000000000 $(dfx identity get-wallet) # 3000T cycles - -# # Then top up the context contract with enough for 100+ proxies -# dfx canister deposit-cycles 200000000000000 context_contract # 200T cycles - -# # Get the canister ID first -# CONTEXT_ID=$(dfx canister id context_contract) -# dfx canister deposit-cycles 1000000000000000 $CONTEXT_ID # 100T cycles - # Print all relevant information at the end echo -e "\n=== Deployment Summary ===" echo "Context Contract ID: ${CONTEXT_ID}" @@ -164,4 +156,5 @@ echo -e "\nAccount Information:" echo "Minting Account: ${MINTING_ACCOUNT}" echo "Initial Account: ${INITIAL_ACCOUNT}" echo "Archive Principal: ${ARCHIVE_PRINCIPAL}" +echo "Recipient Principal: ${RECIPIENT_PRINCIPAL}" echo -e "\nDeployment completed successfully!"