From 2cc1eead498aff33f9b9ae26cf6c54ad671c70e8 Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Wed, 18 Dec 2024 15:51:21 +0900 Subject: [PATCH 1/6] Adopt pubkey voted by two dns providers --- src/dns_client/src/lib.rs | 356 +++++++++--------- src/ic_dns_oracle_backend/src/lib.rs | 515 ++++++--------------------- 2 files changed, 285 insertions(+), 586 deletions(-) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index e275c66..e43fc41 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use base64::{engine::general_purpose, Engine as _}; use candid::Nat; use ic_cdk::api::management_canister::http_request::{ @@ -54,15 +56,15 @@ pub async fn get_dkim_public_key( return Err("Invalid selector".to_string()); } - #[cfg(not(debug_assertions))] + // #[cfg(not(debug_assertions))] let prefixes = vec![ "https://dns.google/resolve", "https://cloudflare-dns.com/dns-query", "https://dns.nextdns.io/dns-query", ]; - #[cfg(debug_assertions)] - let prefixes = vec!["https://dns.google/resolve"]; + // #[cfg(debug_assertions)] + // let prefixes = vec!["https://dns.google/resolve"]; let seed = ic_cdk::api::time() as usize % prefixes.len(); let mut shuffled_prefixes = vec![]; @@ -70,7 +72,8 @@ pub async fn get_dkim_public_key( shuffled_prefixes.push(prefixes[(seed + i) % prefixes.len()]); } - let mut errors = vec![]; + let mut logs = vec![]; + let mut pubkey_votes = vec![]; for prefix in shuffled_prefixes { let request = _construct_request(prefix, &selector, &domain); match http_request(request, cycle as u128).await { @@ -81,23 +84,34 @@ pub async fn get_dkim_public_key( "[Access to {prefix}] The response status is {}.", response.status ); - errors.push(message); + logs.push(message); continue; } let pubkey_hex = "0x".to_string() + &hex::encode(&response.body); - return Ok(pubkey_hex); + // if the same pubkey is voted by two different dns resolvers, the same pubkey should be contained in pubkey_votes. + if pubkey_votes.contains(&pubkey_hex) { + return Ok(pubkey_hex); + } else { + pubkey_votes.push(pubkey_hex); + } + let message: String = format!( + "[Access to {prefix}] The response status is {}.", + response.status + ); + logs.push(message); + continue; } Err((r, m)) => { let message = format!( "[Access to {prefix}] The http_request resulted into error. RejectionCode: {r:?}, Error: {m}." ); - errors.push(message); + logs.push(message); continue; } } } // Return the error as a string and end the method. - return Err(errors.join("\n")); + return Err(logs.join("\n")); } /// Transforms the raw HTTP response into a structured `HttpResponse`. @@ -248,26 +262,12 @@ mod test { use candid::{decode_one, Encode, Principal}; use pocket_ic::{ common::rest::{CanisterHttpReply, CanisterHttpResponse, MockCanisterHttpResponse}, - PocketIcBuilder, WasmResult, + PocketIc, PocketIcBuilder, WasmResult, }; #[test] - fn test_dns_client_gmail() { - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create an empty canister as the anonymous principal and add cycles. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(canister_id, 2_000_000_000_000); - let wasm_bytes = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); - pic.install_canister(canister_id, wasm_bytes, vec![], None); + fn test_dns_client_gmail_two_responses() { + let (pic, canister_id) = test_setup(); // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. let call_id = pic @@ -278,14 +278,7 @@ mod test { Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), ) .unwrap(); - // We need a pair of ticks for the test canister method to make the http outcall - // and for the management canister to start processing the http outcall. - pic.tick(); - pic.tick(); - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; - println!("{:?}", canister_http_request); + let body = r#" { "Status": 0, @@ -311,17 +304,9 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); // Now the test canister will receive the http outcall response // and reply to the ingress message from the test driver. @@ -339,23 +324,8 @@ mod test { } #[test] - fn test_dns_client_expect_error_no_answer() { - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create an empty canister as the anonymous principal and add cycles. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(canister_id, 2_000_000_000_000); - let wasm_bytes = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); - pic.install_canister(canister_id, wasm_bytes, vec![], None); - + fn test_dns_client_gmail_single_answer() { + let (pic, canister_id) = test_setup(); // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. let call_id = pic @@ -366,13 +336,100 @@ mod test { Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), ) .unwrap(); - // We need a pair of ticks for the test canister method to make the http outcall - // and for the management canister to start processing the http outcall. + + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16 + } + ], + "Answer": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16, + "TTL": 3600, + "data": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAntvSKT1hkqhKe0xcaZ0x+QbouDsJuBfby/S82jxsoC/SodmfmVs2D1KAH3mi1AqdMdU12h2VfETeOJkgGYq5ljd996AJ7ud2SyOLQmlhaNHH7Lx+Mdab8/zDN1SdxPARDgcM7AsRECHwQ15R20FaKUABGu4NTbR2fDKnYwiq5jQyBkLWP+LgGOgfUF4T4HZb2PY2bQtEP6QeqOtcW4rrsH24L7XhD+HSZb1hsitrE0VPbhJzxDwI4JF815XMnSVjZgYUXP8CxI1Y0FONlqtQYgsorZ9apoW1KPQe8brSSlRsi9sXB/tu56LmG7tEDNmrZ5XUwQYUUADBOu7t1niwXwIDAQAB" + } + ], + "Comment": "Response from 216.239.32.10." + } + "#; + mock_http_response(&pic, body); pic.tick(); + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16 + } + ], + "Comment": "Response from 216.239.32.10." + } + "#; + mock_http_response(&pic, body); pic.tick(); + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16 + } + ], + "Comment": "Response from 216.239.32.10." + } + "#; + mock_http_response(&pic, body); + // Now the test canister will receive the http outcall response + // and reply to the ingress message from the test driver. + let reply = pic.await_call(call_id).unwrap(); + match reply { + WasmResult::Reply(data) => { + let http_response: Result = decode_one(&data).unwrap(); + assert!(http_response.is_err()); + } + WasmResult::Reject(msg) => panic!("Unexpected reject {}", msg), + }; + // There should be no more pending canister http outcalls. let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; + assert_eq!(canister_http_requests.len(), 0); + } + + #[test] + fn test_dns_client_expect_error_no_answer() { + let (pic, canister_id) = test_setup(); + // Submit an update call to the test canister making a canister http outcall + // and mock a canister http outcall response. + let call_id = pic + .submit_call( + canister_id, + Principal::anonymous(), + "get_dkim_public_key", + Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), + ) + .unwrap(); + let body = r#" { "Status": 0, @@ -390,17 +447,11 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); // Now the test canister will receive the http outcall response // and reply to the ingress message from the test driver. @@ -419,22 +470,7 @@ mod test { #[test] fn test_dns_client_expect_error_invalid_key_type() { - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create an empty canister as the anonymous principal and add cycles. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(canister_id, 2_000_000_000_000); - let wasm_bytes = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); - pic.install_canister(canister_id, wasm_bytes, vec![], None); - + let (pic, canister_id) = test_setup(); // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. let call_id = pic @@ -445,13 +481,7 @@ mod test { Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), ) .unwrap(); - // We need a pair of ticks for the test canister method to make the http outcall - // and for the management canister to start processing the http outcall. - pic.tick(); - pic.tick(); - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; + let body = r#" { "Status": 0, @@ -477,17 +507,11 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); // Now the test canister will receive the http outcall response // and reply to the ingress message from the test driver. @@ -506,21 +530,7 @@ mod test { #[test] fn test_dns_client_expect_error_invalid_base64_format() { - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create an empty canister as the anonymous principal and add cycles. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(canister_id, 2_000_000_000_000); - let wasm_bytes = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); - pic.install_canister(canister_id, wasm_bytes, vec![], None); + let (pic, canister_id) = test_setup(); // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. @@ -532,13 +542,7 @@ mod test { Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), ) .unwrap(); - // We need a pair of ticks for the test canister method to make the http outcall - // and for the management canister to start processing the http outcall. - pic.tick(); - pic.tick(); - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; + let body = r#" { "Status": 0, @@ -564,17 +568,11 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); // Now the test canister will receive the http outcall response // and reply to the ingress message from the test driver. @@ -593,21 +591,7 @@ mod test { #[test] fn test_dns_client_expect_error_invalid_selector() { - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create an empty canister as the anonymous principal and add cycles. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(canister_id, 2_000_000_000_000); - let wasm_bytes = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); - pic.install_canister(canister_id, wasm_bytes, vec![], None); + let (pic, canister_id) = test_setup(); // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. @@ -640,21 +624,7 @@ mod test { #[test] fn test_dns_client_expect_error_invalid_domain() { - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create an empty canister as the anonymous principal and add cycles. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(canister_id, 2_000_000_000_000); - let wasm_bytes = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); - pic.install_canister(canister_id, wasm_bytes, vec![], None); + let (pic, canister_id) = test_setup(); // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. @@ -684,4 +654,44 @@ mod test { let canister_http_requests = pic.get_canister_http(); assert_eq!(canister_http_requests.len(), 0); } + + fn test_setup() -> (PocketIc, Principal) { + let pic = PocketIcBuilder::new() + .with_nns_subnet() + .with_ii_subnet() // this subnet has ECDSA keys + .with_application_subnet() + .build(); + + let topology = pic.topology(); + let app_subnet = topology.get_app_subnets()[0]; + + // Create an empty canister as the anonymous principal and add cycles. + let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + pic.add_cycles(canister_id, 2_000_000_000_000); + let wasm_bytes = + include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(); + pic.install_canister(canister_id, wasm_bytes, vec![], None); + (pic, canister_id) + } + + fn mock_http_response(pic: &PocketIc, body: &str) { + // We need a pair of ticks for the test canister method to make the http outcall + // and for the management canister to start processing the http outcall. + pic.tick(); + pic.tick(); + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 1); + let canister_http_request = &canister_http_requests[0]; + let mock_canister_http_response = MockCanisterHttpResponse { + subnet_id: canister_http_request.subnet_id, + request_id: canister_http_request.request_id, + response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { + status: 200, + headers: vec![], + body: body.as_bytes().to_vec(), + }), + additional_responses: vec![], + }; + pic.mock_canister_http_response(mock_canister_http_response); + } } diff --git a/src/ic_dns_oracle_backend/src/lib.rs b/src/ic_dns_oracle_backend/src/lib.rs index 2217ce2..d579f92 100644 --- a/src/ic_dns_oracle_backend/src/lib.rs +++ b/src/ic_dns_oracle_backend/src/lib.rs @@ -667,7 +667,7 @@ mod test { use libsecp256k1; use pocket_ic::{ common::rest::{CanisterHttpReply, CanisterHttpResponse, MockCanisterHttpResponse}, - PocketIcBuilder, WasmResult, + PocketIc, PocketIcBuilder, WasmResult, }; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::pkcs1::EncodeRsaPublicKey; @@ -692,52 +692,7 @@ mod test { #[test] fn test_sign_gmail() { - // We create a PocketIC instance consisting of the NNS, II, and one application subnet. - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - // We retrieve the app subnet ID from the topology. - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create empty canisters as the anonymous principal and add cycles. - let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); - let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); - // We create a canister on the app subnet. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); - pic.add_cycles(canister_id, 2_000_000_000_000); - pic.install_canister( - poseidon_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - dns_client_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - canister_id, - include_bytes!( - "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" - ) - .to_vec(), - Encode!( - &Some(Environment::Production), - &poseidon_canister_id.to_string(), - &dns_client_canister_id.to_string() - ) - .unwrap(), - None, - ); + let (pic, canister_id) = test_setup(); // Init the signer's ethereum address. let call_id = pic @@ -769,12 +724,6 @@ mod test { ) .unwrap(); - pic.tick(); - pic.tick(); - - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; let body = r#" { "Status": 0, @@ -800,17 +749,9 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, body); + pic.tick(); + mock_http_response(&pic, body); // // Now the test canister will receive the http outcall response // // and reply to the ingress message from the test driver. @@ -855,52 +796,7 @@ mod test { #[test] fn test_sign_gappssmtp() { - // We create a PocketIC instance consisting of the NNS, II, and one application subnet. - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - // We retrieve the app subnet ID from the topology. - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create empty canisters as the anonymous principal and add cycles. - let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); - let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); - // We create a canister on the app subnet. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); - pic.add_cycles(canister_id, 2_000_000_000_000); - pic.install_canister( - poseidon_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - dns_client_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - canister_id, - include_bytes!( - "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" - ) - .to_vec(), - Encode!( - &Some(Environment::Production), - &poseidon_canister_id.to_string(), - &dns_client_canister_id.to_string() - ) - .unwrap(), - None, - ); + let (pic, canister_id) = test_setup(); // Init the signer's ethereum address. let call_id = pic @@ -931,49 +827,22 @@ mod test { ) .unwrap(); - pic.tick(); - pic.tick(); - - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; let body = r#" {"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"20230601._domainkey.zeroknowledge-fm.20230601.gappssmtp.com.","type":16}],"Answer":[],"Comment":"Response from 216.239.38.99."} "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, body); pic.tick(); + mock_http_response(&pic, body); pic.tick(); + mock_http_response(&pic, body); pic.tick(); - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; + let body = r#" {"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"20230601._domainkey.zeroknowledge-fm.20230601.gappssmtp.com.","type":16}],"Answer":[{"name":"20230601._domainkey.zeroknowledge-fm.20230601.gappssmtp.com.","type":16,"TTL":3600,"data":"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3gWcOhCm99qzN+h7/2+LeP3CLsJkQQ4EP/2mrceXle5pKq8uZmBl1U4d2Vxn4w+pWFANDLmcHolLboESLFqEL5N6ae7u9b236dW4zn9AFkXAGenTzQEeif9VUFtLAZ0Qh2eV7OQgz/vPj5IaNqJ7h9hpM9gO031fe4v+J0DLCE8Rgo7hXbNgJavctc0983DaCDQaznHZ44LZ6TtZv9TBs+QFvsy4+UCTfsuOtHzoEqOOuXsVXZKLP6B882XbEnBpXEF8QzV4J26HiAJFUbO3mAqZL2UeKC0hhzoIZqZXNG0BfuzOF0VLpDa18GYMUiu+LhEJPJO9D8zhzvQIHNrpGwIDAQAB"}],"Comment":"Response from 216.239.38.99."} "#; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); - pic.tick(); - pic.tick(); + mock_http_response(&pic, body); pic.tick(); + mock_http_response(&pic, body); // // Now the test canister will receive the http outcall response // // and reply to the ingress message from the test driver. @@ -1020,52 +889,7 @@ mod test { #[test] fn test_revoke_valid_case() { - // We create a PocketIC instance consisting of the NNS, II, and one application subnet. - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - // We retrieve the app subnet ID from the topology. - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create empty canisters as the anonymous principal and add cycles. - let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); - let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); - // We create a canister on the app subnet. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); - pic.add_cycles(canister_id, 2_000_000_000_000); - pic.install_canister( - poseidon_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - dns_client_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - canister_id, - include_bytes!( - "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" - ) - .to_vec(), - Encode!( - &Some(Environment::Production), - &poseidon_canister_id.to_string(), - &dns_client_canister_id.to_string() - ) - .unwrap(), - None, - ); + let (pic, canister_id) = test_setup(); // Init the signer's ethereum address. let call_id = pic @@ -1103,12 +927,6 @@ mod test { ) .unwrap(); - pic.tick(); - pic.tick(); - - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; let mut body = r#" { "Status": 0, @@ -1136,17 +954,9 @@ mod test { "# .to_string(); body = body.replace("{{BASE64}}", &public_key_der_base64); - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, &body); + pic.tick(); + mock_http_response(&pic, &body); // Now the test canister will receive the http outcall response // and reply to the ingress message from the test driver. @@ -1189,52 +999,7 @@ mod test { #[test] fn test_revoke_valid_case_gappssmtp() { - // We create a PocketIC instance consisting of the NNS, II, and one application subnet. - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - // We retrieve the app subnet ID from the topology. - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create empty canisters as the anonymous principal and add cycles. - let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); - let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); - // We create a canister on the app subnet. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); - pic.add_cycles(canister_id, 2_000_000_000_000); - pic.install_canister( - poseidon_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - dns_client_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - canister_id, - include_bytes!( - "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" - ) - .to_vec(), - Encode!( - &Some(Environment::Production), - &poseidon_canister_id.to_string(), - &dns_client_canister_id.to_string() - ) - .unwrap(), - None, - ); + let (pic, canister_id) = test_setup(); // Init the signer's ethereum address. let call_id = pic @@ -1270,11 +1035,6 @@ mod test { ) .unwrap(); - pic.tick(); - pic.tick(); - - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); let body = r#" { "Status": 0, @@ -1293,25 +1053,13 @@ mod test { } "# .to_string(); - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_requests[0].subnet_id, - request_id: canister_http_requests[0].request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); - + mock_http_response(&pic, &body); pic.tick(); + mock_http_response(&pic, &body); pic.tick(); + mock_http_response(&pic, &body); pic.tick(); - let canister_http_requests: Vec = - pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; + let mut body = r#" { "Status": 0, @@ -1339,20 +1087,11 @@ mod test { "# .to_string(); body = body.replace("{{BASE64}}", &public_key_der_base64); - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); + mock_http_response(&pic, &body); + pic.tick(); + mock_http_response(&pic, &body); let reply = pic.await_call(call_id).unwrap(); - println!("{:?}", reply); let res = match reply { WasmResult::Reply(data) => { let res: Result = decode_one(&data).unwrap(); @@ -1367,7 +1106,6 @@ mod test { // There should be no more pending canister http outcalls. let canister_http_requests = pic.get_canister_http(); assert_eq!(canister_http_requests.len(), 0); - println!("{:?}", res); let signature = hex::decode(&res.signature[2..]).unwrap(); let signature_bytes: [u8; 64] = signature[0..64].try_into().unwrap(); let signature_bytes_64 = libsecp256k1::Signature::parse_standard(&signature_bytes).unwrap(); @@ -1392,53 +1130,8 @@ mod test { } #[test] - fn test_revoke_invalid_case() { - // We create a PocketIC instance consisting of the NNS, II, and one application subnet. - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - // We retrieve the app subnet ID from the topology. - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create empty canisters as the anonymous principal and add cycles. - let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); - let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); - // We create a canister on the app subnet. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); - pic.add_cycles(canister_id, 2_000_000_000_000); - pic.install_canister( - poseidon_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - dns_client_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - canister_id, - include_bytes!( - "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" - ) - .to_vec(), - Encode!( - &Some(Environment::Production), - &poseidon_canister_id.to_string(), - &dns_client_canister_id.to_string() - ) - .unwrap(), - None, - ); + fn test_revoke_key_mismatch_case() { + let (pic, canister_id) = test_setup(); // Init the signer's ethereum address. let call_id = pic @@ -1464,12 +1157,6 @@ mod test { ) .unwrap(); - pic.tick(); - pic.tick(); - - let canister_http_requests = pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; let body = r#" { "Status": 0, @@ -1496,36 +1183,14 @@ mod test { } "# .to_string(); - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); - + mock_http_response(&pic, &body); pic.tick(); + mock_http_response(&pic, &body); pic.tick(); + mock_http_response(&pic, &body); + pic.tick(); + mock_http_response(&pic, &body); pic.tick(); - let canister_http_requests: Vec = - pic.get_canister_http(); - assert_eq!(canister_http_requests.len(), 1); - let canister_http_request = &canister_http_requests[0]; - let mock_canister_http_response = MockCanisterHttpResponse { - subnet_id: canister_http_request.subnet_id, - request_id: canister_http_request.request_id, - response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { - status: 200, - headers: vec![], - body: body.as_bytes().to_vec(), - }), - additional_responses: vec![], - }; - pic.mock_canister_http_response(mock_canister_http_response); let reply = pic.await_call(call_id).unwrap(); match reply { @@ -1539,52 +1204,7 @@ mod test { #[test] fn test_sign_gmail_invalid_selector() { - // We create a PocketIC instance consisting of the NNS, II, and one application subnet. - let pic = PocketIcBuilder::new() - .with_nns_subnet() - .with_ii_subnet() // this subnet has ECDSA keys - .with_application_subnet() - .build(); - - // We retrieve the app subnet ID from the topology. - let topology = pic.topology(); - let app_subnet = topology.get_app_subnets()[0]; - - // Create empty canisters as the anonymous principal and add cycles. - let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); - let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); - // We create a canister on the app subnet. - let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); - assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); - pic.add_cycles(canister_id, 2_000_000_000_000); - pic.install_canister( - poseidon_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - dns_client_canister_id, - include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), - vec![], - None, - ); - pic.install_canister( - canister_id, - include_bytes!( - "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" - ) - .to_vec(), - Encode!( - &Some(Environment::Production), - &poseidon_canister_id.to_string(), - &dns_client_canister_id.to_string() - ) - .unwrap(), - None, - ); + let (pic, canister_id) = test_setup(); // Init the signer's ethereum address. let call_id = pic @@ -1613,7 +1233,6 @@ mod test { let canister_http_requests = pic.get_canister_http(); assert_eq!(canister_http_requests.len(), 0); let reply = pic.await_call(call_id).unwrap(); - println!("{:?}", reply); match reply { WasmResult::Reply(data) => { let res: Result = decode_one(&data).unwrap(); @@ -1642,4 +1261,74 @@ mod test { let hash = raw_keccak256(eth_message).to_vec(); hash.try_into().unwrap() } + + fn test_setup() -> (PocketIc, Principal) { + // We create a PocketIC instance consisting of the NNS, II, and one application subnet. + let pic = PocketIcBuilder::new() + .with_nns_subnet() + .with_ii_subnet() // this subnet has ECDSA keys + .with_application_subnet() + .build(); + + // We retrieve the app subnet ID from the topology. + let topology = pic.topology(); + let app_subnet = topology.get_app_subnets()[0]; + + // Create empty canisters as the anonymous principal and add cycles. + let poseidon_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + pic.add_cycles(poseidon_canister_id, 2_000_000_000_000); + let dns_client_canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + pic.add_cycles(dns_client_canister_id, 2_000_000_000_000); + // We create a canister on the app subnet. + let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + assert_eq!(pic.get_subnet(canister_id), Some(app_subnet)); + pic.add_cycles(canister_id, 2_000_000_000_000); + pic.install_canister( + poseidon_canister_id, + include_bytes!("../../../target/wasm32-unknown-unknown/debug/poseidon.wasm").to_vec(), + vec![], + None, + ); + pic.install_canister( + dns_client_canister_id, + include_bytes!("../../../target/wasm32-unknown-unknown/debug/dns_client.wasm").to_vec(), + vec![], + None, + ); + pic.install_canister( + canister_id, + include_bytes!( + "../../../target/wasm32-unknown-unknown/debug/ic_dns_oracle_backend.wasm" + ) + .to_vec(), + Encode!( + &Some(Environment::Production), + &poseidon_canister_id.to_string(), + &dns_client_canister_id.to_string() + ) + .unwrap(), + None, + ); + (pic, canister_id) + } + + fn mock_http_response(pic: &PocketIc, body: &str) { + pic.tick(); + pic.tick(); + + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 1); + let canister_http_request = &canister_http_requests[0]; + let mock_canister_http_response = MockCanisterHttpResponse { + subnet_id: canister_http_request.subnet_id, + request_id: canister_http_request.request_id, + response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { + status: 200, + headers: vec![], + body: body.as_bytes().to_vec(), + }), + additional_responses: vec![], + }; + pic.mock_canister_http_response(mock_canister_http_response); + } } From db64f39092d15b21d15b2cc9302c11828983069a Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Wed, 18 Dec 2024 20:22:35 +0900 Subject: [PATCH 2/6] Remove _transform_headers() --- src/dns_client/src/lib.rs | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index e43fc41..9d131d6 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -130,7 +130,7 @@ fn transform(raw: TransformArgs) -> HttpResponse { Err(e) => HttpResponse { status: Nat::from(500u64), body: e.as_bytes().to_vec(), - headers: _transform_headers(), + headers: vec![], ..Default::default() }, } @@ -218,7 +218,7 @@ fn _transform(raw: TransformArgs) -> Result { return Ok(HttpResponse { status: raw.response.status.clone(), body: pubkey_bytes.n().to_bytes_be().to_vec(), - headers: _transform_headers(), + headers: vec![], ..Default::default() }); } @@ -226,35 +226,6 @@ fn _transform(raw: TransformArgs) -> Result { Err("No key found".to_string()) } -fn _transform_headers() -> Vec { - vec![ - HttpHeader { - name: "Content-Security-Policy".to_string(), - value: "default-src 'self'".to_string(), - }, - HttpHeader { - name: "Referrer-Policy".to_string(), - value: "strict-origin".to_string(), - }, - HttpHeader { - name: "Permissions-Policy".to_string(), - value: "geolocation=(self)".to_string(), - }, - HttpHeader { - name: "Strict-Transport-Security".to_string(), - value: "max-age=63072000".to_string(), - }, - HttpHeader { - name: "X-Frame-Options".to_string(), - value: "DENY".to_string(), - }, - HttpHeader { - name: "X-Content-Type-Options".to_string(), - value: "nosniff".to_string(), - }, - ] -} - ic_cdk::export_candid!(); #[cfg(test)] From 124304cf5ec3d2f5ce0a2946a25c002688fa723f Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Thu, 19 Dec 2024 11:37:42 +0900 Subject: [PATCH 3/6] charge only required cycles, validate http response more, and charge cycles in two stages --- src/dns_client/src/lib.rs | 29 ++++++++++++++++-- src/ic_dns_oracle_backend/src/lib.rs | 44 ++++++++++++++++++++++++---- src/poseidon/src/lib.rs | 2 +- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index 9d131d6..6e68107 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use base64::{engine::general_purpose, Engine as _}; -use candid::Nat; +use candid::{Nat, Principal}; use ic_cdk::api::management_canister::http_request::{ http_request, CanisterHttpRequestArgument, HttpHeader, HttpMethod, HttpResponse, TransformArgs, TransformContext, @@ -44,7 +44,7 @@ pub async fn get_dkim_public_key( return Err("Insufficient cycles".to_string()); } } - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(available_cycles); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); if available_cycles != accepted_cycles { return Err("Fail to accept all available cycles".to_string()); } @@ -65,6 +65,10 @@ pub async fn get_dkim_public_key( // #[cfg(debug_assertions)] // let prefixes = vec!["https://dns.google/resolve"]; + // let (seed_raw,): ([u8; 32],) = ic_cdk::call(Principal::management_canister(), "raw_rand", ()) + // .await + // .expect("Failed to call the management canister"); + // let seed = (seed_raw[0..16].iter().map(|&b| b as u128).sum::() % 3) as usize; let seed = ic_cdk::api::time() as usize % prefixes.len(); let mut shuffled_prefixes = vec![]; @@ -154,7 +158,9 @@ fn _construct_request(prefix: &str, selector: &str, domain: &str) -> CanisterHtt value: "application/dns-json".to_string(), }]; - let transform = TransformContext::from_name("transform".to_string(), vec![]); + let expected_name = format!("\"{}._domainkey.{}.\"", selector, domain); + let transform = + TransformContext::from_name("transform".to_string(), expected_name.as_bytes().to_vec()); CanisterHttpRequestArgument { url: url.to_string(), method: HttpMethod::GET, @@ -186,7 +192,18 @@ fn _transform(raw: TransformArgs) -> Result { .as_array() .ok_or_else(|| "No array of Answer")? .to_vec(); + let expected_name = String::from_utf8(raw.context).expect("context is not a valid utf8 string"); for i in 0..answers.len() { + if let Some(name) = answers[i].get("name") { + if name.to_string() != expected_name { + continue; + } + } + if let Some(dns_type) = answers[i].get("type") { + if dns_type.to_string() != "16" { + continue; + } + } let data = answers[i]["data"].to_string(); if let Some(k_caps) = Regex::new("k=([a-z]+)").unwrap().captures(&data) { if &k_caps[1] != "rsa" { @@ -194,6 +211,12 @@ fn _transform(raw: TransformArgs) -> Result { } } + if let Some(v_caps) = Regex::new("v=([A-Z0-9]+)").unwrap().captures(&data) { + if &v_caps[1] != "DKIM1" { + continue; + } + } + if let Some(p_caps) = Regex::new(r#"p=([A-Za-z0-9\\+/" ]+);?"#) .unwrap() .captures(&data) diff --git a/src/ic_dns_oracle_backend/src/lib.rs b/src/ic_dns_oracle_backend/src/lib.rs index d579f92..bf45433 100644 --- a/src/ic_dns_oracle_backend/src/lib.rs +++ b/src/ic_dns_oracle_backend/src/lib.rs @@ -11,11 +11,19 @@ use std::cell::RefCell; // consumed cycle for sign_dkim_public_key: 26_164_599_060 cycles // the consumed cycle * 1.5 is charged cycle = 39_246_898_590 cycles -pub const SIGN_CHARGED_CYCLE: u128 = 39_246_898_590; +pub const SIGN_CHARGED_CYCLE1: u128 = 39_246_898_590; + +// consumed cycle for sign_dkim_public_key: 26_164_599_060 cycles +// the consumed cycle * 1.5 is charged cycle = 39_246_898_590 cycles +pub const SIGN_CHARGED_CYCLE2: u128 = 39_246_898_590; // consumed cycle for revoke_dkim_public_key: 26_254_964_417 cycles // the consumed cycle * 1.5 is charged cycle = 39_382_446_626 cycles -pub const REVOKE_CHARGED_CYCLE: u128 = 39_382_446_626; +pub const REVOKE_CHARGED_CYCLE1: u128 = 39_382_446_626; + +// consumed cycle for revoke_dkim_public_key: 26_254_964_417 cycles +// the consumed cycle * 1.5 is charged cycle = 39_382_446_626 cycles +pub const REVOKE_CHARGED_CYCLE2: u128 = 39_382_446_626; // consumed cycle for get_dkim_public_key: 735_324_690 cycles // the consumed cycle * 1.5 is charged cycle = 1_102_987_035 cycles @@ -259,12 +267,12 @@ pub async fn sign_dkim_public_key( let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { - if available_cycles < SIGN_CHARGED_CYCLE { + if available_cycles < SIGN_CHARGED_CYCLE1 { return Err("Insufficient cycles".to_string()); } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(available_cycles); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE1); if available_cycles != accepted_cycles { return Err("Fail to accept all available cycles".to_string()); } @@ -288,6 +296,18 @@ pub async fn sign_dkim_public_key( } Err(e) => e, }; + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); + #[cfg(not(debug_assertions))] + { + if available_cycles < SIGN_CHARGED_CYCLE2 { + return Err("Insufficient cycles".to_string()); + } + } + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE2); + if available_cycles != accepted_cycles { + return Err("Fail to accept all available cycles".to_string()); + } let error1 = match _sign_dkim_public_key(selector, domain_with_gappssmtp, domain.clone()).await { Ok(res) => { @@ -453,12 +473,12 @@ pub async fn revoke_dkim_public_key( let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { - if available_cycles < REVOKE_CHARGED_CYCLE { + if available_cycles < REVOKE_CHARGED_CYCLE1 { return Err("Insufficient cycles".to_string()); } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(available_cycles); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE1); if available_cycles != accepted_cycles { return Err("Fail to accept all available cycles".to_string()); } @@ -486,6 +506,18 @@ pub async fn revoke_dkim_public_key( } Err(e) => e, }; + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); + #[cfg(not(debug_assertions))] + { + if available_cycles < REVOKE_CHARGED_CYCLE2 { + return Err("Insufficient cycles".to_string()); + } + } + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE2); + if available_cycles != accepted_cycles { + return Err("Fail to accept all available cycles".to_string()); + } let domain_with_gappssmtp = format!("{}.{}.gappssmtp.com", &domain.replace(".", "-"), &selector); let error1 = match _revoke_dkim_public_key( diff --git a/src/poseidon/src/lib.rs b/src/poseidon/src/lib.rs index e871e43..868012c 100644 --- a/src/poseidon/src/lib.rs +++ b/src/poseidon/src/lib.rs @@ -25,7 +25,7 @@ pub fn public_key_hash(public_key_hex: String) -> Result { } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(available_cycles); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); if available_cycles != accepted_cycles { return Err("Fail to accept all available cycles".to_string()); } From f1d9cddfff523f80884f15edd8488075628a6840 Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Thu, 19 Dec 2024 19:33:06 +0900 Subject: [PATCH 4/6] Use raw_seed --- src/dns_client/src/lib.rs | 21 +++++++---- src/ic_dns_oracle_backend/src/lib.rs | 53 +++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index 6e68107..7782fbd 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -65,12 +65,11 @@ pub async fn get_dkim_public_key( // #[cfg(debug_assertions)] // let prefixes = vec!["https://dns.google/resolve"]; - // let (seed_raw,): ([u8; 32],) = ic_cdk::call(Principal::management_canister(), "raw_rand", ()) - // .await - // .expect("Failed to call the management canister"); - // let seed = (seed_raw[0..16].iter().map(|&b| b as u128).sum::() % 3) as usize; - - let seed = ic_cdk::api::time() as usize % prefixes.len(); + let (seed_raw,): ([u8; 32],) = ic_cdk::call(Principal::management_canister(), "raw_rand", ()) + .await + .expect("Failed to call the management canister"); + let seed = (seed_raw[0..16].iter().map(|&b| b as u128).sum::() % 3) as usize; + // let seed = ic_cdk::api::time() as usize % prefixes.len(); let mut shuffled_prefixes = vec![]; for i in 0..prefixes.len() { shuffled_prefixes.push(prefixes[(seed + i) % prefixes.len()]); @@ -298,6 +297,8 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); @@ -356,6 +357,8 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); let body = r#" @@ -441,6 +444,8 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); @@ -501,6 +506,8 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); @@ -562,6 +569,8 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); diff --git a/src/ic_dns_oracle_backend/src/lib.rs b/src/ic_dns_oracle_backend/src/lib.rs index bf45433..0ba7e44 100644 --- a/src/ic_dns_oracle_backend/src/lib.rs +++ b/src/ic_dns_oracle_backend/src/lib.rs @@ -781,6 +781,8 @@ mod test { "Comment": "Response from 216.239.32.10." } "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); @@ -862,6 +864,8 @@ mod test { let body = r#" {"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"20230601._domainkey.zeroknowledge-fm.20230601.gappssmtp.com.","type":16}],"Answer":[],"Comment":"Response from 216.239.38.99."} "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); @@ -872,6 +876,8 @@ mod test { let body = r#" {"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"20230601._domainkey.zeroknowledge-fm.20230601.gappssmtp.com.","type":16}],"Answer":[{"name":"20230601._domainkey.zeroknowledge-fm.20230601.gappssmtp.com.","type":16,"TTL":3600,"data":"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3gWcOhCm99qzN+h7/2+LeP3CLsJkQQ4EP/2mrceXle5pKq8uZmBl1U4d2Vxn4w+pWFANDLmcHolLboESLFqEL5N6ae7u9b236dW4zn9AFkXAGenTzQEeif9VUFtLAZ0Qh2eV7OQgz/vPj5IaNqJ7h9hpM9gO031fe4v+J0DLCE8Rgo7hXbNgJavctc0983DaCDQaznHZ44LZ6TtZv9TBs+QFvsy4+UCTfsuOtHzoEqOOuXsVXZKLP6B882XbEnBpXEF8QzV4J26HiAJFUbO3mAqZL2UeKC0hhzoIZqZXNG0BfuzOF0VLpDa18GYMUiu+LhEJPJO9D8zhzvQIHNrpGwIDAQAB"}],"Comment":"Response from 216.239.38.99."} "#; + pic.tick(); + pic.tick(); mock_http_response(&pic, body); pic.tick(); mock_http_response(&pic, body); @@ -986,6 +992,8 @@ mod test { "# .to_string(); body = body.replace("{{BASE64}}", &public_key_der_base64); + pic.tick(); + pic.tick(); mock_http_response(&pic, &body); pic.tick(); mock_http_response(&pic, &body); @@ -1077,7 +1085,7 @@ mod test { "CD": false, "Question": [ { - "name": "20230601._domainkey.gmail.com.", + "name": "20230601.gmail.com.", "type": 16 } ], @@ -1085,6 +1093,8 @@ mod test { } "# .to_string(); + pic.tick(); + pic.tick(); mock_http_response(&pic, &body); pic.tick(); mock_http_response(&pic, &body); @@ -1102,13 +1112,13 @@ mod test { "CD": false, "Question": [ { - "name": "20230601._domainkey.gmail.com.", + "name": "20230601._domainkey.gmail-com.20230601.gappssmtp.com.", "type": 16 } ], "Answer": [ { - "name": "20230601._domainkey.gmail.com.", + "name": "20230601._domainkey.gmail-com.20230601.gappssmtp.com.", "type": 16, "TTL": 3600, "data": "v=DKIM1; k=rsa; p={{BASE64}}" @@ -1119,9 +1129,12 @@ mod test { "# .to_string(); body = body.replace("{{BASE64}}", &public_key_der_base64); + pic.tick(); + pic.tick(); mock_http_response(&pic, &body); pic.tick(); mock_http_response(&pic, &body); + pic.tick(); let reply = pic.await_call(call_id).unwrap(); let res = match reply { @@ -1199,13 +1212,40 @@ mod test { "CD": false, "Question": [ { - "name": "20230601._domainkey.gmail.com.", + "name": "20230601.gmail.com.", + "type": 16 + } + ], + "Comment": "Response from 216.239.32.10." + } + "# + .to_string(); + pic.tick(); + pic.tick(); + mock_http_response(&pic, &body); + pic.tick(); + mock_http_response(&pic, &body); + pic.tick(); + mock_http_response(&pic, &body); + pic.tick(); + + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail-com.20230601.gappssmtp.com.", "type": 16 } ], "Answer": [ { - "name": "20230601._domainkey.gmail.com.", + "name": "20230601._domainkey.gmail-com.20230601.gappssmtp.com.", "type": 16, "TTL": 3600, "data": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAntvSKT1hkqhKe0xcaZ0x+QbouDsJuBfby/S82jxsoC/SodmfmVs2D1KAH3mi1AqdMdU12h2VfETeOJkgGYq5ljd996AJ7ud2SyOLQmlhaNHH7Lx+Mdab8/zDN1SdxPARDgcM7AsRECHwQ15R20FaKUABGu4NTbR2fDKnYwiq5jQyBkLWP+LgGOgfUF4T4HZb2PY2bQtEP6QeqOtcW4rrsH24L7XhD+HSZb1hsitrE0VPbhJzxDwI4JF815XMnSVjZgYUXP8CxI1Y0FONlqtQYgsorZ9apoW1KPQe8brSSlRsi9sXB/tu56LmG7tEDNmrZ5XUwQYUUADBOu7t1niwXwIDAQAB" @@ -1215,14 +1255,11 @@ mod test { } "# .to_string(); - mock_http_response(&pic, &body); pic.tick(); - mock_http_response(&pic, &body); pic.tick(); mock_http_response(&pic, &body); pic.tick(); mock_http_response(&pic, &body); - pic.tick(); let reply = pic.await_call(call_id).unwrap(); match reply { From b11641025853a9ae5afa9b915dca940aa1941645 Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Fri, 20 Dec 2024 20:28:38 +0900 Subject: [PATCH 5/6] Updated charged cycles --- README.md | 10 ++-- src/dns_client/src/lib.rs | 12 ++--- src/ic_dns_oracle_backend/src/lib.rs | 75 +++++++++++++++------------- src/poseidon/src/lib.rs | 10 ++-- 4 files changed, 54 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 7e4e062..b7a02af 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Our repository contains the implementations of theee canisters as follows: Our IC DNS oracle backend canister is available at https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=fxmww-qiaaa-aaaaj-azu7a-cai. Once you prepare your identity and wallet on ICP, you can obtain the signature for the hash of the public key registered on DNS for the pair of the selector 20230601 and the domain gmail.com by calling the following command: ``` -dfx canister call fxmww-qiaaa-aaaaj-azu7a-cai sign_dkim_public_key '("20230601", "gmail.com")' --network ic --with-cycles 39246898590 --wallet +dfx canister call fxmww-qiaaa-aaaaj-azu7a-cai sign_dkim_public_key '("20230601", "gmail.com")' --network ic --with-cycles 85_414_812_012 --wallet ``` You can verify it as the ECDSA signature from 0x6293a80bf4bd3fff995a0cab74cbf281d922da02, which is the signer's Ethereum address output by the `get_signer_ethereum_address` function. @@ -33,10 +33,10 @@ Specifically, each function requires the following amount of cycles. | Function Name | Required Cycles | |---------------|-----------------| -| public_key_hash | 26415989 | -| get_dkim_public_key | 1102987035 | -| sign_dkim_public_key | 39246898590 | -| revoke_dkim_public_key | 39382446626 | +| public_key_hash | 52_946_839 | +| get_dkim_public_key | 2_236_193_826 | +| sign_dkim_public_key | 42_707_406_006 (normal domain) / 85_414_812_012 (domain with gappssmtp.com) | +| revoke_dkim_public_key | 39_438_456_624 (normal domain) / 78_876_913_248 (domain with gappssmtp.com) | ## References - [Quick Start](https://internetcomputer.org/docs/quickstart/quickstart-intro) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index 7782fbd..fa23bce 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use base64::{engine::general_purpose, Engine as _}; use candid::{Nat, Principal}; use ic_cdk::api::management_canister::http_request::{ @@ -16,9 +14,9 @@ const SELECTOR_REGEX: &str = r"^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*$"; const DOMAIN_REGEX: &str = r"^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*$"; -// consumed cycle for get_dkim_public_key: 745_646_986 cycles -// the consumed cycle * 1.479 is charged cycle = 1_102_987_035 cycles -pub const CHARGED_CYCLE: u128 = 1_102_987_035; +// consumed cycle for get_dkim_public_key: 1_490_795_884 cycles +// the consumed cycle * 1.5 is charged cycle = 2_236_193_826 cycles +pub const CHARGED_CYCLE: u128 = 2_236_193_826; /// Fetches the DKIM public key for the given selector and domain. /// @@ -45,8 +43,8 @@ pub async fn get_dkim_public_key( } } let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); - if available_cycles != accepted_cycles { - return Err("Fail to accept all available cycles".to_string()); + if CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); } // Verify selector and domain if !Regex::new(SELECTOR_REGEX).unwrap().is_match(&selector) { diff --git a/src/ic_dns_oracle_backend/src/lib.rs b/src/ic_dns_oracle_backend/src/lib.rs index 0ba7e44..ebef0d9 100644 --- a/src/ic_dns_oracle_backend/src/lib.rs +++ b/src/ic_dns_oracle_backend/src/lib.rs @@ -9,29 +9,23 @@ use rsa::{pkcs1::DecodeRsaPrivateKey, traits::PublicKeyParts, BigUint, RsaPrivat use serde::Deserialize; use std::cell::RefCell; -// consumed cycle for sign_dkim_public_key: 26_164_599_060 cycles -// the consumed cycle * 1.5 is charged cycle = 39_246_898_590 cycles -pub const SIGN_CHARGED_CYCLE1: u128 = 39_246_898_590; +// consumed cycle for _sign_dkim_public_key: 28_471_604_004 cycles +// the consumed cycle * 1.5 is charged cycle = 42_707_406_006 cycles +// Note that you need to pay two times of the charged cycle for domains with gappssmtp.com. +pub const SIGN_CHARGED_CYCLE: u128 = 42_707_406_006; -// consumed cycle for sign_dkim_public_key: 26_164_599_060 cycles -// the consumed cycle * 1.5 is charged cycle = 39_246_898_590 cycles -pub const SIGN_CHARGED_CYCLE2: u128 = 39_246_898_590; +// consumed cycle for _revoke_dkim_public_key: 26_292_304_416 cycles +// the consumed cycle * 1.5 is charged cycle = 39_438_456_624 cycles +// Note that you need to pay two times of the charged cycle for domains with gappssmtp.com. +pub const REVOKE_CHARGED_CYCLE: u128 = 39_438_456_624; -// consumed cycle for revoke_dkim_public_key: 26_254_964_417 cycles -// the consumed cycle * 1.5 is charged cycle = 39_382_446_626 cycles -pub const REVOKE_CHARGED_CYCLE1: u128 = 39_382_446_626; +// consumed cycle for get_dkim_public_key: 1_490_795_884 cycles +// the consumed cycle * 1.5 is charged cycle = 2_236_193_826 cycles +pub const DNS_CLIENT_CHARGED_CYCLE: u128 = 2_236_193_826; -// consumed cycle for revoke_dkim_public_key: 26_254_964_417 cycles -// the consumed cycle * 1.5 is charged cycle = 39_382_446_626 cycles -pub const REVOKE_CHARGED_CYCLE2: u128 = 39_382_446_626; - -// consumed cycle for get_dkim_public_key: 735_324_690 cycles -// the consumed cycle * 1.5 is charged cycle = 1_102_987_035 cycles -pub const DNS_CLIENT_CHARGED_CYCLE: u128 = 1_102_987_035; - -// consumed cycle for public_key_hash: 17_610_659 cycles -// the consumed cycle * 1.5 is charged cycle = 26_415_989 cycles -pub const POSEIDON_CHARGED_CYCLE: u128 = 26_415_989; +// consumed cycle for public_key_hash: 35_297_893 cycles +// the consumed cycle * 1.5 is charged cycle = 52_946_839 cycles +pub const POSEIDON_CHARGED_CYCLE: u128 = 52_946_839; /// Structure representing a signature for a new DKIM public key. /// @@ -267,14 +261,14 @@ pub async fn sign_dkim_public_key( let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { - if available_cycles < SIGN_CHARGED_CYCLE1 { + if available_cycles < SIGN_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE1); - if available_cycles != accepted_cycles { - return Err("Fail to accept all available cycles".to_string()); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE); + if SIGN_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); } write_log( "sign_dkim_public_key", @@ -299,14 +293,14 @@ pub async fn sign_dkim_public_key( let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { - if available_cycles < SIGN_CHARGED_CYCLE2 { + if available_cycles < SIGN_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE2); - if available_cycles != accepted_cycles { - return Err("Fail to accept all available cycles".to_string()); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE); + if SIGN_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); } let error1 = match _sign_dkim_public_key(selector, domain_with_gappssmtp, domain.clone()).await { @@ -473,14 +467,14 @@ pub async fn revoke_dkim_public_key( let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { - if available_cycles < REVOKE_CHARGED_CYCLE1 { + if available_cycles < REVOKE_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE1); - if available_cycles != accepted_cycles { - return Err("Fail to accept all available cycles".to_string()); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE); + if REVOKE_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); } write_log( "revoke_dkim_public_key", @@ -509,14 +503,14 @@ pub async fn revoke_dkim_public_key( let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { - if available_cycles < REVOKE_CHARGED_CYCLE2 { + if available_cycles < REVOKE_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } } // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE2); - if available_cycles != accepted_cycles { - return Err("Fail to accept all available cycles".to_string()); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE); + if REVOKE_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); } let domain_with_gappssmtp = format!("{}.{}.gappssmtp.com", &domain.replace(".", "-"), &selector); @@ -696,6 +690,7 @@ mod test { use candid::{decode_one, encode_one, Encode, Principal}; use easy_hasher::easy_hasher::raw_keccak256; use hex; + use ic_cdk::api::management_canister::main::{CanisterIdRecord, CanisterInfoRequest}; use libsecp256k1; use pocket_ic::{ common::rest::{CanisterHttpReply, CanisterHttpResponse, MockCanisterHttpResponse}, @@ -956,6 +951,10 @@ mod test { // Submit an update call to the test canister making a canister http outcall // and mock a canister http outcall response. + println!( + "canister info {:?}", + pic.canister_status(canister_id, None).unwrap() + ); let call_id = pic .submit_call( canister_id, @@ -1008,6 +1007,10 @@ mod test { } WasmResult::Reject(msg) => panic!("Unexpected reject {}", msg), }; + println!( + "canister info {:?}", + pic.canister_status(canister_id, None).unwrap() + ); assert_eq!(res.selector, "20230601"); assert_eq!(res.domain, "gmail.com"); assert_eq!(res.public_key, public_key_hex); diff --git a/src/poseidon/src/lib.rs b/src/poseidon/src/lib.rs index 868012c..6845d7b 100644 --- a/src/poseidon/src/lib.rs +++ b/src/poseidon/src/lib.rs @@ -2,9 +2,9 @@ use ff::PrimeField; use hex; use poseidon_rs::*; -// consumed cycle for public_key_hash: 17_610_659 cycles -// the consumed cycle * 1.5 is charged cycle = 26_415_989 cycles -pub const CHARGED_CYCLE: u128 = 26_415_989; +// consumed cycle for public_key_hash: 35_297_893 cycles +// the consumed cycle * 1.5 is charged cycle = 52_946_839 cycles +pub const CHARGED_CYCLE: u128 = 52_946_839; /// Computes the hash of the given public key. /// @@ -26,8 +26,8 @@ pub fn public_key_hash(public_key_hex: String) -> Result { } // Accept all available cycles. let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); - if available_cycles != accepted_cycles { - return Err("Fail to accept all available cycles".to_string()); + if CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); } _public_key_hash(public_key_hex) } From be3c1e6bb5fa9fe3e368851fa866c0166d426e00 Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Tue, 31 Dec 2024 20:22:00 +0900 Subject: [PATCH 6/6] Fix failing unit tests --- src/dns_client/src/lib.rs | 11 ++++--- src/ic_dns_oracle_backend/src/lib.rs | 46 ++++++++++++++-------------- src/poseidon/src/lib.rs | 12 ++++---- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index fa23bce..0f7fe86 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -35,16 +35,16 @@ pub async fn get_dkim_public_key( domain: String, cycle: u64, ) -> Result { - let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); if available_cycles < CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } - } - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); - if CHARGED_CYCLE != accepted_cycles { - return Err("Fail to accept the charged cycles".to_string()); + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); + if CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); + } } // Verify selector and domain if !Regex::new(SELECTOR_REGEX).unwrap().is_match(&selector) { @@ -298,6 +298,7 @@ mod test { pic.tick(); pic.tick(); mock_http_response(&pic, body); + println!("res 1"); pic.tick(); mock_http_response(&pic, body); diff --git a/src/ic_dns_oracle_backend/src/lib.rs b/src/ic_dns_oracle_backend/src/lib.rs index ebef0d9..319bd68 100644 --- a/src/ic_dns_oracle_backend/src/lib.rs +++ b/src/ic_dns_oracle_backend/src/lib.rs @@ -264,11 +264,11 @@ pub async fn sign_dkim_public_key( if available_cycles < SIGN_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } - } - // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE); - if SIGN_CHARGED_CYCLE != accepted_cycles { - return Err("Fail to accept the charged cycles".to_string()); + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE); + if SIGN_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); + } } write_log( "sign_dkim_public_key", @@ -290,17 +290,17 @@ pub async fn sign_dkim_public_key( } Err(e) => e, }; - let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); if available_cycles < SIGN_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } - } - // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE); - if SIGN_CHARGED_CYCLE != accepted_cycles { - return Err("Fail to accept the charged cycles".to_string()); + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(SIGN_CHARGED_CYCLE); + if SIGN_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); + } } let error1 = match _sign_dkim_public_key(selector, domain_with_gappssmtp, domain.clone()).await { @@ -464,17 +464,17 @@ pub async fn revoke_dkim_public_key( domain: String, private_key_der_hex: String, ) -> Result { - let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); if available_cycles < REVOKE_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } - } - // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE); - if REVOKE_CHARGED_CYCLE != accepted_cycles { - return Err("Fail to accept the charged cycles".to_string()); + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE); + if REVOKE_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); + } } write_log( "revoke_dkim_public_key", @@ -500,17 +500,17 @@ pub async fn revoke_dkim_public_key( } Err(e) => e, }; - let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); if available_cycles < REVOKE_CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } - } - // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE); - if REVOKE_CHARGED_CYCLE != accepted_cycles { - return Err("Fail to accept the charged cycles".to_string()); + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(REVOKE_CHARGED_CYCLE); + if REVOKE_CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); + } } let domain_with_gappssmtp = format!("{}.{}.gappssmtp.com", &domain.replace(".", "-"), &selector); diff --git a/src/poseidon/src/lib.rs b/src/poseidon/src/lib.rs index 6845d7b..cf0f345 100644 --- a/src/poseidon/src/lib.rs +++ b/src/poseidon/src/lib.rs @@ -17,17 +17,17 @@ pub const CHARGED_CYCLE: u128 = 52_946_839; /// A result containing the hashed public key as a hexadecimal string, or an error message. #[ic_cdk::update] pub fn public_key_hash(public_key_hex: String) -> Result { - let available_cycles = ic_cdk::api::call::msg_cycles_available128(); #[cfg(not(debug_assertions))] { + let available_cycles = ic_cdk::api::call::msg_cycles_available128(); if available_cycles < CHARGED_CYCLE { return Err("Insufficient cycles".to_string()); } - } - // Accept all available cycles. - let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); - if CHARGED_CYCLE != accepted_cycles { - return Err("Fail to accept the charged cycles".to_string()); + // Accept all available cycles. + let accepted_cycles = ic_cdk::api::call::msg_cycles_accept128(CHARGED_CYCLE); + if CHARGED_CYCLE != accepted_cycles { + return Err("Fail to accept the charged cycles".to_string()); + } } _public_key_hash(public_key_hex) }