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

Add tests that cover fees for each individual resource. #1192

Merged
merged 2 commits into from
Nov 10, 2023
Merged
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
302 changes: 299 additions & 3 deletions soroban-env-host/tests/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,302 @@ fn ttl_entry_size() {
);
}

fn change_resource<T>(func: T) -> TransactionResources
where
T: FnOnce(&mut TransactionResources) -> (),
{
let mut resources = TransactionResources {
instructions: 0,
read_entries: 0,
write_entries: 0,
read_bytes: 0,
write_bytes: 0,
contract_events_size_bytes: 0,
transaction_size_bytes: 0,
};
func(&mut resources);
resources
}

#[test]
fn resource_fee_computation_with_single_resource() {
// Historical fee is always paid for 300 byte of transaction result.
// ceil(6000 * 300 / 1024) == 1758
const BASE_HISTORICAL_FEE: i64 = 1758;
let fee_config = FeeConfiguration {
fee_per_instruction_increment: 1000,
fee_per_read_entry: 2000,
fee_per_write_entry: 3000,
fee_per_read_1kb: 4000,
fee_per_write_1kb: 5000,
fee_per_historical_1kb: 6000,
fee_per_contract_event_1kb: 7000,
fee_per_transaction_size_1kb: 8000,
};

// Instructions
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.instructions = 1;
}),
&fee_config,
),
(1 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.instructions = 10000;
}),
&fee_config,
),
(1000 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.instructions = 123_451_234;
}),
&fee_config,
),
(12_345_124 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.instructions = u32::MAX;
}),
&fee_config,
),
(429_496_730 + BASE_HISTORICAL_FEE, 0)
);

// Read entries
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_entries = 1;
}),
&fee_config,
),
(2000 * 1 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_entries = 5;
}),
&fee_config,
),
(2000 * 5 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_entries = u32::MAX;
}),
&fee_config,
),
(8_589_934_590_000 + BASE_HISTORICAL_FEE, 0)
);

// Write entries
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_entries = 1;
}),
&fee_config,
),
// Write entries are also counted towards the read entry fee.
(2000 + 3000 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_entries = 5;
}),
&fee_config,
),
((2000 + 3000) * 5 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_entries = u32::MAX;
}),
&fee_config,
),
(
8_589_934_590_000 + 12_884_901_885_000 + BASE_HISTORICAL_FEE,
0
)
);

// Read bytes
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_bytes = 1;
}),
&fee_config,
),
// ceil(1 * 4000 / 1024) = 4
(4 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_bytes = 5 * 1024;
}),
&fee_config,
),
(5 * 4000 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_bytes = 5 * 1024 + 1;
}),
&fee_config,
),
(20_004 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.read_bytes = u32::MAX;
}),
&fee_config,
),
(16_777_215_997 + BASE_HISTORICAL_FEE, 0)
);

// Write bytes
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_bytes = 1;
}),
&fee_config,
),
// ceil(1 * 5000 / 1024) = 4
(5 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_bytes = 5 * 1024;
}),
&fee_config,
),
(5 * 5000 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_bytes = 5 * 1024 + 1;
}),
&fee_config,
),
(25_005 + BASE_HISTORICAL_FEE, 0)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.write_bytes = u32::MAX;
}),
&fee_config,
),
(20_971_519_996 + BASE_HISTORICAL_FEE, 0)
);

// Transaction size (affected by historical + tx size fees)
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.transaction_size_bytes = 1;
}),
&fee_config,
),
// Historical fee: ceil(1 * 6000 / 1024) = 6
// Tx size fee: ceil(1 * 8000 / 1024) = 8
(6 + 8 + BASE_HISTORICAL_FEE, 0)
);

assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.transaction_size_bytes = 5 * 1024;
}),
&fee_config,
),
((6000 + 8000) * 5 + BASE_HISTORICAL_FEE, 0)
);

assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.transaction_size_bytes = 5 * 1024 + 1;
}),
&fee_config,
),
(30_006 + 40_008 + BASE_HISTORICAL_FEE, 0)
);

assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.transaction_size_bytes = u32::MAX;
}),
&fee_config,
),
// BASE_HISTORICAL_FEE is omitted as it's saturated with overall
// `transaction_size_bytes`.
(25_165_823_995 + 33_554_431_993, 0)
);

// Events size
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.contract_events_size_bytes = 1;
}),
&fee_config,
),
// ceil(1 * 7000 / 1024) = 7
(BASE_HISTORICAL_FEE, 7)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.contract_events_size_bytes = 5 * 1024;
}),
&fee_config,
),
(BASE_HISTORICAL_FEE, 5 * 7000)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.contract_events_size_bytes = 5 * 1024 + 1;
}),
&fee_config,
),
(BASE_HISTORICAL_FEE, 35_007)
);
assert_eq!(
compute_transaction_resource_fee(
&change_resource(|res: &mut TransactionResources| {
res.contract_events_size_bytes = u32::MAX;
}),
&fee_config,
),
(BASE_HISTORICAL_FEE, 29_360_127_994)
);
}

#[test]
fn resource_fee_computation() {
// No resources
Expand Down Expand Up @@ -299,7 +595,7 @@ fn test_rent_extend_fees_with_only_extend() {
new_size_bytes: 10 * 1024,
old_live_until_ledger: 100_000,
new_live_until_ledger: 300_000,
}
},
],
&fee_config,
50_000,
Expand Down Expand Up @@ -405,7 +701,7 @@ fn test_rent_extend_fees_with_only_size_change() {
new_size_bytes: 100_000,
old_live_until_ledger: 100_000,
new_live_until_ledger: 100_000,
}
},
],
&fee_config,
25_000,
Expand Down Expand Up @@ -479,7 +775,7 @@ fn test_rent_extend_with_size_change_and_extend() {
new_size_bytes: 100_000,
old_live_until_ledger: 100_000,
new_live_until_ledger: 300_000,
}
},
],
&fee_config,
25_000,
Expand Down