@@ -1406,7 +1406,7 @@ fn garbage_collect_local_state_with_legal_reject_signal_for_response_success() {
1406
1406
) ;
1407
1407
}
1408
1408
1409
- /// Tests that garbage collecting with a legal reject signal does raise a critical error.
1409
+ /// Tests that garbage collecting with an illegal reject signal does raise a critical error.
1410
1410
#[ test]
1411
1411
fn garbage_collect_local_state_with_illegal_reject_signal_for_response_success ( ) {
1412
1412
garbage_collect_local_state_with_reject_signals_for_response_success_impl (
@@ -1504,6 +1504,16 @@ fn garbage_collect_local_state_with_reject_signals_for_request_from_absent_canis
1504
1504
..StreamConfig :: default ( )
1505
1505
} ) ;
1506
1506
expected_state. with_streams ( btreemap ! [ REMOTE_SUBNET => expected_stream] ) ;
1507
+ // Cycles attached to the request / reject response are lost.
1508
+ expected_state
1509
+ . metadata
1510
+ . subnet_metrics
1511
+ . observe_consumed_cycles_with_use_case (
1512
+ DroppedMessages ,
1513
+ message_in_stream ( state. get_stream ( & REMOTE_SUBNET ) , 21 )
1514
+ . cycles ( )
1515
+ . into ( ) ,
1516
+ ) ;
1507
1517
1508
1518
// Act and compare to expected.
1509
1519
let mut available_guaranteed_response_memory =
@@ -1537,7 +1547,7 @@ fn garbage_collect_local_state_with_reject_signals_for_request_from_absent_canis
1537
1547
1538
1548
/// Tests that an incoming reject signal for a request to and from `LOCAL_CANISTER` in the stream
1539
1549
/// to `REMOTE_SUBNET` triggers locally generating a reject response that is successfully inducted
1540
- /// but the misrouted request (it should be in the loopback stream) raises a critical error.
1550
+ /// but the misrouted request (it should have been in the loopback stream) raises a critical error.
1541
1551
#[ test]
1542
1552
fn garbage_collect_local_state_with_reject_signals_for_misrouted_request ( ) {
1543
1553
with_test_setup (
@@ -1674,7 +1684,7 @@ fn garbage_collect_local_state_with_reject_signals_for_request_from_migrating_ca
1674
1684
/// Calls `induct_stream_slices()` with one stream slice coming from `CANISTER_MIGRATION_SUBNET`
1675
1685
/// as input containing 3 messages:
1676
1686
/// - a reject response for a request sent to `REMOTE_CANISTER` from `LOCAL_CANISTER`,
1677
- /// - a data response with the same recipients.
1687
+ /// - a reply with the same recipients.
1678
1688
/// - and a request with the same recipients.
1679
1689
///
1680
1690
/// `LOCAL_CANISTER` is marked as having migrated from `CANISTER_MIGRATION_SUBNET` to
@@ -1696,9 +1706,9 @@ fn induct_stream_slices_reject_response_from_old_host_subnet_is_accepted() {
1696
1706
messages: vec![
1697
1707
// ...a reject response for a request sent to `REMOTE_CANISTER` @0...
1698
1708
RejectResponse ( * REMOTE_CANISTER , * LOCAL_CANISTER , RejectReason :: QueueFull ) ,
1699
- // ...a data response @1...
1709
+ // ...a reply @1...
1700
1710
Response ( * REMOTE_CANISTER , * LOCAL_CANISTER ) ,
1701
- // ...and a request from @2.
1711
+ // ...and a request @2.
1702
1712
Request ( * REMOTE_CANISTER , * LOCAL_CANISTER ) ,
1703
1713
] ,
1704
1714
..StreamSliceConfig :: default ( )
@@ -1726,6 +1736,14 @@ fn induct_stream_slices_reject_response_from_old_host_subnet_is_accepted() {
1726
1736
} ) ;
1727
1737
expected_state. with_streams ( btreemap ! [ CANISTER_MIGRATION_SUBNET => expected_stream] ) ;
1728
1738
1739
+ // Cycles attached to the dropped reply and request are lost.
1740
+ let cycles_lost = messages_in_slice ( slices. get ( & CANISTER_MIGRATION_SUBNET ) , 1 ..=2 )
1741
+ . fold ( Cycles :: zero ( ) , |acc, msg| acc + msg. cycles ( ) ) ;
1742
+ expected_state
1743
+ . metadata
1744
+ . subnet_metrics
1745
+ . observe_consumed_cycles_with_use_case ( DroppedMessages , cycles_lost. into ( ) ) ;
1746
+
1729
1747
let mut available_guaranteed_response_memory =
1730
1748
stream_handler. available_guaranteed_response_memory ( & state) ;
1731
1749
let inducted_state = stream_handler. induct_stream_slices (
@@ -1976,8 +1994,11 @@ fn check_stream_handler_generated_reject_signal_queue_full() {
1976
1994
let mut callback_id = 2 ;
1977
1995
while state
1978
1996
. push_input (
1979
- Request ( * LOCAL_CANISTER , * LOCAL_CANISTER )
1980
- . build_with ( CallbackId :: new ( callback_id) , 0 ) ,
1997
+ Request ( * LOCAL_CANISTER , * LOCAL_CANISTER ) . build_with (
1998
+ CallbackId :: new ( callback_id) ,
1999
+ 0 ,
2000
+ Cycles :: new ( 1 ) ,
2001
+ ) ,
1981
2002
& mut ( i64:: MAX / 2 ) ,
1982
2003
)
1983
2004
. is_ok ( )
@@ -2036,6 +2057,11 @@ fn duplicate_best_effort_response_is_dropped() {
2036
2057
..StreamConfig :: default ( )
2037
2058
} ) ;
2038
2059
expected_state. with_streams ( btreemap ! [ LOCAL_SUBNET => loopback_stream] ) ;
2060
+ // Cycles of the duplicate response are lost.
2061
+ expected_state
2062
+ . metadata
2063
+ . subnet_metrics
2064
+ . observe_consumed_cycles_with_use_case ( DroppedMessages , response. cycles ( ) . into ( ) ) ;
2039
2065
2040
2066
// Push the clone of the best effort response onto the loopback stream.
2041
2067
state. modify_streams ( |streams| streams. get_mut ( & LOCAL_SUBNET ) . unwrap ( ) . push ( response) ) ;
@@ -2071,6 +2097,7 @@ fn failing_to_induct_best_effort_response_does_not_raise_a_critical_error_impl(
2071
2097
} ] ,
2072
2098
|stream_handler, mut state, metrics| {
2073
2099
prepare_state ( & mut state) ;
2100
+ let response = message_in_stream ( state. get_stream ( & LOCAL_SUBNET ) , 21 ) . clone ( ) ;
2074
2101
2075
2102
// Expecting an unchanged state...
2076
2103
let mut expected_state = state. clone ( ) ;
@@ -2080,7 +2107,12 @@ fn failing_to_induct_best_effort_response_does_not_raise_a_critical_error_impl(
2080
2107
signals_end : 22 ,
2081
2108
..StreamConfig :: default ( )
2082
2109
} ) ;
2083
- expected_state. with_streams ( btreemap ! [ LOCAL_SUBNET => loopback_stream] ) ;
2110
+ expected_state. with_streams ( btreemap ! [ LOCAL_SUBNET => loopback_stream. clone( ) ] ) ;
2111
+ // Cycles attached to the dropped response are lost.
2112
+ expected_state
2113
+ . metadata
2114
+ . subnet_metrics
2115
+ . observe_consumed_cycles_with_use_case ( DroppedMessages , response. cycles ( ) . into ( ) ) ;
2084
2116
2085
2117
let inducted_state = stream_handler. induct_loopback_stream ( state, & mut ( i64:: MAX / 2 ) ) ;
2086
2118
assert_eq ! ( expected_state, inducted_state) ;
@@ -2215,8 +2247,11 @@ fn legacy_check_stream_handler_generated_reject_response_queue_full() {
2215
2247
let mut callback_id = 2 ;
2216
2248
while state
2217
2249
. push_input (
2218
- Request ( * LOCAL_CANISTER , * LOCAL_CANISTER )
2219
- . build_with ( CallbackId :: new ( callback_id) , 0 ) ,
2250
+ Request ( * LOCAL_CANISTER , * LOCAL_CANISTER ) . build_with (
2251
+ CallbackId :: new ( callback_id) ,
2252
+ 0 ,
2253
+ Cycles :: new ( 1 ) ,
2254
+ ) ,
2220
2255
& mut ( i64:: MAX / 2 ) ,
2221
2256
)
2222
2257
. is_ok ( )
@@ -2275,7 +2310,7 @@ fn induct_stream_slices_partial_success() {
2275
2310
btreemap ! [ REMOTE_SUBNET => StreamSliceConfig {
2276
2311
messages_begin: 43 ,
2277
2312
messages: vec![
2278
- // ...two incoming request @43 and @44...
2313
+ // ...two incoming requests @43 and @44...
2279
2314
Request ( * REMOTE_CANISTER , * LOCAL_CANISTER ) ,
2280
2315
Request ( * REMOTE_CANISTER , * LOCAL_CANISTER ) ,
2281
2316
// ...an incoming response @45...
@@ -2325,6 +2360,16 @@ fn induct_stream_slices_partial_success() {
2325
2360
} ) ;
2326
2361
expected_state. with_streams ( btreemap ! [ REMOTE_SUBNET => expected_stream] ) ;
2327
2362
2363
+ // Cycles attached to the dropped requests from `LOCAL_CANISTER` and
2364
+ // `UNKNOWN_CANISTER`; as well as those attached to the non-existent response to
2365
+ // `OTHER_LOCAL_CANISTER` are lost.
2366
+ let cycles_lost = messages_in_slice ( slices. get ( & REMOTE_SUBNET ) , 47 ..=49 )
2367
+ . fold ( Cycles :: zero ( ) , |acc, msg| acc + msg. cycles ( ) ) ;
2368
+ expected_state
2369
+ . metadata
2370
+ . subnet_metrics
2371
+ . observe_consumed_cycles_with_use_case ( DroppedMessages , cycles_lost. into ( ) ) ;
2372
+
2328
2373
let initial_available_guaranteed_response_memory =
2329
2374
stream_handler. available_guaranteed_response_memory ( & state) ;
2330
2375
let mut available_guaranteed_response_memory =
@@ -2451,6 +2496,16 @@ fn legacy_induct_stream_slices_partial_success() {
2451
2496
} ) ;
2452
2497
expected_state. with_streams ( btreemap ! [ REMOTE_SUBNET => expected_stream] ) ;
2453
2498
2499
+ // Cycles attached to the dropped requests from `LOCAL_CANISTER` and
2500
+ // `UNKNOWN_CANISTER`; as well as those attached to the non-existent response to
2501
+ // `OTHER_LOCAL_CANISTER` are lost.
2502
+ let cycles_lost = messages_in_slice ( slices. get ( & REMOTE_SUBNET ) , 47 ..=49 )
2503
+ . fold ( Cycles :: zero ( ) , |acc, msg| acc + msg. cycles ( ) ) ;
2504
+ expected_state
2505
+ . metadata
2506
+ . subnet_metrics
2507
+ . observe_consumed_cycles_with_use_case ( DroppedMessages , cycles_lost. into ( ) ) ;
2508
+
2454
2509
let initial_available_guaranteed_response_memory =
2455
2510
stream_handler. available_guaranteed_response_memory ( & state) ;
2456
2511
let mut available_guaranteed_response_memory =
@@ -2564,6 +2619,14 @@ fn induct_stream_slices_receiver_subnet_mismatch() {
2564
2619
} ) ;
2565
2620
expected_state. with_streams ( btreemap ! [ REMOTE_SUBNET => expected_stream] ) ;
2566
2621
2622
+ // Cycles attached to all messages in the slice are lost.
2623
+ let cycles_lost = messages_in_slice ( slices. get ( & REMOTE_SUBNET ) , 43 ..=46 )
2624
+ . fold ( Cycles :: zero ( ) , |acc, msg| acc + msg. cycles ( ) ) ;
2625
+ expected_state
2626
+ . metadata
2627
+ . subnet_metrics
2628
+ . observe_consumed_cycles_with_use_case ( DroppedMessages , cycles_lost. into ( ) ) ;
2629
+
2567
2630
let mut available_guaranteed_response_memory =
2568
2631
stream_handler. available_guaranteed_response_memory ( & state) ;
2569
2632
let inducted_state = stream_handler. induct_stream_slices (
@@ -3367,6 +3430,16 @@ fn process_stream_slices_with_reject_signals_partial_success() {
3367
3430
REMOTE_SUBNET => expected_outgoing_stream,
3368
3431
CANISTER_MIGRATION_SUBNET => rerouted_stream,
3369
3432
] ) ;
3433
+ // Cycles attached to the dropped request from `UNKNOWN_CANISTER` are lost.
3434
+ expected_state
3435
+ . metadata
3436
+ . subnet_metrics
3437
+ . observe_consumed_cycles_with_use_case (
3438
+ DroppedMessages ,
3439
+ message_in_slice ( slices. get ( & REMOTE_SUBNET ) , 154 )
3440
+ . cycles ( )
3441
+ . into ( ) ,
3442
+ ) ;
3370
3443
3371
3444
// Act.
3372
3445
let inducted_state = stream_handler. process_stream_slices ( state, slices) ;
@@ -3978,6 +4051,7 @@ fn with_test_setup_and_config(
3978
4051
// For all other messages a `other_callback_id` is used, i.e. something that
3979
4052
// simulates callback IDs generated in a different canister.
3980
4053
let mut other_callback_id = 0_u64 ;
4054
+ let mut cycles = Cycles :: new ( 1 ) ;
3981
4055
let mut messages_from_builders = |builders : Vec < MessageBuilder > | -> Vec < RequestOrResponse > {
3982
4056
builders
3983
4057
. into_iter ( )
@@ -3993,6 +4067,9 @@ fn with_test_setup_and_config(
3993
4067
( respondent, originator, NO_DEADLINE )
3994
4068
}
3995
4069
} ;
4070
+ // Attach a unique (bit mask-like) number of cycles to each message (assuming
4071
+ // that there are fewer than 127 messages).
4072
+ cycles = cycles + cycles;
3996
4073
3997
4074
// Register a callback and make an input queue reservation if `msg_config`
3998
4075
// corresponds to `LOCAL_CANISTER`; else use a dummy callback id.
@@ -4022,11 +4099,15 @@ fn with_test_setup_and_config(
4022
4099
// Empty output queues.
4023
4100
canister_state. output_into_iter ( ) . count ( ) ;
4024
4101
4025
- builder. build_with ( callback_id, payload_size_bytes)
4102
+ builder. build_with ( callback_id, payload_size_bytes, cycles )
4026
4103
} else {
4027
4104
// Message will not be inducted, use a replacement
4028
4105
other_callback_id += 1 ;
4029
- builder. build_with ( CallbackId :: new ( other_callback_id) , payload_size_bytes)
4106
+ builder. build_with (
4107
+ CallbackId :: new ( other_callback_id) ,
4108
+ payload_size_bytes,
4109
+ cycles,
4110
+ )
4030
4111
}
4031
4112
} )
4032
4113
. collect ( )
@@ -4334,27 +4415,35 @@ enum MessageBuilder {
4334
4415
}
4335
4416
4336
4417
impl MessageBuilder {
4337
- fn build_with ( self , callback_id : CallbackId , payload_size_bytes : usize ) -> RequestOrResponse {
4418
+ fn build_with (
4419
+ self ,
4420
+ callback_id : CallbackId ,
4421
+ payload_size_bytes : usize ,
4422
+ cycles : Cycles ,
4423
+ ) -> RequestOrResponse {
4338
4424
match self {
4339
4425
Self :: Request ( sender, receiver) => RequestBuilder :: new ( )
4340
4426
. sender ( sender)
4341
4427
. receiver ( receiver)
4342
4428
. sender_reply_callback ( callback_id)
4343
4429
. method_payload ( vec ! [ 0_u8 ; payload_size_bytes] )
4430
+ . payment ( cycles)
4344
4431
. build ( )
4345
4432
. into ( ) ,
4346
4433
Self :: Response ( respondent, originator) => ResponseBuilder :: new ( )
4347
4434
. respondent ( respondent)
4348
4435
. originator ( originator)
4349
4436
. originator_reply_callback ( callback_id)
4350
4437
. response_payload ( Payload :: Data ( vec ! [ 0_u8 ; payload_size_bytes] ) )
4438
+ . refund ( cycles)
4351
4439
. build ( )
4352
4440
. into ( ) ,
4353
4441
Self :: BestEffortResponse ( respondent, originator, deadline) => ResponseBuilder :: new ( )
4354
4442
. respondent ( respondent)
4355
4443
. originator ( originator)
4356
4444
. originator_reply_callback ( callback_id)
4357
4445
. response_payload ( Payload :: Data ( vec ! [ 0_u8 ; payload_size_bytes] ) )
4446
+ . refund ( cycles)
4358
4447
. deadline ( deadline)
4359
4448
. build ( )
4360
4449
. into ( ) ,
@@ -4364,6 +4453,7 @@ impl MessageBuilder {
4364
4453
. sender ( originator)
4365
4454
. receiver ( respondent)
4366
4455
. sender_reply_callback ( callback_id)
4456
+ . payment ( cycles)
4367
4457
. build ( ) ,
4368
4458
) ,
4369
4459
}
0 commit comments