From 6b1252761fbd65bcb49a1372256da7ab62b34fa9 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 17:42:43 -0700 Subject: [PATCH 01/12] Set up optional canister init args --- Cargo.toml | 1 + dfx.json | 3 ++- src/accounting.rs | 16 ++-------------- src/candid_rpc.rs | 2 +- src/main.rs | 22 ++++------------------ src/memory.rs | 3 ++- src/types.rs | 6 +++++- 7 files changed, 17 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 047933f0..c9a7127c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" [profile.release] debug = false lto = true +strip = true opt-level = 's' # Required by `ic-test-utilities-load-wasm` diff --git a/dfx.json b/dfx.json index 70962a57..a0594624 100644 --- a/dfx.json +++ b/dfx.json @@ -12,7 +12,8 @@ "evm_rpc_fiduciary": { "candid": "candid/evm_rpc.did", "type": "rust", - "package": "evm_rpc" + "package": "evm_rpc", + "args": "(opt record {nodes_in_subnet = 28})" }, "e2e_rust": { "dependencies": ["evm_rpc"], diff --git a/src/accounting.rs b/src/accounting.rs index 2bd093a0..815c7967 100644 --- a/src/accounting.rs +++ b/src/accounting.rs @@ -35,7 +35,7 @@ pub fn get_http_request_cost( json_rpc_payload: &str, max_response_bytes: u64, ) -> u128 { - let nodes_in_subnet = METADATA.with(|m| m.borrow().get().nodes_in_subnet); + let nodes_in_subnet = TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow()); let ingress_bytes = (json_rpc_payload.len() + api.url.len()) as u128 + INGRESS_OVERHEAD_BYTES; let base_cost = INGRESS_MESSAGE_RECEIVED_COST + INGRESS_MESSAGE_BYTE_RECEIVED_COST * ingress_bytes @@ -46,7 +46,7 @@ pub fn get_http_request_cost( /// Calculate the additional cost for calling a registered JSON-RPC provider. pub fn get_provider_cost(provider: &Provider, json_rpc_payload: &str) -> u128 { - let nodes_in_subnet = METADATA.with(|m| m.borrow().get().nodes_in_subnet); + let nodes_in_subnet = TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow()); let cost_per_node = provider.cycles_per_call as u128 + provider.cycles_per_message_byte as u128 * json_rpc_payload.len() as u128; cost_per_node * (nodes_in_subnet as u128) @@ -54,12 +54,6 @@ pub fn get_provider_cost(provider: &Provider, json_rpc_payload: &str) -> u128 { #[test] fn test_request_cost() { - METADATA.with(|m| { - let mut metadata = m.borrow().get().clone(); - metadata.nodes_in_subnet = 13; - m.borrow_mut().set(metadata).unwrap(); - }); - let url = "https://cloudflare-eth.com"; let payload = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_gasPrice\",\"params\":[],\"id\":1}"; let base_cost = get_request_cost( @@ -87,12 +81,6 @@ fn test_request_cost() { #[test] fn test_provider_cost() { - METADATA.with(|m| { - let mut metadata = m.borrow().get().clone(); - metadata.nodes_in_subnet = 13; - m.borrow_mut().set(metadata).unwrap(); - }); - let provider = Provider { provider_id: 0, hostname: "".to_string(), diff --git a/src/candid_rpc.rs b/src/candid_rpc.rs index 586974f9..52d65f55 100644 --- a/src/candid_rpc.rs +++ b/src/candid_rpc.rs @@ -24,7 +24,7 @@ struct CanisterTransport; #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl RpcTransport for CanisterTransport { fn get_subnet_size() -> u32 { - METADATA.with(|m| m.borrow().get().nodes_in_subnet) + TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow()) } fn resolve_api(provider: &RpcService) -> Result { diff --git a/src/main.rs b/src/main.rs index b23c5ef9..ecd7bc1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -241,10 +241,12 @@ fn transform(args: TransformArgs) -> HttpResponse { } #[ic_cdk::init] -fn init() { +fn init(args: Option) { + if let Some(args) = args { + TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow_mut() = args.nodes_in_subnet); + } METADATA.with(|m| { let mut metadata = m.borrow().get().clone(); - metadata.nodes_in_subnet = DEFAULT_NODES_IN_SUBNET; metadata.open_rpc_access = DEFAULT_OPEN_RPC_ACCESS; m.borrow_mut().set(metadata).unwrap(); }); @@ -335,22 +337,6 @@ fn set_open_rpc_access(open_rpc_access: bool) { }); } -#[query(name = "getNodesInSubnet", guard = "require_admin_or_controller")] -#[candid_method(query, rename = "getNodesInSubnet")] -fn get_nodes_in_subnet() -> u32 { - METADATA.with(|m| m.borrow().get().nodes_in_subnet) -} - -#[update(name = "setNodesInSubnet", guard = "require_admin_or_controller")] -#[candid_method(rename = "setNodesInSubnet")] -fn set_nodes_in_subnet(nodes_in_subnet: u32) { - METADATA.with(|m| { - let mut metadata = m.borrow().get().clone(); - metadata.nodes_in_subnet = nodes_in_subnet; - m.borrow_mut().set(metadata).unwrap(); - }); -} - #[cfg(not(any(target_arch = "wasm32", test)))] fn main() { candid::export_service!(); diff --git a/src/memory.rs b/src/memory.rs index c432f142..c2319f4b 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -7,7 +7,7 @@ use ic_stable_structures::VectorMemory; use ic_stable_structures::{Cell, StableBTreeMap}; use std::cell::RefCell; -use crate::types::*; +use crate::{types::*, DEFAULT_NODES_IN_SUBNET}; #[cfg(not(target_arch = "wasm32"))] type Memory = VirtualMemory; @@ -21,6 +21,7 @@ declare_log_buffer!(name = ERROR, capacity = 1000); thread_local! { // Transient static data: this is reset when the canister is upgraded. pub static TRANSIENT_METRICS: RefCell = RefCell::new(Metrics::default()); + pub static TRANSIENT_SUBNET_SIZE: RefCell = RefCell::new(DEFAULT_NODES_IN_SUBNET); // Stable static data: this is preserved when the canister is upgraded. #[cfg(not(target_arch = "wasm32"))] diff --git a/src/types.rs b/src/types.rs index 098ca959..cd5f6332 100644 --- a/src/types.rs +++ b/src/types.rs @@ -15,6 +15,11 @@ use std::collections::HashMap; use crate::constants::STRING_STORABLE_MAX_SIZE; use crate::{AUTH_SET_STORABLE_MAX_SIZE, PROVIDERS}; +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct InitArgs { + pub nodes_in_subnet: u32, +} + #[derive(Clone, Debug, CandidType, Deserialize)] pub enum JsonRpcSource { Chain(u64), @@ -160,7 +165,6 @@ impl BoundedStorable for AuthSet { #[derive(Clone, Debug, Default, CandidType, Deserialize)] pub struct Metadata { - pub nodes_in_subnet: u32, pub next_provider_id: u64, pub open_rpc_access: bool, } From b2b19a3a7f9b21f908ada1eabca48ea9b16a0566 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 17:48:48 -0700 Subject: [PATCH 02/12] Remove 'getNodesInSubnet()' and 'setNodesInSubnet()' --- candid/evm_rpc.did | 2 -- 1 file changed, 2 deletions(-) diff --git a/candid/evm_rpc.did b/candid/evm_rpc.did index dcfb296d..cfe955a4 100644 --- a/candid/evm_rpc.did +++ b/candid/evm_rpc.did @@ -217,13 +217,11 @@ service : { eth_sendRawTransaction : (RpcSource, text) -> (MultiSendRawTransactionResult); getAccumulatedCycleCount : (nat64) -> (nat) query; getAuthorized : (Auth) -> (vec text) query; - getNodesInSubnet : () -> (nat32) query; getOpenRpcAccess : () -> (bool) query; getProviders : () -> (vec ProviderView) query; registerProvider : (RegisterProviderArgs) -> (nat64); request : (JsonRpcSource, text, nat64) -> (RequestResult); requestCost : (JsonRpcSource, text, nat64) -> (RequestCostResult) query; - setNodesInSubnet : (nat32) -> (); setOpenRpcAccess : (bool) -> (); unregisterProvider : (nat64) -> (bool); updateProvider : (UpdateProviderArgs) -> (); From f4b97baca30e8acb9fce4934c3f554be7ef141f6 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 19:05:07 -0700 Subject: [PATCH 03/12] Set up Motoko E2E test for fiduciary canister --- dfx.json | 4 +- e2e/motoko/Main.mo | 363 +++++++++++++++++++++++---------------------- 2 files changed, 190 insertions(+), 177 deletions(-) diff --git a/dfx.json b/dfx.json index a0594624..65d4cb42 100644 --- a/dfx.json +++ b/dfx.json @@ -16,13 +16,13 @@ "args": "(opt record {nodes_in_subnet = 28})" }, "e2e_rust": { - "dependencies": ["evm_rpc"], + "dependencies": ["evm_rpc", "evm_rpc_fiduciary"], "candid": "e2e/rust/e2e_rust.did", "type": "rust", "package": "e2e" }, "e2e_motoko": { - "dependencies": ["evm_rpc"], + "dependencies": ["evm_rpc", "evm_rpc_fiduciary"], "type": "motoko", "main": "e2e/motoko/Main.mo" } diff --git a/e2e/motoko/Main.mo b/e2e/motoko/Main.mo index 32ef4886..09c4feb6 100644 --- a/e2e/motoko/Main.mo +++ b/e2e/motoko/Main.mo @@ -1,202 +1,215 @@ import EvmRpcCanister "canister:evm_rpc"; +import EvmRpcFidicuaryCanister "canister:evm_rpc_fiduciary"; -import Principal "mo:base/Principal"; -import Evm "mo:evm"; +import Blob "mo:base/Blob"; import Debug "mo:base/Debug"; +import Cycles "mo:base/ExperimentalCycles"; +import Principal "mo:base/Principal"; import Text "mo:base/Text"; -import Blob "mo:base/Blob"; -import Cycles "mo:base/ExperimentalCycles" +import Evm "mo:evm"; shared ({ caller = installer }) actor class Main() { - let mainnet = Evm.Rpc( - #Canister EvmRpcCanister, - #Service { - hostname = "cloudflare-eth.com"; - network = ? #EthMainnet; - }, - ); - public shared ({ caller }) func test() : async () { assert caller == installer; - let source = #Service { - hostname = "cloudflare-eth.com"; - chainId = ?(1 : Nat64); // Ethereum mainnet - }; - let json = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_gasPrice\",\"params\":null,\"id\":1}"; - let maxResponseBytes : Nat64 = 1000; - - // `requestCost()` - let cyclesResult = await EvmRpcCanister.requestCost(source, json, maxResponseBytes); - let cycles = switch cyclesResult { - case (#Ok cycles) { cycles }; - case (#Err err) { - Debug.trap("unexpected error for `request_cost`: " # (debug_show err)); + let canisterDetails = [ + (EvmRpcCanister, "default", 13), + (EvmRpcFidicuaryCanister, "fiduciary", 28), + ]; + for ((canister, name, nodesInSubnet) in canisterDetails.vals()) { + Debug.print("Testing " # name # " canister..."); + + let mainnet = Evm.Rpc( + #Canister canister, + #Service { + hostname = "cloudflare-eth.com"; + network = ? #EthMainnet; + }, + ); + + let source = #Service { + hostname = "cloudflare-eth.com"; + chainId = ?(1 : Nat64); // Ethereum mainnet + }; + let json = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_gasPrice\",\"params\":null,\"id\":1}"; + let maxResponseBytes : Nat64 = 1000; + + // `requestCost()` + let cyclesResult = await EvmRpcCanister.requestCost(source, json, maxResponseBytes); + let cycles = switch cyclesResult { + case (#Ok cycles) { cycles }; + case (#Err err) { + Debug.trap("unexpected error for `request_cost`: " # (debug_show err)); + }; + }; + let expectedCycles = 521_498_000 * nodesInSubnet / 13; + if (cycles != expectedCycles) { + Debug.trap("unexpected number of cycles: " # debug_show cycles # " (expected " # debug_show expectedCycles # ")"); }; - }; - // `request()` without cycles - let resultWithoutCycles = await EvmRpcCanister.request(source, json, maxResponseBytes); - assert switch resultWithoutCycles { - case (#Err(#ProviderError(#TooFewCycles { expected }))) expected == cycles; - case _ false; - }; + // `request()` without cycles + let resultWithoutCycles = await EvmRpcCanister.request(source, json, maxResponseBytes); + assert switch resultWithoutCycles { + case (#Err(#ProviderError(#TooFewCycles { expected }))) expected == cycles; + case _ false; + }; - // `request()` with cycles - let result = await mainnet.request("eth_gasPrice", #Array([]), 1000); - label validate { - switch result { - case (#ok(#Object fields)) { - for ((key, val) in fields.vals()) { - switch (key, val) { - case ("result", #String val) { - assert Text.startsWith(val, #text "0x"); - break validate; + // `request()` with cycles + let result = await mainnet.request("eth_gasPrice", #Array([]), 1000); + label validate { + switch result { + case (#ok(#Object fields)) { + for ((key, val) in fields.vals()) { + switch (key, val) { + case ("result", #String val) { + assert Text.startsWith(val, #text "0x"); + break validate; + }; + case _ {}; }; - case _ {}; }; }; + case _ {}; }; - case _ {}; + Debug.trap(debug_show result); }; - Debug.trap(debug_show result); - }; - // Candid-RPC methods - type RpcResult = { #Ok : T; #Err : EvmRpcCanister.RpcError }; - type MultiRpcResult = { - #Consistent : RpcResult; - #Inconsistent : [(EvmRpcCanister.RpcService, RpcResult)]; - }; + // Candid-RPC methods + type RpcResult = { #Ok : T; #Err : EvmRpcCanister.RpcError }; + type MultiRpcResult = { + #Consistent : RpcResult; + #Inconsistent : [(EvmRpcCanister.RpcService, RpcResult)]; + }; - func assertOk(method : Text, result : MultiRpcResult) { - switch result { - case (#Consistent(#Ok _)) {}; - case (#Consistent(#Err err)) { - Debug.trap("received error for " # method # ": " # debug_show err); - }; - case (#Inconsistent(results)) { - for ((service, result) in results.vals()) { - switch result { - case (#Ok(_)) {}; - case (#Err(err)) { - Debug.trap("received error in inconsistent results for " # method # ": " # debug_show err); + func assertOk(method : Text, result : MultiRpcResult) { + switch result { + case (#Consistent(#Ok _)) {}; + case (#Consistent(#Err err)) { + Debug.trap("received error for " # method # ": " # debug_show err); + }; + case (#Inconsistent(results)) { + for ((service, result) in results.vals()) { + switch result { + case (#Ok(_)) {}; + case (#Err(err)) { + Debug.trap("received error in inconsistent results for " # method # ": " # debug_show err); + }; }; }; }; }; }; - }; - let candidRpcCycles = 1_000_000_000_000; - let ethMainnetSource = #EthMainnet(?[#Ankr, #BlockPi, #Cloudflare, #PublicNode]); - - Cycles.add(candidRpcCycles); - assertOk( - "eth_getLogs", - await EvmRpcCanister.eth_getLogs( - ethMainnetSource, - { - addresses = ["0xdAC17F958D2ee523a2206206994597C13D831ec7"]; - fromBlock = null; - toBlock = null; - topics = null; - }, - ), - ); - Cycles.add(candidRpcCycles); - assertOk( - "eth_getBlockByNumber", - await EvmRpcCanister.eth_getBlockByNumber(ethMainnetSource, #Latest), - ); - Cycles.add(candidRpcCycles); - assertOk( - "eth_getTransactionReceipt", - await EvmRpcCanister.eth_getTransactionReceipt(ethMainnetSource, "0xdd5d4b18923d7aae953c7996d791118102e889bea37b48a651157a4890e4746f"), - ); - Cycles.add(candidRpcCycles); - assertOk( - "eth_getTransactionCount", - await EvmRpcCanister.eth_getTransactionCount( - ethMainnetSource, - { - address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; - block = #Latest; - }, - ), - ); - Cycles.add(candidRpcCycles); - assertOk( - "eth_feeHistory", - await EvmRpcCanister.eth_feeHistory( - ethMainnetSource, - { - blockCount = 3; - newestBlock = #Latest; - rewardPercentiles = null; - }, - ), - ); - Cycles.add(candidRpcCycles); - assertOk( - "eth_sendRawTransaction", - await EvmRpcCanister.eth_sendRawTransaction( - ethMainnetSource, - "0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83", - ), - ); - - // Signature verification - let a1 = "0xc9b28dca7ea6c5e176a58ba9df53c30ba52c6642"; - let a2 = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"; - - let m1 = #Data("hello" : Blob); - let s1 = "0x5c0e32248c10f7125b32cae1de9988f2dab686031083302f85b0a82f78e9206516b272fb7641f3e8ab63cf9f3a9b9220b2d6ff2699dc34f0d000d7693ca1ea5e1c"; - - let m2 = #Data("other" : Blob); - let s2 = "0x27ae1f90fd65c86b07aae1287dba8715db7e429ff9bf700205cb8ac904c6ba071c8fb7c6f8b5e15338521fee95a452c6a688f1c6fec5eeddbfa680a2abf300341b"; - - // Invalid address - assert not ( - await EvmRpcCanister.verifyMessageSignature({ - address = a2; - message = m1; - signature = s1; - }) - ); - - // Invalid message - assert not ( - await EvmRpcCanister.verifyMessageSignature({ - address = a1; - message = m2; - signature = s1; - }) - ); - - // Invalid signature - assert not ( - await EvmRpcCanister.verifyMessageSignature({ - address = a1; - message = m1; - signature = s2; - }) - ); - - // Valid signatures - assert ( - await EvmRpcCanister.verifyMessageSignature({ - address = a1; - message = m1; - signature = s1; - }) - ); - assert ( - await EvmRpcCanister.verifyMessageSignature({ - address = a1; - message = m2; - signature = s2; - }) - ); + let candidRpcCycles = 1_000_000_000_000; + let ethMainnetSource = #EthMainnet(?[#Ankr, #BlockPi, #Cloudflare, #PublicNode]); + + Cycles.add(candidRpcCycles); + assertOk( + "eth_getLogs", + await EvmRpcCanister.eth_getLogs( + ethMainnetSource, + { + addresses = ["0xdAC17F958D2ee523a2206206994597C13D831ec7"]; + fromBlock = null; + toBlock = null; + topics = null; + }, + ), + ); + Cycles.add(candidRpcCycles); + assertOk( + "eth_getBlockByNumber", + await EvmRpcCanister.eth_getBlockByNumber(ethMainnetSource, #Latest), + ); + Cycles.add(candidRpcCycles); + assertOk( + "eth_getTransactionReceipt", + await EvmRpcCanister.eth_getTransactionReceipt(ethMainnetSource, "0xdd5d4b18923d7aae953c7996d791118102e889bea37b48a651157a4890e4746f"), + ); + Cycles.add(candidRpcCycles); + assertOk( + "eth_getTransactionCount", + await EvmRpcCanister.eth_getTransactionCount( + ethMainnetSource, + { + address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; + block = #Latest; + }, + ), + ); + Cycles.add(candidRpcCycles); + assertOk( + "eth_feeHistory", + await EvmRpcCanister.eth_feeHistory( + ethMainnetSource, + { + blockCount = 3; + newestBlock = #Latest; + rewardPercentiles = null; + }, + ), + ); + Cycles.add(candidRpcCycles); + assertOk( + "eth_sendRawTransaction", + await EvmRpcCanister.eth_sendRawTransaction( + ethMainnetSource, + "0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83", + ), + ); + + // Signature verification + let a1 = "0xc9b28dca7ea6c5e176a58ba9df53c30ba52c6642"; + let a2 = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"; + + let m1 = #Data("hello" : Blob); + let s1 = "0x5c0e32248c10f7125b32cae1de9988f2dab686031083302f85b0a82f78e9206516b272fb7641f3e8ab63cf9f3a9b9220b2d6ff2699dc34f0d000d7693ca1ea5e1c"; + + let m2 = #Data("other" : Blob); + let s2 = "0x27ae1f90fd65c86b07aae1287dba8715db7e429ff9bf700205cb8ac904c6ba071c8fb7c6f8b5e15338521fee95a452c6a688f1c6fec5eeddbfa680a2abf300341b"; + + // Invalid address + assert not ( + await EvmRpcCanister.verifyMessageSignature({ + address = a2; + message = m1; + signature = s1; + }) + ); + + // Invalid message + assert not ( + await EvmRpcCanister.verifyMessageSignature({ + address = a1; + message = m2; + signature = s1; + }) + ); + + // Invalid signature + assert not ( + await EvmRpcCanister.verifyMessageSignature({ + address = a1; + message = m1; + signature = s2; + }) + ); + + // Valid signatures + assert ( + await EvmRpcCanister.verifyMessageSignature({ + address = a1; + message = m1; + signature = s1; + }) + ); + assert ( + await EvmRpcCanister.verifyMessageSignature({ + address = a1; + message = m2; + signature = s2; + }) + ); + }; }; }; From cd01b90deb05386eb576b7ef46bda2985f795bdb Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 19:40:42 -0700 Subject: [PATCH 04/12] Misc --- candid/evm_rpc.did | 5 ++++- dfx.json | 3 +-- e2e/motoko/Main.mo | 13 ++++++------- scripts/local | 4 +++- src/types.rs | 1 + 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/candid/evm_rpc.did b/candid/evm_rpc.did index cfe955a4..0dd24660 100644 --- a/candid/evm_rpc.did +++ b/candid/evm_rpc.did @@ -59,6 +59,9 @@ type HttpOutcallError = variant { parsingError : opt text; }; }; +type InitArgs = record { + nodesInSubnet : nat32; +}; type JsonRpcError = record { code : int64; message : text }; type JsonRpcSource = variant { Custom : record { url : text; headers : opt vec HttpHeader }; @@ -204,7 +207,7 @@ type ValidationError = variant { UrlParseError : text; InvalidHex : text; }; -service : { +service : (InitArgs) -> { authorize : (principal, Auth) -> (); deauthorize : (principal, Auth) -> (); eth_feeHistory : (RpcSource, FeeHistoryArgs) -> (MultiFeeHistoryResult); diff --git a/dfx.json b/dfx.json index 65d4cb42..57c7ac4a 100644 --- a/dfx.json +++ b/dfx.json @@ -12,8 +12,7 @@ "evm_rpc_fiduciary": { "candid": "candid/evm_rpc.did", "type": "rust", - "package": "evm_rpc", - "args": "(opt record {nodes_in_subnet = 28})" + "package": "evm_rpc" }, "e2e_rust": { "dependencies": ["evm_rpc", "evm_rpc_fiduciary"], diff --git a/e2e/motoko/Main.mo b/e2e/motoko/Main.mo index 09c4feb6..f9d209cc 100644 --- a/e2e/motoko/Main.mo +++ b/e2e/motoko/Main.mo @@ -13,10 +13,10 @@ shared ({ caller = installer }) actor class Main() { assert caller == installer; let canisterDetails = [ - (EvmRpcCanister, "default", 13), - (EvmRpcFidicuaryCanister, "fiduciary", 28), + (EvmRpcCanister, "default", 13, 521_498_000), + (EvmRpcFidicuaryCanister, "fiduciary", 28, 55555), ]; - for ((canister, name, nodesInSubnet) in canisterDetails.vals()) { + for ((canister, name, nodesInSubnet, expectedCycles) in canisterDetails.vals()) { Debug.print("Testing " # name # " canister..."); let mainnet = Evm.Rpc( @@ -42,9 +42,8 @@ shared ({ caller = installer }) actor class Main() { Debug.trap("unexpected error for `request_cost`: " # (debug_show err)); }; }; - let expectedCycles = 521_498_000 * nodesInSubnet / 13; if (cycles != expectedCycles) { - Debug.trap("unexpected number of cycles: " # debug_show cycles # " (expected " # debug_show expectedCycles # ")"); + Debug.trap("unexpected number of cycles for " # name # " canister: " # debug_show cycles # " (expected " # debug_show expectedCycles # ")"); }; // `request()` without cycles @@ -162,10 +161,10 @@ shared ({ caller = installer }) actor class Main() { let a1 = "0xc9b28dca7ea6c5e176a58ba9df53c30ba52c6642"; let a2 = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"; - let m1 = #Data("hello" : Blob); + let m1 = #Data(Blob.toArray("hello")); let s1 = "0x5c0e32248c10f7125b32cae1de9988f2dab686031083302f85b0a82f78e9206516b272fb7641f3e8ab63cf9f3a9b9220b2d6ff2699dc34f0d000d7693ca1ea5e1c"; - let m2 = #Data("other" : Blob); + let m2 = #Data(Blob.toArray("other")); let s2 = "0x27ae1f90fd65c86b07aae1287dba8715db7e429ff9bf700205cb8ac904c6ba071c8fb7c6f8b5e15338521fee95a452c6a688f1c6fec5eeddbfa680a2abf300341b"; // Invalid address diff --git a/scripts/local b/scripts/local index e3e1c87c..e73b0a48 100755 --- a/scripts/local +++ b/scripts/local @@ -5,7 +5,9 @@ CANISTER_ID=evm_rpc PRINCIPAL=$(dfx identity get-principal) -dfx deploy $CANISTER_ID --mode reinstall -y +dfx deploy evm_rpc --argument "(record {nodesInSubnet = 13})" --mode reinstall -y +dfx deploy evm_rpc_fiduciary --argument "(record {nodesInSubnet = 26})" --mode reinstall -y + dfx canister call $CANISTER_ID authorize "(principal \"$PRINCIPAL\", variant { RegisterProvider })" dfx canister call $CANISTER_ID registerProvider '(record {hostname = "cloudflare-eth.com"; credentialPath = "/v1/mainnet"; chainId = 1; cyclesPerCall = 1000; cyclesPerMessageByte = 100})' diff --git a/src/types.rs b/src/types.rs index cd5f6332..950c842c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,6 +17,7 @@ use crate::{AUTH_SET_STORABLE_MAX_SIZE, PROVIDERS}; #[derive(Clone, Debug, CandidType, Deserialize)] pub struct InitArgs { + #[serde(rename = "nodesInSubnet")] pub nodes_in_subnet: u32, } From cb680469c1e72151c269a83a6f3ddc615543ac4e Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 20:12:17 -0700 Subject: [PATCH 05/12] Update E2E test --- e2e/motoko/Main.mo | 32 ++++++++++++++++---------------- scripts/local | 1 + src/main.rs | 7 +++---- tests/tests.rs | 6 +++++- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/e2e/motoko/Main.mo b/e2e/motoko/Main.mo index f9d209cc..6dafdd3f 100644 --- a/e2e/motoko/Main.mo +++ b/e2e/motoko/Main.mo @@ -14,7 +14,7 @@ shared ({ caller = installer }) actor class Main() { let canisterDetails = [ (EvmRpcCanister, "default", 13, 521_498_000), - (EvmRpcFidicuaryCanister, "fiduciary", 28, 55555), + (EvmRpcFidicuaryCanister, "fiduciary", 28, 1_042_996_000), ]; for ((canister, name, nodesInSubnet, expectedCycles) in canisterDetails.vals()) { Debug.print("Testing " # name # " canister..."); @@ -35,7 +35,7 @@ shared ({ caller = installer }) actor class Main() { let maxResponseBytes : Nat64 = 1000; // `requestCost()` - let cyclesResult = await EvmRpcCanister.requestCost(source, json, maxResponseBytes); + let cyclesResult = await canister.requestCost(source, json, maxResponseBytes); let cycles = switch cyclesResult { case (#Ok cycles) { cycles }; case (#Err err) { @@ -47,7 +47,7 @@ shared ({ caller = installer }) actor class Main() { }; // `request()` without cycles - let resultWithoutCycles = await EvmRpcCanister.request(source, json, maxResponseBytes); + let resultWithoutCycles = await canister.request(source, json, maxResponseBytes); assert switch resultWithoutCycles { case (#Err(#ProviderError(#TooFewCycles { expected }))) expected == cycles; case _ false; @@ -74,10 +74,10 @@ shared ({ caller = installer }) actor class Main() { }; // Candid-RPC methods - type RpcResult = { #Ok : T; #Err : EvmRpcCanister.RpcError }; + type RpcResult = { #Ok : T; #Err : canister.RpcError }; type MultiRpcResult = { #Consistent : RpcResult; - #Inconsistent : [(EvmRpcCanister.RpcService, RpcResult)]; + #Inconsistent : [(canister.RpcService, RpcResult)]; }; func assertOk(method : Text, result : MultiRpcResult) { @@ -105,7 +105,7 @@ shared ({ caller = installer }) actor class Main() { Cycles.add(candidRpcCycles); assertOk( "eth_getLogs", - await EvmRpcCanister.eth_getLogs( + await canister.eth_getLogs( ethMainnetSource, { addresses = ["0xdAC17F958D2ee523a2206206994597C13D831ec7"]; @@ -118,17 +118,17 @@ shared ({ caller = installer }) actor class Main() { Cycles.add(candidRpcCycles); assertOk( "eth_getBlockByNumber", - await EvmRpcCanister.eth_getBlockByNumber(ethMainnetSource, #Latest), + await canister.eth_getBlockByNumber(ethMainnetSource, #Latest), ); Cycles.add(candidRpcCycles); assertOk( "eth_getTransactionReceipt", - await EvmRpcCanister.eth_getTransactionReceipt(ethMainnetSource, "0xdd5d4b18923d7aae953c7996d791118102e889bea37b48a651157a4890e4746f"), + await canister.eth_getTransactionReceipt(ethMainnetSource, "0xdd5d4b18923d7aae953c7996d791118102e889bea37b48a651157a4890e4746f"), ); Cycles.add(candidRpcCycles); assertOk( "eth_getTransactionCount", - await EvmRpcCanister.eth_getTransactionCount( + await canister.eth_getTransactionCount( ethMainnetSource, { address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; @@ -139,7 +139,7 @@ shared ({ caller = installer }) actor class Main() { Cycles.add(candidRpcCycles); assertOk( "eth_feeHistory", - await EvmRpcCanister.eth_feeHistory( + await canister.eth_feeHistory( ethMainnetSource, { blockCount = 3; @@ -151,7 +151,7 @@ shared ({ caller = installer }) actor class Main() { Cycles.add(candidRpcCycles); assertOk( "eth_sendRawTransaction", - await EvmRpcCanister.eth_sendRawTransaction( + await canister.eth_sendRawTransaction( ethMainnetSource, "0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83", ), @@ -169,7 +169,7 @@ shared ({ caller = installer }) actor class Main() { // Invalid address assert not ( - await EvmRpcCanister.verifyMessageSignature({ + await canister.verifyMessageSignature({ address = a2; message = m1; signature = s1; @@ -178,7 +178,7 @@ shared ({ caller = installer }) actor class Main() { // Invalid message assert not ( - await EvmRpcCanister.verifyMessageSignature({ + await canister.verifyMessageSignature({ address = a1; message = m2; signature = s1; @@ -187,7 +187,7 @@ shared ({ caller = installer }) actor class Main() { // Invalid signature assert not ( - await EvmRpcCanister.verifyMessageSignature({ + await canister.verifyMessageSignature({ address = a1; message = m1; signature = s2; @@ -196,14 +196,14 @@ shared ({ caller = installer }) actor class Main() { // Valid signatures assert ( - await EvmRpcCanister.verifyMessageSignature({ + await canister.verifyMessageSignature({ address = a1; message = m1; signature = s1; }) ); assert ( - await EvmRpcCanister.verifyMessageSignature({ + await canister.verifyMessageSignature({ address = a1; message = m2; signature = s2; diff --git a/scripts/local b/scripts/local index e73b0a48..62b9b594 100755 --- a/scripts/local +++ b/scripts/local @@ -5,6 +5,7 @@ CANISTER_ID=evm_rpc PRINCIPAL=$(dfx identity get-principal) +dfx canister create --all dfx deploy evm_rpc --argument "(record {nodesInSubnet = 13})" --mode reinstall -y dfx deploy evm_rpc_fiduciary --argument "(record {nodesInSubnet = 26})" --mode reinstall -y diff --git a/src/main.rs b/src/main.rs index ecd7bc1d..d4594c29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -241,10 +241,9 @@ fn transform(args: TransformArgs) -> HttpResponse { } #[ic_cdk::init] -fn init(args: Option) { - if let Some(args) = args { - TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow_mut() = args.nodes_in_subnet); - } +fn init(args: InitArgs) { + TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow_mut() = args.nodes_in_subnet); + METADATA.with(|m| { let mut metadata = m.borrow().get().clone(); metadata.open_rpc_access = DEFAULT_OPEN_RPC_ACCESS; diff --git a/tests/tests.rs b/tests/tests.rs index f5a559f9..72145869 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -77,6 +77,10 @@ impl EvmRpcSetup { .build(), ); + let args = InitArgs { + nodes_in_subnet: DEFAULT_NODES_IN_SUBNET, + }; + let controller = PrincipalId::new_user_test_id(DEFAULT_CONTROLLER_TEST_ID); let canister_id = env.create_canister_with_cycles( None, @@ -87,7 +91,7 @@ impl EvmRpcSetup { .build(), ), ); - env.install_existing_canister(canister_id, evm_rpc_wasm(), Encode!(&()).unwrap()) + env.install_existing_canister(canister_id, evm_rpc_wasm(), Encode!(&args).unwrap()) .unwrap(); let caller = PrincipalId::new_user_test_id(DEFAULT_CALLER_TEST_ID); From 08d54c50776491978abf952d5522808ce6d41320 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 20:14:54 -0700 Subject: [PATCH 06/12] Replace 'service_equal' check with 'service_compatible' --- src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index d4594c29..3e7ab64f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -356,7 +356,7 @@ fn test_candid_interface() { } } - fn check_service_equal( + fn check_service_compatible( new_name: &str, new: candid::utils::CandidSource, old_name: &str, @@ -364,7 +364,7 @@ fn test_candid_interface() { ) { let new_str = source_to_str(&new); let old_str = source_to_str(&old); - match candid::utils::service_equal(new, old) { + match candid::utils::service_compatible(new, old) { Ok(_) => {} Err(e) => { eprintln!( @@ -387,7 +387,7 @@ fn test_candid_interface() { let old_interface = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) .join("candid/evm_rpc.did"); - check_service_equal( + check_service_compatible( "actual ledger candid interface", candid::utils::CandidSource::Text(&new_interface), "declared candid interface in evm_rpc.did file", From 7692193ec4f79af067e5224c7da4fec6173ade24 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 20:16:22 -0700 Subject: [PATCH 07/12] Update CI --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb0da72a..e75f3b76 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,7 +68,10 @@ jobs: run: npm ci - name: Deploy EVM RPC - run: dfx deploy evm_rpc + run: dfx deploy evm_rpc --argument "(variant {nodesInSubnet = 13})" + + - name: Deploy EVM RPC on fidicuary subnet + run: dfx deploy evm_rpc_fiduciary --argument "(variant {nodesInSubnet = 28})" - name: Generate language bindings run: npm run generate From 7c4fb1cbb9bd4d451d083bcd79b1430850eda767 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 20:17:06 -0700 Subject: [PATCH 08/12] Clarify --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e75f3b76..8f1e2c9a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,7 +70,7 @@ jobs: - name: Deploy EVM RPC run: dfx deploy evm_rpc --argument "(variant {nodesInSubnet = 13})" - - name: Deploy EVM RPC on fidicuary subnet + - name: Deploy EVM RPC fiduciary canister run: dfx deploy evm_rpc_fiduciary --argument "(variant {nodesInSubnet = 28})" - name: Generate language bindings From 366a9bc243bfbe548699cc9f3faa7a5d44340324 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 20:37:17 -0700 Subject: [PATCH 09/12] Fix --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f1e2c9a..4a075160 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,10 +68,10 @@ jobs: run: npm ci - name: Deploy EVM RPC - run: dfx deploy evm_rpc --argument "(variant {nodesInSubnet = 13})" + run: dfx deploy evm_rpc --argument "(record {nodesInSubnet = 13})" - name: Deploy EVM RPC fiduciary canister - run: dfx deploy evm_rpc_fiduciary --argument "(variant {nodesInSubnet = 28})" + run: dfx deploy evm_rpc_fiduciary --argument "(record {nodesInSubnet = 28})" - name: Generate language bindings run: npm run generate From 13ff27b130f18cab784d7ae37c0620c4ce03e77b Mon Sep 17 00:00:00 2001 From: rvanasa Date: Tue, 2 Jan 2024 20:47:46 -0700 Subject: [PATCH 10/12] Misc --- e2e/motoko/Main.mo | 2 +- scripts/local | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/motoko/Main.mo b/e2e/motoko/Main.mo index 6dafdd3f..d692254c 100644 --- a/e2e/motoko/Main.mo +++ b/e2e/motoko/Main.mo @@ -14,7 +14,7 @@ shared ({ caller = installer }) actor class Main() { let canisterDetails = [ (EvmRpcCanister, "default", 13, 521_498_000), - (EvmRpcFidicuaryCanister, "fiduciary", 28, 1_042_996_000), + (EvmRpcFidicuaryCanister, "fiduciary", 28, 1_123_226_461), ]; for ((canister, name, nodesInSubnet, expectedCycles) in canisterDetails.vals()) { Debug.print("Testing " # name # " canister..."); diff --git a/scripts/local b/scripts/local index 62b9b594..4cf61e7a 100755 --- a/scripts/local +++ b/scripts/local @@ -7,7 +7,7 @@ PRINCIPAL=$(dfx identity get-principal) dfx canister create --all dfx deploy evm_rpc --argument "(record {nodesInSubnet = 13})" --mode reinstall -y -dfx deploy evm_rpc_fiduciary --argument "(record {nodesInSubnet = 26})" --mode reinstall -y +dfx deploy evm_rpc_fiduciary --argument "(record {nodesInSubnet = 28})" --mode reinstall -y dfx canister call $CANISTER_ID authorize "(principal \"$PRINCIPAL\", variant { RegisterProvider })" From 418273ff14e48fd4d65d68f9a69d4ff46ef79ee1 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Wed, 3 Jan 2024 15:11:27 -0700 Subject: [PATCH 11/12] Update Motoko E2E test --- e2e/motoko/Main.mo | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/e2e/motoko/Main.mo b/e2e/motoko/Main.mo index d692254c..b066eb35 100644 --- a/e2e/motoko/Main.mo +++ b/e2e/motoko/Main.mo @@ -13,6 +13,7 @@ shared ({ caller = installer }) actor class Main() { assert caller == installer; let canisterDetails = [ + // (`canister module`, `debug name`, `nodes in subnet`, `expected cycles for JSON-RPC call`) (EvmRpcCanister, "default", 13, 521_498_000), (EvmRpcFidicuaryCanister, "fiduciary", 28, 1_123_226_461), ]; @@ -73,6 +74,14 @@ shared ({ caller = installer }) actor class Main() { Debug.trap(debug_show result); }; + // `request()` without sufficient cycles + let resultWithoutEnoughCycles = await canister.request(source, json, maxResponseBytes); + Cycles.add(cycles - 1); + assert switch resultWithoutEnoughCycles { + case (#Err(#ProviderError(#TooFewCycles { expected }))) expected == cycles; + case _ false; + }; + // Candid-RPC methods type RpcResult = { #Ok : T; #Err : canister.RpcError }; type MultiRpcResult = { @@ -102,6 +111,13 @@ shared ({ caller = installer }) actor class Main() { let candidRpcCycles = 1_000_000_000_000; let ethMainnetSource = #EthMainnet(?[#Ankr, #BlockPi, #Cloudflare, #PublicNode]); + switch (await canister.eth_getBlockByNumber(ethMainnetSource, #Latest)) { + case (#Consistent(#Err(#ProviderError(#TooFewCycles _)))) {}; + case result { + Debug.trap("received unexpected result: " # debug_show result); + }; + }; + Cycles.add(candidRpcCycles); assertOk( "eth_getLogs", From b4b4c2808810189881d2fcb0717944e16a90f87a Mon Sep 17 00:00:00 2001 From: rvanasa Date: Wed, 3 Jan 2024 15:14:59 -0700 Subject: [PATCH 12/12] Rename prefix 'TRANSIENT_' -> 'UNSTABLE_' --- src/accounting.rs | 4 ++-- src/candid_rpc.rs | 2 +- src/main.rs | 2 +- src/memory.rs | 6 +++--- src/metrics.rs | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/accounting.rs b/src/accounting.rs index 815c7967..673c6677 100644 --- a/src/accounting.rs +++ b/src/accounting.rs @@ -35,7 +35,7 @@ pub fn get_http_request_cost( json_rpc_payload: &str, max_response_bytes: u64, ) -> u128 { - let nodes_in_subnet = TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow()); + let nodes_in_subnet = UNSTABLE_SUBNET_SIZE.with(|m| *m.borrow()); let ingress_bytes = (json_rpc_payload.len() + api.url.len()) as u128 + INGRESS_OVERHEAD_BYTES; let base_cost = INGRESS_MESSAGE_RECEIVED_COST + INGRESS_MESSAGE_BYTE_RECEIVED_COST * ingress_bytes @@ -46,7 +46,7 @@ pub fn get_http_request_cost( /// Calculate the additional cost for calling a registered JSON-RPC provider. pub fn get_provider_cost(provider: &Provider, json_rpc_payload: &str) -> u128 { - let nodes_in_subnet = TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow()); + let nodes_in_subnet = UNSTABLE_SUBNET_SIZE.with(|m| *m.borrow()); let cost_per_node = provider.cycles_per_call as u128 + provider.cycles_per_message_byte as u128 * json_rpc_payload.len() as u128; cost_per_node * (nodes_in_subnet as u128) diff --git a/src/candid_rpc.rs b/src/candid_rpc.rs index 52d65f55..00188bd3 100644 --- a/src/candid_rpc.rs +++ b/src/candid_rpc.rs @@ -24,7 +24,7 @@ struct CanisterTransport; #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl RpcTransport for CanisterTransport { fn get_subnet_size() -> u32 { - TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow()) + UNSTABLE_SUBNET_SIZE.with(|m| *m.borrow()) } fn resolve_api(provider: &RpcService) -> Result { diff --git a/src/main.rs b/src/main.rs index 3e7ab64f..d03a4f01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -242,7 +242,7 @@ fn transform(args: TransformArgs) -> HttpResponse { #[ic_cdk::init] fn init(args: InitArgs) { - TRANSIENT_SUBNET_SIZE.with(|m| *m.borrow_mut() = args.nodes_in_subnet); + UNSTABLE_SUBNET_SIZE.with(|m| *m.borrow_mut() = args.nodes_in_subnet); METADATA.with(|m| { let mut metadata = m.borrow().get().clone(); diff --git a/src/memory.rs b/src/memory.rs index c2319f4b..24791886 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -19,9 +19,9 @@ declare_log_buffer!(name = INFO, capacity = 1000); declare_log_buffer!(name = ERROR, capacity = 1000); thread_local! { - // Transient static data: this is reset when the canister is upgraded. - pub static TRANSIENT_METRICS: RefCell = RefCell::new(Metrics::default()); - pub static TRANSIENT_SUBNET_SIZE: RefCell = RefCell::new(DEFAULT_NODES_IN_SUBNET); + // Unstable static data: this is reset when the canister is upgraded. + pub static UNSTABLE_METRICS: RefCell = RefCell::new(Metrics::default()); + pub static UNSTABLE_SUBNET_SIZE: RefCell = RefCell::new(DEFAULT_NODES_IN_SUBNET); // Stable static data: this is preserved when the canister is upgraded. #[cfg(not(target_arch = "wasm32"))] diff --git a/src/metrics.rs b/src/metrics.rs index b9beb78d..ea989146 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -1,14 +1,14 @@ #[macro_export] macro_rules! inc_metric { ($metric:ident) => {{ - $crate::TRANSIENT_METRICS.with(|m| m.borrow_mut().$metric += 1); + $crate::UNSTABLE_METRICS.with(|m| m.borrow_mut().$metric += 1); }}; } #[macro_export] macro_rules! inc_metric_entry { ($metric:ident, $entry:expr) => {{ - $crate::TRANSIENT_METRICS.with(|m| { + $crate::UNSTABLE_METRICS.with(|m| { m.borrow_mut() .$metric .entry($entry.clone()) @@ -21,14 +21,14 @@ macro_rules! inc_metric_entry { #[macro_export] macro_rules! add_metric { ($metric:ident, $value:expr) => {{ - $crate::TRANSIENT_METRICS.with(|m| m.borrow_mut().$metric += $value); + $crate::UNSTABLE_METRICS.with(|m| m.borrow_mut().$metric += $value); }}; } #[macro_export] macro_rules! get_metric { ($metric:ident) => {{ - $crate::TRANSIENT_METRICS.with(|m| m.borrow().$metric) + $crate::UNSTABLE_METRICS.with(|m| m.borrow().$metric) }}; } @@ -58,7 +58,7 @@ pub fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> st get_metric!(request_cycles_refunded) as f64, "Cycles refunded by request() calls.", )?; - crate::TRANSIENT_METRICS.with(|m| { + crate::UNSTABLE_METRICS.with(|m| { m.borrow() .host_requests .iter()