1use indexmap::IndexMap;
19use nautilus_core::{UUID4, UnixNanos};
20use nautilus_model::identifiers::{ClientId, InstrumentId, StrategyId, TraderId};
21use nautilus_serialization::{
22 base_capnp,
23 capnp::{ToCapnp, order_side_to_capnp},
24 trading_capnp,
25};
26
27use crate::messages::execution::{
28 BatchCancelOrders, CancelAllOrders, CancelOrder, ModifyOrder, QueryAccount, QueryOrder,
29 SubmitOrder, SubmitOrderList, TradingCommand,
30};
31
32fn populate_string_map<'a>(
34 builder: base_capnp::string_map::Builder<'a>,
35 params: &IndexMap<String, String>,
36) {
37 let mut entries_builder = builder.init_entries(params.len() as u32);
38 for (i, (key, value)) in params.iter().enumerate() {
39 let mut entry_builder = entries_builder.reborrow().get(i as u32);
40 entry_builder.set_key(key.as_str());
41 entry_builder.set_value(value.as_str());
42 }
43}
44
45fn populate_trading_command_header<'a>(
47 mut builder: trading_capnp::trading_command_header::Builder<'a>,
48 trader_id: &TraderId,
49 client_id: Option<&ClientId>,
50 strategy_id: &StrategyId,
51 instrument_id: &InstrumentId,
52 command_id: &UUID4,
53 ts_init: UnixNanos,
54) {
55 let trader_id_builder = builder.reborrow().init_trader_id();
56 trader_id.to_capnp(trader_id_builder);
57
58 if let Some(client_id) = client_id {
59 let client_id_builder = builder.reborrow().init_client_id();
60 client_id.to_capnp(client_id_builder);
61 }
62
63 let strategy_id_builder = builder.reborrow().init_strategy_id();
64 strategy_id.to_capnp(strategy_id_builder);
65
66 let instrument_id_builder = builder.reborrow().init_instrument_id();
67 instrument_id.to_capnp(instrument_id_builder);
68
69 let command_id_builder = builder.reborrow().init_command_id();
70 command_id.to_capnp(command_id_builder);
71
72 let mut ts_init_builder = builder.reborrow().init_ts_init();
73 ts_init_builder.set_value(*ts_init);
74}
75
76impl<'a> ToCapnp<'a> for CancelOrder {
77 type Builder = trading_capnp::cancel_order::Builder<'a>;
78
79 fn to_capnp(&self, mut builder: Self::Builder) {
80 let header_builder = builder.reborrow().init_header();
81 populate_trading_command_header(
82 header_builder,
83 &self.trader_id,
84 self.client_id.as_ref(),
85 &self.strategy_id,
86 &self.instrument_id,
87 &self.command_id,
88 self.ts_init,
89 );
90
91 let client_order_id_builder = builder.reborrow().init_client_order_id();
92 self.client_order_id.to_capnp(client_order_id_builder);
93
94 if let Some(ref venue_order_id) = self.venue_order_id {
95 let venue_order_id_builder = builder.reborrow().init_venue_order_id();
96 venue_order_id.to_capnp(venue_order_id_builder);
97 }
98
99 if let Some(ref params) = self.params {
100 let params_builder = builder.reborrow().init_params();
101 populate_string_map(params_builder, params);
102 }
103 }
104}
105
106impl<'a> ToCapnp<'a> for CancelAllOrders {
107 type Builder = trading_capnp::cancel_all_orders::Builder<'a>;
108
109 fn to_capnp(&self, mut builder: Self::Builder) {
110 let header_builder = builder.reborrow().init_header();
111 populate_trading_command_header(
112 header_builder,
113 &self.trader_id,
114 self.client_id.as_ref(),
115 &self.strategy_id,
116 &self.instrument_id,
117 &self.command_id,
118 self.ts_init,
119 );
120
121 builder.set_order_side(order_side_to_capnp(self.order_side));
122
123 if let Some(ref params) = self.params {
124 let params_builder = builder.reborrow().init_params();
125 populate_string_map(params_builder, params);
126 }
127 }
128}
129
130impl<'a> ToCapnp<'a> for BatchCancelOrders {
131 type Builder = trading_capnp::batch_cancel_orders::Builder<'a>;
132
133 fn to_capnp(&self, mut builder: Self::Builder) {
134 let header_builder = builder.reborrow().init_header();
135 populate_trading_command_header(
136 header_builder,
137 &self.trader_id,
138 self.client_id.as_ref(),
139 &self.strategy_id,
140 &self.instrument_id,
141 &self.command_id,
142 self.ts_init,
143 );
144
145 let mut cancellations_builder = builder
146 .reborrow()
147 .init_cancellations(self.cancels.len() as u32);
148 for (i, cancel) in self.cancels.iter().enumerate() {
149 let cancel_builder = cancellations_builder.reborrow().get(i as u32);
150 cancel.to_capnp(cancel_builder);
151 }
152
153 if let Some(ref params) = self.params {
154 let params_builder = builder.reborrow().init_params();
155 populate_string_map(params_builder, params);
156 }
157 }
158}
159
160impl<'a> ToCapnp<'a> for ModifyOrder {
161 type Builder = trading_capnp::modify_order::Builder<'a>;
162
163 fn to_capnp(&self, mut builder: Self::Builder) {
164 let header_builder = builder.reborrow().init_header();
165 populate_trading_command_header(
166 header_builder,
167 &self.trader_id,
168 self.client_id.as_ref(),
169 &self.strategy_id,
170 &self.instrument_id,
171 &self.command_id,
172 self.ts_init,
173 );
174
175 let client_order_id_builder = builder.reborrow().init_client_order_id();
176 self.client_order_id.to_capnp(client_order_id_builder);
177
178 if let Some(ref venue_order_id) = self.venue_order_id {
179 let venue_order_id_builder = builder.reborrow().init_venue_order_id();
180 venue_order_id.to_capnp(venue_order_id_builder);
181 }
182
183 if let Some(ref quantity) = self.quantity {
184 let quantity_builder = builder.reborrow().init_quantity();
185 quantity.to_capnp(quantity_builder);
186 }
187
188 if let Some(ref price) = self.price {
189 let price_builder = builder.reborrow().init_price();
190 price.to_capnp(price_builder);
191 }
192
193 if let Some(ref trigger_price) = self.trigger_price {
194 let trigger_price_builder = builder.reborrow().init_trigger_price();
195 trigger_price.to_capnp(trigger_price_builder);
196 }
197
198 if let Some(ref params) = self.params {
199 let params_builder = builder.reborrow().init_params();
200 populate_string_map(params_builder, params);
201 }
202 }
203}
204
205impl<'a> ToCapnp<'a> for QueryOrder {
206 type Builder = trading_capnp::query_order::Builder<'a>;
207
208 fn to_capnp(&self, mut builder: Self::Builder) {
209 let header_builder = builder.reborrow().init_header();
210 populate_trading_command_header(
211 header_builder,
212 &self.trader_id,
213 self.client_id.as_ref(),
214 &self.strategy_id,
215 &self.instrument_id,
216 &self.command_id,
217 self.ts_init,
218 );
219
220 let client_order_id_builder = builder.reborrow().init_client_order_id();
221 self.client_order_id.to_capnp(client_order_id_builder);
222
223 if let Some(ref venue_order_id) = self.venue_order_id {
224 let venue_order_id_builder = builder.reborrow().init_venue_order_id();
225 venue_order_id.to_capnp(venue_order_id_builder);
226 }
227 }
228}
229
230impl<'a> ToCapnp<'a> for QueryAccount {
231 type Builder = trading_capnp::query_account::Builder<'a>;
232
233 fn to_capnp(&self, mut builder: Self::Builder) {
234 let trader_id_builder = builder.reborrow().init_trader_id();
235 self.trader_id.to_capnp(trader_id_builder);
236
237 let account_id_builder = builder.reborrow().init_account_id();
238 self.account_id.to_capnp(account_id_builder);
239
240 let command_id_builder = builder.reborrow().init_command_id();
241 self.command_id.to_capnp(command_id_builder);
242
243 let mut ts_init_builder = builder.reborrow().init_ts_init();
244 ts_init_builder.set_value(*self.ts_init);
245 }
246}
247
248impl<'a> ToCapnp<'a> for SubmitOrder {
249 type Builder = trading_capnp::submit_order::Builder<'a>;
250
251 fn to_capnp(&self, mut builder: Self::Builder) {
252 let header_builder = builder.reborrow().init_header();
253 populate_trading_command_header(
254 header_builder,
255 &self.trader_id,
256 self.client_id.as_ref(),
257 &self.strategy_id,
258 &self.instrument_id,
259 &self.command_id,
260 self.ts_init,
261 );
262
263 let order_init_builder = builder.reborrow().init_order_init();
264 self.order_init.to_capnp(order_init_builder);
265
266 if let Some(ref position_id) = self.position_id {
267 let position_id_builder = builder.reborrow().init_position_id();
268 position_id.to_capnp(position_id_builder);
269 }
270
271 if let Some(ref params) = self.params {
272 let params_builder = builder.reborrow().init_params();
273 populate_string_map(params_builder, params);
274 }
275 }
276}
277
278impl<'a> ToCapnp<'a> for SubmitOrderList {
279 type Builder = trading_capnp::submit_order_list::Builder<'a>;
280
281 fn to_capnp(&self, mut builder: Self::Builder) {
282 let header_builder = builder.reborrow().init_header();
283 populate_trading_command_header(
284 header_builder,
285 &self.trader_id,
286 self.client_id.as_ref(),
287 &self.strategy_id,
288 &self.instrument_id,
289 &self.command_id,
290 self.ts_init,
291 );
292
293 let mut order_inits_builder = builder
294 .reborrow()
295 .init_order_inits(self.order_inits.len() as u32);
296 for (i, order_init) in self.order_inits.iter().enumerate() {
297 let order_init_builder = order_inits_builder.reborrow().get(i as u32);
298 order_init.to_capnp(order_init_builder);
299 }
300
301 if let Some(ref position_id) = self.position_id {
302 let position_id_builder = builder.reborrow().init_position_id();
303 position_id.to_capnp(position_id_builder);
304 }
305
306 if let Some(ref params) = self.params {
307 let params_builder = builder.reborrow().init_params();
308 populate_string_map(params_builder, params);
309 }
310 }
311}
312
313impl<'a> ToCapnp<'a> for TradingCommand {
314 type Builder = trading_capnp::trading_command::Builder<'a>;
315
316 fn to_capnp(&self, builder: Self::Builder) {
317 match self {
318 Self::SubmitOrder(command) => {
319 let submit_builder = builder.init_submit_order();
320 command.to_capnp(submit_builder);
321 }
322 Self::SubmitOrderList(command) => {
323 let submit_list_builder = builder.init_submit_order_list();
324 command.to_capnp(submit_list_builder);
325 }
326 Self::ModifyOrder(command) => {
327 let modify_builder = builder.init_modify_order();
328 command.to_capnp(modify_builder);
329 }
330 Self::CancelOrder(command) => {
331 let cancel_builder = builder.init_cancel_order();
332 command.to_capnp(cancel_builder);
333 }
334 Self::CancelAllOrders(command) => {
335 let cancel_all_builder = builder.init_cancel_all_orders();
336 command.to_capnp(cancel_all_builder);
337 }
338 Self::BatchCancelOrders(command) => {
339 let batch_cancel_builder = builder.init_batch_cancel_orders();
340 command.to_capnp(batch_cancel_builder);
341 }
342 Self::QueryOrder(command) => {
343 let query_builder = builder.init_query_order();
344 command.to_capnp(query_builder);
345 }
346 Self::QueryAccount(command) => {
347 let query_builder = builder.init_query_account();
348 command.to_capnp(query_builder);
349 }
350 }
351 }
352}
353
354#[cfg(test)]
355mod tests {
356 use capnp::message::Builder;
357 use nautilus_core::UnixNanos;
358 use nautilus_model::{
359 enums::{OrderSide, OrderType},
360 identifiers::{
361 AccountId, ClientId, ClientOrderId, InstrumentId, OrderListId, StrategyId, TraderId,
362 },
363 orders::{Order, OrderList, OrderTestBuilder},
364 stubs::TestDefault,
365 types::{Price, Quantity},
366 };
367 use rstest::*;
368
369 use super::*;
370 use crate::messages::execution::{
371 cancel::{BatchCancelOrdersBuilder, CancelAllOrdersBuilder, CancelOrderBuilder},
372 modify::ModifyOrderBuilder,
373 query::{QueryAccountBuilder, QueryOrderBuilder},
374 };
375
376 #[fixture]
377 fn trader_id() -> TraderId {
378 TraderId::test_default()
379 }
380
381 #[fixture]
382 fn strategy_id() -> StrategyId {
383 StrategyId::test_default()
384 }
385
386 #[fixture]
387 fn instrument_id() -> InstrumentId {
388 InstrumentId::test_default()
389 }
390
391 #[fixture]
392 fn client_order_id() -> ClientOrderId {
393 ClientOrderId::test_default()
394 }
395
396 #[fixture]
397 fn command_id() -> UUID4 {
398 UUID4::new()
399 }
400
401 #[fixture]
402 fn ts_init() -> UnixNanos {
403 UnixNanos::default()
404 }
405
406 #[fixture]
407 fn client_id() -> ClientId {
408 ClientId::new("TEST")
409 }
410
411 #[rstest]
412 fn test_cancel_order_serialization(
413 trader_id: TraderId,
414 client_id: ClientId,
415 strategy_id: StrategyId,
416 instrument_id: InstrumentId,
417 client_order_id: ClientOrderId,
418 command_id: UUID4,
419 ts_init: UnixNanos,
420 ) {
421 let command = CancelOrderBuilder::default()
422 .trader_id(trader_id)
423 .client_id(Some(client_id))
424 .strategy_id(strategy_id)
425 .instrument_id(instrument_id)
426 .client_order_id(client_order_id)
427 .venue_order_id(None)
428 .command_id(command_id)
429 .ts_init(ts_init)
430 .params(None)
431 .build()
432 .unwrap();
433
434 let mut message = Builder::new_default();
435 {
436 let builder = message.init_root::<trading_capnp::cancel_order::Builder>();
437 command.to_capnp(builder);
438 }
439
440 let reader = message
441 .get_root_as_reader::<trading_capnp::cancel_order::Reader>()
442 .expect("Valid capnp message");
443
444 assert!(reader.has_header());
446 let header = reader.get_header().unwrap();
447 assert!(header.has_trader_id());
448 assert!(header.has_client_id());
449 assert!(header.has_strategy_id());
450 assert!(header.has_instrument_id());
451 assert!(header.has_command_id());
452 assert!(header.has_ts_init());
453 }
454
455 #[rstest]
456 fn test_cancel_all_orders_serialization(
457 trader_id: TraderId,
458 strategy_id: StrategyId,
459 instrument_id: InstrumentId,
460 command_id: UUID4,
461 ts_init: UnixNanos,
462 ) {
463 let command = CancelAllOrdersBuilder::default()
464 .trader_id(trader_id)
465 .client_id(None)
466 .strategy_id(strategy_id)
467 .instrument_id(instrument_id)
468 .order_side(OrderSide::Buy)
469 .command_id(command_id)
470 .ts_init(ts_init)
471 .params(None)
472 .build()
473 .unwrap();
474
475 let mut message = Builder::new_default();
476 {
477 let builder = message.init_root::<trading_capnp::cancel_all_orders::Builder>();
478 command.to_capnp(builder);
479 }
480
481 let reader = message
482 .get_root_as_reader::<trading_capnp::cancel_all_orders::Reader>()
483 .expect("Valid capnp message");
484
485 assert!(reader.has_header());
486 }
487
488 #[rstest]
489 fn test_batch_cancel_orders_serialization(
490 trader_id: TraderId,
491 strategy_id: StrategyId,
492 instrument_id: InstrumentId,
493 command_id: UUID4,
494 ts_init: UnixNanos,
495 ) {
496 let cancel1 = CancelOrderBuilder::default()
497 .trader_id(trader_id)
498 .client_id(None)
499 .strategy_id(strategy_id)
500 .instrument_id(instrument_id)
501 .client_order_id(ClientOrderId::new("O-001"))
502 .venue_order_id(None)
503 .command_id(UUID4::new())
504 .ts_init(ts_init)
505 .params(None)
506 .build()
507 .unwrap();
508
509 let cancel2 = CancelOrderBuilder::default()
510 .trader_id(trader_id)
511 .client_id(None)
512 .strategy_id(strategy_id)
513 .instrument_id(instrument_id)
514 .client_order_id(ClientOrderId::new("O-002"))
515 .venue_order_id(None)
516 .command_id(UUID4::new())
517 .ts_init(ts_init)
518 .params(None)
519 .build()
520 .unwrap();
521
522 let command = BatchCancelOrdersBuilder::default()
523 .trader_id(trader_id)
524 .client_id(None)
525 .strategy_id(strategy_id)
526 .instrument_id(instrument_id)
527 .cancels(vec![cancel1, cancel2])
528 .command_id(command_id)
529 .ts_init(ts_init)
530 .params(None)
531 .build()
532 .unwrap();
533
534 let mut message = Builder::new_default();
535 {
536 let builder = message.init_root::<trading_capnp::batch_cancel_orders::Builder>();
537 command.to_capnp(builder);
538 }
539
540 let reader = message
541 .get_root_as_reader::<trading_capnp::batch_cancel_orders::Reader>()
542 .expect("Valid capnp message");
543
544 assert!(reader.has_header());
545 assert!(reader.has_cancellations());
546 assert_eq!(reader.get_cancellations().unwrap().len(), 2);
547 }
548
549 #[rstest]
550 fn test_modify_order_serialization(
551 trader_id: TraderId,
552 strategy_id: StrategyId,
553 instrument_id: InstrumentId,
554 client_order_id: ClientOrderId,
555 command_id: UUID4,
556 ts_init: UnixNanos,
557 ) {
558 let command = ModifyOrderBuilder::default()
559 .trader_id(trader_id)
560 .client_id(None)
561 .strategy_id(strategy_id)
562 .instrument_id(instrument_id)
563 .client_order_id(client_order_id)
564 .venue_order_id(None)
565 .quantity(Some(Quantity::new(100.0, 0)))
566 .price(Some(Price::new(50_000.0, 2)))
567 .trigger_price(Some(Price::new(49_000.0, 2)))
568 .command_id(command_id)
569 .ts_init(ts_init)
570 .params(None)
571 .build()
572 .unwrap();
573
574 let mut message = Builder::new_default();
575 {
576 let builder = message.init_root::<trading_capnp::modify_order::Builder>();
577 command.to_capnp(builder);
578 }
579
580 let reader = message
581 .get_root_as_reader::<trading_capnp::modify_order::Reader>()
582 .expect("Valid capnp message");
583
584 assert!(reader.has_header());
585 assert!(reader.has_quantity());
586 assert!(reader.has_price());
587 assert!(reader.has_trigger_price());
588 }
589
590 #[rstest]
591 fn test_query_order_serialization(
592 trader_id: TraderId,
593 strategy_id: StrategyId,
594 instrument_id: InstrumentId,
595 client_order_id: ClientOrderId,
596 command_id: UUID4,
597 ts_init: UnixNanos,
598 ) {
599 let command = QueryOrderBuilder::default()
600 .trader_id(trader_id)
601 .client_id(None)
602 .strategy_id(strategy_id)
603 .instrument_id(instrument_id)
604 .client_order_id(client_order_id)
605 .venue_order_id(None)
606 .command_id(command_id)
607 .ts_init(ts_init)
608 .build()
609 .unwrap();
610
611 let mut message = Builder::new_default();
612 {
613 let builder = message.init_root::<trading_capnp::query_order::Builder>();
614 command.to_capnp(builder);
615 }
616
617 let reader = message
618 .get_root_as_reader::<trading_capnp::query_order::Reader>()
619 .expect("Valid capnp message");
620
621 assert!(reader.has_header());
622 }
623
624 #[rstest]
625 fn test_query_account_serialization(
626 trader_id: TraderId,
627 command_id: UUID4,
628 ts_init: UnixNanos,
629 ) {
630 let command = QueryAccountBuilder::default()
631 .trader_id(trader_id)
632 .client_id(None)
633 .account_id(AccountId::new("ACC-001"))
634 .command_id(command_id)
635 .ts_init(ts_init)
636 .build()
637 .unwrap();
638
639 let mut message = Builder::new_default();
640 {
641 let builder = message.init_root::<trading_capnp::query_account::Builder>();
642 command.to_capnp(builder);
643 }
644
645 let reader = message
646 .get_root_as_reader::<trading_capnp::query_account::Reader>()
647 .expect("Valid capnp message");
648
649 assert!(reader.has_trader_id());
650 assert!(reader.has_account_id());
651 }
652
653 #[rstest]
654 fn test_submit_order_serialization(command_id: UUID4, ts_init: UnixNanos, client_id: ClientId) {
655 let order = OrderTestBuilder::new(OrderType::Limit)
656 .instrument_id(InstrumentId::from("BTCUSDT.BINANCE"))
657 .side(OrderSide::Buy)
658 .quantity(Quantity::new(1.0, 8))
659 .price(Price::new(50_000.0, 2))
660 .build();
661
662 let command = SubmitOrder::new(
663 order.trader_id(),
664 Some(client_id),
665 order.strategy_id(),
666 order.instrument_id(),
667 order.client_order_id(),
668 order.init_event().clone(),
669 None,
670 None,
671 None,
672 command_id,
673 ts_init,
674 );
675
676 let mut message = Builder::new_default();
677 {
678 let builder = message.init_root::<trading_capnp::submit_order::Builder>();
679 command.to_capnp(builder);
680 }
681
682 let reader = message
683 .get_root_as_reader::<trading_capnp::submit_order::Reader>()
684 .expect("Valid capnp message");
685
686 assert!(reader.has_header());
687 assert!(reader.has_order_init());
688 }
689
690 #[rstest]
691 fn test_submit_order_list_serialization(
692 command_id: UUID4,
693 ts_init: UnixNanos,
694 client_id: ClientId,
695 ) {
696 let order1 = OrderTestBuilder::new(OrderType::Limit)
697 .instrument_id(InstrumentId::from("BTCUSDT.BINANCE"))
698 .client_order_id(ClientOrderId::from("O-001"))
699 .side(OrderSide::Buy)
700 .quantity(Quantity::new(1.0, 8))
701 .price(Price::new(50_000.0, 2))
702 .build();
703
704 let order2 = OrderTestBuilder::new(OrderType::Limit)
705 .instrument_id(InstrumentId::from("BTCUSDT.BINANCE"))
706 .client_order_id(ClientOrderId::from("O-002"))
707 .side(OrderSide::Sell)
708 .quantity(Quantity::new(1.0, 8))
709 .price(Price::new(51_000.0, 2))
710 .build();
711
712 let orders = [order1.clone(), order2];
713 let order_inits: Vec<_> = orders.iter().map(|o| o.init_event().clone()).collect();
714 let order_list = OrderList::new(
715 OrderListId::new("OL-001"),
716 InstrumentId::from("BTCUSDT.BINANCE"),
717 order1.strategy_id(),
718 vec![order1.client_order_id(), orders[1].client_order_id()],
719 ts_init,
720 );
721
722 let command = SubmitOrderList::new(
723 order1.trader_id(),
724 Some(client_id),
725 order1.strategy_id(),
726 order_list,
727 order_inits,
728 None,
729 None,
730 None,
731 command_id,
732 ts_init,
733 );
734
735 let mut message = Builder::new_default();
736 {
737 let builder = message.init_root::<trading_capnp::submit_order_list::Builder>();
738 command.to_capnp(builder);
739 }
740
741 let reader = message
742 .get_root_as_reader::<trading_capnp::submit_order_list::Reader>()
743 .expect("Valid capnp message");
744
745 assert!(reader.has_header());
746 assert!(reader.has_order_inits());
747 assert_eq!(reader.get_order_inits().unwrap().len(), 2);
748 }
749
750 #[rstest]
751 fn test_trading_command_enum_serialization(
752 trader_id: TraderId,
753 strategy_id: StrategyId,
754 instrument_id: InstrumentId,
755 client_order_id: ClientOrderId,
756 command_id: UUID4,
757 ts_init: UnixNanos,
758 ) {
759 let cancel = CancelOrderBuilder::default()
760 .trader_id(trader_id)
761 .client_id(None)
762 .strategy_id(strategy_id)
763 .instrument_id(instrument_id)
764 .client_order_id(client_order_id)
765 .venue_order_id(None)
766 .command_id(command_id)
767 .ts_init(ts_init)
768 .params(None)
769 .build()
770 .unwrap();
771
772 let command = TradingCommand::CancelOrder(cancel);
773
774 let mut message = Builder::new_default();
775 {
776 let builder = message.init_root::<trading_capnp::trading_command::Builder>();
777 command.to_capnp(builder);
778 }
779
780 let reader = message
781 .get_root_as_reader::<trading_capnp::trading_command::Reader>()
782 .expect("Valid capnp message");
783
784 assert!(reader.has_cancel_order());
786 }
787}