Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: refine cycles cost calculation #143

Merged
merged 7 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions e2e/motoko/Main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ shared ({ caller = installer }) actor class Main() {

let canisterDetails = [
// (`canister module`, `debug name`, `nodes in subnet`, `expected cycles for JSON-RPC call`)
(EvmRpcCanister, "default", 13, 65_923_200),
(EvmRpcFidicuaryCanister, "fiduciary", 28, 141_988_430),
(EvmRpcCanister, "default", 13, 61_898_400),
(EvmRpcFidicuaryCanister, "fiduciary", 28, 133_319_630),
Comment on lines +22 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should document somewhere how these numbers are derived.
Maybe such details could be discussed on a wiki page (which the EVM RPC canister should definitely get). What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely. The calculation for these numbers is explained in the design document, which we could transfer to a wiki page.

];
for ((canister, name, nodesInSubnet, expectedCycles) in canisterDetails.vals()) {
Debug.print("Testing " # name # " canister...");
Expand Down
33 changes: 22 additions & 11 deletions src/accounting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ pub fn get_http_request_cost(
+ INGRESS_OVERHEAD_BYTES;
let base_cost = INGRESS_MESSAGE_RECEIVED_COST
+ INGRESS_MESSAGE_BYTE_RECEIVED_COST * ingress_bytes
+ HTTP_OUTCALL_REQUEST_COST
+ HTTP_OUTCALL_BYTE_RECEIVED_COST * (ingress_bytes + max_response_bytes as u128);
+ HTTP_OUTCALL_REQUEST_BASE_COST
+ HTTP_OUTCALL_REQUEST_COST_PER_BYTE * payload_size_bytes as u128
+ HTTP_OUTCALL_RESPONSE_COST_PER_BYTE * max_response_bytes as u128;
base_cost * (nodes_in_subnet as u128) / NODES_IN_DEFAULT_SUBNET as u128
}

Expand Down Expand Up @@ -80,7 +81,7 @@ fn test_request_cost() {
1000,
);
let estimated_cost_10_extra_bytes = base_cost
+ 10 * (INGRESS_MESSAGE_BYTE_RECEIVED_COST + HTTP_OUTCALL_BYTE_RECEIVED_COST)
+ 10 * (INGRESS_MESSAGE_BYTE_RECEIVED_COST + HTTP_OUTCALL_REQUEST_COST_PER_BYTE)
* nodes_in_subnet as u128
/ NODES_IN_DEFAULT_SUBNET as u128;
// Request body with 10 additional bytes should be within 1 cycle of expected cost (due to rounding)
Expand Down Expand Up @@ -155,15 +156,25 @@ fn test_candid_rpc_cost() {
let provider = PROVIDERS.with(|providers| providers.borrow().get(&provider_id).unwrap());

// Default subnet
assert_eq!(get_candid_rpc_cost(&provider, 0, 0), 54767387);
assert_eq!(get_candid_rpc_cost(&provider, 123, 123), 59170787);
assert_eq!(get_candid_rpc_cost(&provider, 123, 4567890), 47563947587);
assert_eq!(get_candid_rpc_cost(&provider, 890, 4567890), 47583429387);
assert_eq!(
[
get_candid_rpc_cost(&provider, 0, 0),
get_candid_rpc_cost(&provider, 123, 123),
get_candid_rpc_cost(&provider, 123, 4567890),
get_candid_rpc_cost(&provider, 890, 4567890),
],
[51064987, 54828787, 47559605587, 47575098987]
);

// Fiduciary subnet
UNSTABLE_SUBNET_SIZE.with(|n| *n.borrow_mut() = NODES_IN_FIDUCIARY_SUBNET);
assert_eq!(get_candid_rpc_cost(&provider, 0, 0), 117960525);
assert_eq!(get_candid_rpc_cost(&provider, 123, 123), 127444772);
assert_eq!(get_candid_rpc_cost(&provider, 123, 4567890), 102445425572);
assert_eq!(get_candid_rpc_cost(&provider, 890, 4567890), 102487386372);
assert_eq!(
[
get_candid_rpc_cost(&provider, 0, 0),
get_candid_rpc_cost(&provider, 123, 123),
get_candid_rpc_cost(&provider, 123, 4567890),
get_candid_rpc_cost(&provider, 890, 4567890),
],
[109986125, 118092772, 102436073572, 102469443972]
);
}
5 changes: 3 additions & 2 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use cketh_common::eth_rpc_client::providers::{EthMainnetService, EthSepoliaServi
pub const INGRESS_OVERHEAD_BYTES: u128 = 100;
pub const INGRESS_MESSAGE_RECEIVED_COST: u128 = 1_200_000;
pub const INGRESS_MESSAGE_BYTE_RECEIVED_COST: u128 = 2_000;
pub const HTTP_OUTCALL_REQUEST_COST: u128 = 49_140_000;
pub const HTTP_OUTCALL_BYTE_RECEIVED_COST: u128 = 10_400;
pub const HTTP_OUTCALL_REQUEST_BASE_COST: u128 = 49_140_000;
pub const HTTP_OUTCALL_REQUEST_COST_PER_BYTE: u128 = 5_200;
pub const HTTP_OUTCALL_RESPONSE_COST_PER_BYTE: u128 = 10_400;

// Minimum number of bytes charged for a URL; improves consistency of costs between providers
pub const RPC_URL_MIN_COST_BYTES: u32 = 256;
Expand Down