1#![deny(unused_crate_dependencies)]
20#![warn(missing_docs)]
21
22use codec::{Decode, Encode};
23use polkadot_primitives::{BlockNumber, Hash};
24use std::{collections::HashMap, fmt};
25
26#[doc(hidden)]
27pub use polkadot_node_jaeger as jaeger;
28pub use sc_network::IfDisconnected;
29pub use sc_network_types::PeerId;
30#[doc(hidden)]
31pub use std::sync::Arc;
32
33mod reputation;
34pub use self::reputation::{ReputationChange, UnifiedReputationChange};
35
36pub mod peer_set;
38
39pub mod request_response;
41
42pub mod authority_discovery;
44pub mod grid_topology;
46
47pub const MIN_GOSSIP_PEERS: usize = 25;
49
50#[derive(Debug, Clone, Copy, PartialEq)]
52pub struct WrongVariant;
53
54impl fmt::Display for WrongVariant {
55 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(formatter, "Wrong message variant")
57 }
58}
59
60impl std::error::Error for WrongVariant {}
61
62#[derive(Debug, Clone, Copy, PartialEq)]
64pub enum ObservedRole {
65 Light,
67 Full,
69 Authority,
71}
72
73impl From<sc_network::ObservedRole> for ObservedRole {
74 fn from(role: sc_network::ObservedRole) -> ObservedRole {
75 match role {
76 sc_network::ObservedRole::Light => ObservedRole::Light,
77 sc_network::ObservedRole::Authority => ObservedRole::Authority,
78 sc_network::ObservedRole::Full => ObservedRole::Full,
79 }
80 }
81}
82
83impl Into<sc_network::ObservedRole> for ObservedRole {
84 fn into(self) -> sc_network::ObservedRole {
85 match self {
86 ObservedRole::Light => sc_network::ObservedRole::Light,
87 ObservedRole::Full => sc_network::ObservedRole::Full,
88 ObservedRole::Authority => sc_network::ObservedRole::Authority,
89 }
90 }
91}
92
93#[derive(Debug, Clone, Default)]
98pub struct OurView {
99 view: View,
100 span_per_head: HashMap<Hash, Arc<jaeger::Span>>,
101}
102
103impl OurView {
104 pub fn new(
106 heads: impl IntoIterator<Item = (Hash, Arc<jaeger::Span>)>,
107 finalized_number: BlockNumber,
108 ) -> Self {
109 let state_per_head = heads.into_iter().collect::<HashMap<_, _>>();
110 let view = View::new(state_per_head.keys().cloned(), finalized_number);
111 Self { view, span_per_head: state_per_head }
112 }
113
114 pub fn span_per_head(&self) -> &HashMap<Hash, Arc<jaeger::Span>> {
118 &self.span_per_head
119 }
120}
121
122impl PartialEq for OurView {
123 fn eq(&self, other: &Self) -> bool {
124 self.view == other.view
125 }
126}
127
128impl std::ops::Deref for OurView {
129 type Target = View;
130
131 fn deref(&self) -> &View {
132 &self.view
133 }
134}
135
136#[macro_export]
149macro_rules! our_view {
150 ( $( $hash:expr ),* $(,)? ) => {
151 $crate::OurView::new(
152 vec![ $( $hash.clone() ),* ].into_iter().map(|h| (h, $crate::Arc::new($crate::jaeger::Span::Disabled))),
153 0,
154 )
155 };
156}
157
158#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)]
163pub struct View {
164 heads: Vec<Hash>,
167 pub finalized_number: BlockNumber,
169}
170
171#[macro_export]
183macro_rules! view {
184 ( $( $hash:expr ),* $(,)? ) => {
185 $crate::View::new(vec![ $( $hash.clone() ),* ], 0)
186 };
187}
188
189impl View {
190 pub fn new(heads: impl IntoIterator<Item = Hash>, finalized_number: BlockNumber) -> Self {
192 let mut heads = heads.into_iter().collect::<Vec<Hash>>();
193 heads.sort();
194 Self { heads, finalized_number }
195 }
196
197 pub fn with_finalized(finalized_number: BlockNumber) -> Self {
199 Self { heads: Vec::new(), finalized_number }
200 }
201
202 pub fn len(&self) -> usize {
204 self.heads.len()
205 }
206
207 pub fn is_empty(&self) -> bool {
209 self.heads.is_empty()
210 }
211
212 pub fn iter(&self) -> impl Iterator<Item = &Hash> {
214 self.heads.iter()
215 }
216
217 pub fn into_iter(self) -> impl Iterator<Item = Hash> {
219 self.heads.into_iter()
220 }
221
222 pub fn replace_difference(&mut self, new: View) -> impl Iterator<Item = &Hash> {
226 let old = std::mem::replace(self, new);
227
228 self.heads.iter().filter(move |h| !old.contains(h))
229 }
230
231 pub fn difference<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
233 self.heads.iter().filter(move |h| !other.contains(h))
234 }
235
236 pub fn intersection<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
238 self.heads.iter().filter(move |h| other.contains(h))
239 }
240
241 pub fn contains(&self, hash: &Hash) -> bool {
243 self.heads.contains(hash)
244 }
245
246 pub fn check_heads_eq(&self, other: &Self) -> bool {
251 self.heads == other.heads
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
257pub enum Versioned<V1, V2, V3 = V2> {
258 V1(V1),
260 V2(V2),
262 V3(V3),
264}
265
266impl<V1: Clone, V2: Clone, V3: Clone> Versioned<&'_ V1, &'_ V2, &'_ V3> {
267 pub fn clone_inner(&self) -> Versioned<V1, V2, V3> {
269 match *self {
270 Versioned::V1(inner) => Versioned::V1(inner.clone()),
271 Versioned::V2(inner) => Versioned::V2(inner.clone()),
272 Versioned::V3(inner) => Versioned::V3(inner.clone()),
273 }
274 }
275}
276
277pub type VersionedValidationProtocol =
279 Versioned<v1::ValidationProtocol, v2::ValidationProtocol, v3::ValidationProtocol>;
280
281impl From<v1::ValidationProtocol> for VersionedValidationProtocol {
282 fn from(v1: v1::ValidationProtocol) -> Self {
283 VersionedValidationProtocol::V1(v1)
284 }
285}
286
287impl From<v2::ValidationProtocol> for VersionedValidationProtocol {
288 fn from(v2: v2::ValidationProtocol) -> Self {
289 VersionedValidationProtocol::V2(v2)
290 }
291}
292
293impl From<v3::ValidationProtocol> for VersionedValidationProtocol {
294 fn from(v3: v3::ValidationProtocol) -> Self {
295 VersionedValidationProtocol::V3(v3)
296 }
297}
298
299pub type VersionedCollationProtocol = Versioned<v1::CollationProtocol, v2::CollationProtocol>;
301
302impl From<v1::CollationProtocol> for VersionedCollationProtocol {
303 fn from(v1: v1::CollationProtocol) -> Self {
304 VersionedCollationProtocol::V1(v1)
305 }
306}
307
308impl From<v2::CollationProtocol> for VersionedCollationProtocol {
309 fn from(v2: v2::CollationProtocol) -> Self {
310 VersionedCollationProtocol::V2(v2)
311 }
312}
313
314macro_rules! impl_versioned_full_protocol_from {
315 ($from:ty, $out:ty, $variant:ident) => {
316 impl From<$from> for $out {
317 fn from(versioned_from: $from) -> $out {
318 match versioned_from {
319 Versioned::V1(x) => Versioned::V1(x.into()),
320 Versioned::V2(x) => Versioned::V2(x.into()),
321 Versioned::V3(x) => Versioned::V3(x.into()),
322 }
323 }
324 }
325 };
326}
327macro_rules! impl_versioned_try_from {
330 (
331 $from:ty,
332 $out:ty,
333 $v1_pat:pat => $v1_out:expr,
334 $v2_pat:pat => $v2_out:expr,
335 $v3_pat:pat => $v3_out:expr
336 ) => {
337 impl TryFrom<$from> for $out {
338 type Error = crate::WrongVariant;
339
340 fn try_from(x: $from) -> Result<$out, Self::Error> {
341 #[allow(unreachable_patterns)] match x {
343 Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)),
344 Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out)),
345 Versioned::V3($v3_pat) => Ok(Versioned::V3($v3_out)),
346 _ => Err(crate::WrongVariant),
347 }
348 }
349 }
350
351 impl<'a> TryFrom<&'a $from> for $out {
352 type Error = crate::WrongVariant;
353
354 fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
355 #[allow(unreachable_patterns)] match x {
357 Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())),
358 Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out.clone())),
359 Versioned::V3($v3_pat) => Ok(Versioned::V3($v3_out.clone())),
360 _ => Err(crate::WrongVariant),
361 }
362 }
363 }
364 };
365}
366
367pub type BitfieldDistributionMessage = Versioned<
369 v1::BitfieldDistributionMessage,
370 v2::BitfieldDistributionMessage,
371 v3::BitfieldDistributionMessage,
372>;
373impl_versioned_full_protocol_from!(
374 BitfieldDistributionMessage,
375 VersionedValidationProtocol,
376 BitfieldDistribution
377);
378impl_versioned_try_from!(
379 VersionedValidationProtocol,
380 BitfieldDistributionMessage,
381 v1::ValidationProtocol::BitfieldDistribution(x) => x,
382 v2::ValidationProtocol::BitfieldDistribution(x) => x,
383 v3::ValidationProtocol::BitfieldDistribution(x) => x
384);
385
386pub type StatementDistributionMessage = Versioned<
388 v1::StatementDistributionMessage,
389 v2::StatementDistributionMessage,
390 v3::StatementDistributionMessage,
391>;
392impl_versioned_full_protocol_from!(
393 StatementDistributionMessage,
394 VersionedValidationProtocol,
395 StatementDistribution
396);
397impl_versioned_try_from!(
398 VersionedValidationProtocol,
399 StatementDistributionMessage,
400 v1::ValidationProtocol::StatementDistribution(x) => x,
401 v2::ValidationProtocol::StatementDistribution(x) => x,
402 v3::ValidationProtocol::StatementDistribution(x) => x
403);
404
405pub type ApprovalDistributionMessage = Versioned<
407 v1::ApprovalDistributionMessage,
408 v2::ApprovalDistributionMessage,
409 v3::ApprovalDistributionMessage,
410>;
411impl_versioned_full_protocol_from!(
412 ApprovalDistributionMessage,
413 VersionedValidationProtocol,
414 ApprovalDistribution
415);
416impl_versioned_try_from!(
417 VersionedValidationProtocol,
418 ApprovalDistributionMessage,
419 v1::ValidationProtocol::ApprovalDistribution(x) => x,
420 v2::ValidationProtocol::ApprovalDistribution(x) => x,
421 v3::ValidationProtocol::ApprovalDistribution(x) => x
422
423);
424
425pub type GossipSupportNetworkMessage = Versioned<
427 v1::GossipSupportNetworkMessage,
428 v2::GossipSupportNetworkMessage,
429 v3::GossipSupportNetworkMessage,
430>;
431
432impl TryFrom<VersionedValidationProtocol> for GossipSupportNetworkMessage {
434 type Error = WrongVariant;
435 fn try_from(_: VersionedValidationProtocol) -> Result<Self, Self::Error> {
436 Err(WrongVariant)
437 }
438}
439
440impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessage {
441 type Error = WrongVariant;
442 fn try_from(_: &'a VersionedValidationProtocol) -> Result<Self, Self::Error> {
443 Err(WrongVariant)
444 }
445}
446
447pub type CollatorProtocolMessage =
449 Versioned<v1::CollatorProtocolMessage, v2::CollatorProtocolMessage>;
450impl_versioned_full_protocol_from!(
451 CollatorProtocolMessage,
452 VersionedCollationProtocol,
453 CollatorProtocol
454);
455impl_versioned_try_from!(
456 VersionedCollationProtocol,
457 CollatorProtocolMessage,
458 v1::CollationProtocol::CollatorProtocol(x) => x,
459 v2::CollationProtocol::CollatorProtocol(x) => x,
460 v2::CollationProtocol::CollatorProtocol(x) => x
461);
462
463pub mod v1 {
465 use codec::{Decode, Encode};
466
467 use polkadot_primitives::{
468 CandidateHash, CandidateIndex, CollatorId, CollatorSignature, CompactStatement, Hash,
469 Id as ParaId, UncheckedSignedAvailabilityBitfield, ValidatorIndex, ValidatorSignature,
470 };
471
472 use polkadot_node_primitives::{
473 approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote},
474 UncheckedSignedFullStatement,
475 };
476
477 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
479 pub enum BitfieldDistributionMessage {
480 #[codec(index = 0)]
482 Bitfield(Hash, UncheckedSignedAvailabilityBitfield),
483 }
484
485 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
487 pub enum StatementDistributionMessage {
488 #[codec(index = 0)]
490 Statement(Hash, UncheckedSignedFullStatement),
491 #[codec(index = 1)]
496 LargeStatement(StatementMetadata),
497 }
498
499 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
501 pub struct StatementMetadata {
502 pub relay_parent: Hash,
504 pub candidate_hash: CandidateHash,
506 pub signed_by: ValidatorIndex,
508 pub signature: ValidatorSignature,
510 }
511
512 impl StatementDistributionMessage {
513 pub fn get_fingerprint(&self) -> (CompactStatement, ValidatorIndex) {
515 match self {
516 Self::Statement(_, statement) => (
517 statement.unchecked_payload().to_compact(),
518 statement.unchecked_validator_index(),
519 ),
520 Self::LargeStatement(meta) =>
521 (CompactStatement::Seconded(meta.candidate_hash), meta.signed_by),
522 }
523 }
524
525 pub fn get_signature(&self) -> ValidatorSignature {
527 match self {
528 Self::Statement(_, statement) => statement.unchecked_signature().clone(),
529 Self::LargeStatement(metadata) => metadata.signature.clone(),
530 }
531 }
532
533 pub fn get_relay_parent(&self) -> Hash {
535 match self {
536 Self::Statement(r, _) => *r,
537 Self::LargeStatement(meta) => meta.relay_parent,
538 }
539 }
540
541 pub fn is_large_statement(&self) -> bool {
543 if let Self::LargeStatement(_) = self {
544 true
545 } else {
546 false
547 }
548 }
549 }
550
551 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
553 pub enum ApprovalDistributionMessage {
554 #[codec(index = 0)]
558 Assignments(Vec<(IndirectAssignmentCert, CandidateIndex)>),
559 #[codec(index = 1)]
561 Approvals(Vec<IndirectSignedApprovalVote>),
562 }
563
564 #[derive(Debug, Clone, PartialEq, Eq)]
566 pub enum GossipSupportNetworkMessage {}
567
568 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
570 pub enum CollatorProtocolMessage {
571 #[codec(index = 0)]
574 Declare(CollatorId, ParaId, CollatorSignature),
575 #[codec(index = 1)]
578 AdvertiseCollation(Hash),
579 #[codec(index = 4)]
581 CollationSeconded(Hash, UncheckedSignedFullStatement),
582 }
583
584 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
586 pub enum ValidationProtocol {
587 #[codec(index = 1)]
589 #[from]
590 BitfieldDistribution(BitfieldDistributionMessage),
591 #[codec(index = 3)]
593 #[from]
594 StatementDistribution(StatementDistributionMessage),
595 #[codec(index = 4)]
597 #[from]
598 ApprovalDistribution(ApprovalDistributionMessage),
599 }
600
601 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
603 pub enum CollationProtocol {
604 #[codec(index = 0)]
606 #[from]
607 CollatorProtocol(CollatorProtocolMessage),
608 }
609
610 pub fn declare_signature_payload(peer_id: &sc_network_types::PeerId) -> Vec<u8> {
615 let mut payload = peer_id.to_bytes();
616 payload.extend_from_slice(b"COLL");
617 payload
618 }
619}
620
621pub mod v2 {
623 use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec};
624 use codec::{Decode, Encode};
625
626 use polkadot_primitives::{
627 CandidateHash, CandidateIndex, CollatorId, CollatorSignature, GroupIndex, Hash,
628 Id as ParaId, UncheckedSignedAvailabilityBitfield, UncheckedSignedStatement,
629 };
630
631 use polkadot_node_primitives::{
632 approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote},
633 UncheckedSignedFullStatement,
634 };
635
636 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
638 pub enum BitfieldDistributionMessage {
639 #[codec(index = 0)]
641 Bitfield(Hash, UncheckedSignedAvailabilityBitfield),
642 }
643
644 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
647 pub struct StatementFilter {
648 pub seconded_in_group: BitVec<u8, Lsb0>,
650 pub validated_in_group: BitVec<u8, Lsb0>,
652 }
653
654 impl StatementFilter {
655 pub fn blank(group_size: usize) -> Self {
657 StatementFilter {
658 seconded_in_group: BitVec::repeat(false, group_size),
659 validated_in_group: BitVec::repeat(false, group_size),
660 }
661 }
662
663 pub fn full(group_size: usize) -> Self {
665 StatementFilter {
666 seconded_in_group: BitVec::repeat(true, group_size),
667 validated_in_group: BitVec::repeat(true, group_size),
668 }
669 }
670
671 pub fn has_len(&self, len: usize) -> bool {
674 self.seconded_in_group.len() == len && self.validated_in_group.len() == len
675 }
676
677 pub fn backing_validators(&self) -> usize {
679 self.seconded_in_group
680 .iter()
681 .by_vals()
682 .zip(self.validated_in_group.iter().by_vals())
683 .filter(|&(s, v)| s || v) .count()
685 }
686
687 pub fn has_seconded(&self) -> bool {
689 self.seconded_in_group.iter().by_vals().any(|x| x)
690 }
691
692 pub fn mask_seconded(&mut self, mask: &BitSlice<u8, Lsb0>) {
695 for (mut x, mask) in self
696 .seconded_in_group
697 .iter_mut()
698 .zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
699 {
700 *x = *x && !mask;
706 }
707 }
708
709 pub fn mask_valid(&mut self, mask: &BitSlice<u8, Lsb0>) {
712 for (mut x, mask) in self
713 .validated_in_group
714 .iter_mut()
715 .zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
716 {
717 *x = *x && !mask;
723 }
724 }
725 }
726
727 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
730 pub struct BackedCandidateManifest {
731 pub relay_parent: Hash,
733 pub candidate_hash: CandidateHash,
735 pub group_index: GroupIndex,
737 pub para_id: ParaId,
741 pub parent_head_data_hash: Hash,
743 pub statement_knowledge: StatementFilter,
751 }
752
753 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
755 pub struct BackedCandidateAcknowledgement {
756 pub candidate_hash: CandidateHash,
758 pub statement_knowledge: StatementFilter,
766 }
767
768 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
770 pub enum StatementDistributionMessage {
771 #[codec(index = 0)]
773 Statement(Hash, UncheckedSignedStatement),
774
775 #[codec(index = 1)]
779 BackedCandidateManifest(BackedCandidateManifest),
780
781 #[codec(index = 2)]
784 BackedCandidateKnown(BackedCandidateAcknowledgement),
785
786 #[codec(index = 255)]
794 V1Compatibility(crate::v1::StatementDistributionMessage),
795 }
796
797 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
799 pub enum ApprovalDistributionMessage {
800 #[codec(index = 0)]
804 Assignments(Vec<(IndirectAssignmentCert, CandidateIndex)>),
805 #[codec(index = 1)]
807 Approvals(Vec<IndirectSignedApprovalVote>),
808 }
809
810 #[derive(Debug, Clone, PartialEq, Eq)]
812 pub enum GossipSupportNetworkMessage {}
813
814 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
816 pub enum CollatorProtocolMessage {
817 #[codec(index = 0)]
820 Declare(CollatorId, ParaId, CollatorSignature),
821 #[codec(index = 1)]
824 AdvertiseCollation {
825 relay_parent: Hash,
827 candidate_hash: CandidateHash,
829 parent_head_data_hash: Hash,
831 },
832 #[codec(index = 4)]
834 CollationSeconded(Hash, UncheckedSignedFullStatement),
835 }
836
837 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
839 pub enum ValidationProtocol {
840 #[codec(index = 1)]
842 #[from]
843 BitfieldDistribution(BitfieldDistributionMessage),
844 #[codec(index = 3)]
846 #[from]
847 StatementDistribution(StatementDistributionMessage),
848 #[codec(index = 4)]
850 #[from]
851 ApprovalDistribution(ApprovalDistributionMessage),
852 }
853
854 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
856 pub enum CollationProtocol {
857 #[codec(index = 0)]
859 #[from]
860 CollatorProtocol(CollatorProtocolMessage),
861 }
862
863 pub fn declare_signature_payload(peer_id: &sc_network_types::PeerId) -> Vec<u8> {
868 let mut payload = peer_id.to_bytes();
869 payload.extend_from_slice(b"COLL");
870 payload
871 }
872}
873
874pub mod v3 {
878 use codec::{Decode, Encode};
879
880 use polkadot_node_primitives::approval::v2::{
881 CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2,
882 };
883
884 pub use super::v2::{
886 declare_signature_payload, BackedCandidateAcknowledgement, BackedCandidateManifest,
887 BitfieldDistributionMessage, GossipSupportNetworkMessage, StatementDistributionMessage,
888 StatementFilter,
889 };
890
891 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
893 pub enum ApprovalDistributionMessage {
894 #[codec(index = 0)]
904 Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>),
905 #[codec(index = 1)]
907 Approvals(Vec<IndirectSignedApprovalVoteV2>),
908 }
909
910 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
912 pub enum ValidationProtocol {
913 #[codec(index = 1)]
915 #[from]
916 BitfieldDistribution(BitfieldDistributionMessage),
917 #[codec(index = 3)]
919 #[from]
920 StatementDistribution(StatementDistributionMessage),
921 #[codec(index = 4)]
923 #[from]
924 ApprovalDistribution(ApprovalDistributionMessage),
925 }
926}
927
928pub fn filter_by_peer_version(
930 peers: &[(PeerId, peer_set::ProtocolVersion)],
931 version: peer_set::ProtocolVersion,
932) -> Vec<PeerId> {
933 peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::<Vec<_>>()
934}