Skip to main content

solana_packet/
lib.rs

1//! The definition of a Solana network packet.
2#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5#[cfg(feature = "frozen-abi")]
6use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi, StableAbiSample};
7#[cfg(feature = "bincode")]
8use {
9    bincode::{Options, Result},
10    std::io::Write,
11};
12use {
13    bitflags::bitflags,
14    solana_pubkey::Pubkey,
15    std::{
16        fmt,
17        net::{IpAddr, Ipv4Addr, SocketAddr},
18        slice::SliceIndex,
19    },
20};
21#[cfg(feature = "wincode")]
22use {
23    core::mem::MaybeUninit,
24    wincode::{
25        config::ConfigCore,
26        io::{Reader, Writer},
27        ReadResult, SchemaRead, SchemaWrite, TypeMeta, WriteResult,
28    },
29};
30#[cfg(feature = "serde")]
31use {
32    serde_derive::{Deserialize, Serialize},
33    serde_with::{serde_as, Bytes},
34};
35
36#[cfg(test)]
37static_assertions::const_assert_eq!(PACKET_DATA_SIZE, 1232);
38/// Maximum over-the-wire size of a Transaction
39///   1280 is IPv6 minimum MTU
40///   40 bytes is the size of the IPv6 header
41///   8 bytes is the size of the fragment header
42pub const PACKET_DATA_SIZE: usize = 1280 - 40 - 8;
43
44#[cfg(feature = "bincode")]
45pub trait Encode {
46    fn encode<W: Write>(&self, writer: W) -> Result<()>;
47}
48
49#[cfg(feature = "bincode")]
50impl<T: ?Sized + serde::Serialize> Encode for T {
51    fn encode<W: Write>(&self, writer: W) -> Result<()> {
52        bincode::serialize_into::<W, T>(writer, self)
53    }
54}
55
56bitflags! {
57    #[repr(C)]
58    #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
59    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
60    pub struct PacketFlags: u8 {
61        const DISCARD        = 0b0000_0001;
62        const FORWARDED      = 0b0000_0010;
63        const REPAIR         = 0b0000_0100;
64        const SIMPLE_VOTE_TX = 0b0000_1000;
65        // Previously used - this can now be re-used for something else.
66        const UNUSED_0  = 0b0001_0000;
67        // Previously used - this can now be re-used for something else.
68        const UNUSED_1 = 0b0010_0000;
69        /// For tracking performance
70        const PERF_TRACK_PACKET  = 0b0100_0000;
71        /// For marking packets from staked nodes
72        const FROM_STAKED_NODE = 0b1000_0000;
73    }
74}
75
76#[cfg_attr(feature = "frozen-abi", derive(AbiExample, StableAbi, StableAbiSample))]
77#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
78#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
79#[derive(Clone, Debug, PartialEq, Eq)]
80#[repr(C)]
81pub struct Meta {
82    pub size: usize,
83    pub addr: IpAddr,
84    pub port: u16,
85    #[cfg_attr(feature = "wincode", wincode(with = "PodPacketFlags"))]
86    pub flags: PacketFlags,
87    remote_pubkey: Pubkey,
88}
89
90#[cfg(feature = "frozen-abi")]
91impl ::solana_frozen_abi::abi_example::AbiExample for PacketFlags {
92    fn example() -> Self {
93        Self::empty()
94    }
95}
96
97#[cfg(feature = "frozen-abi")]
98impl ::solana_frozen_abi::abi_example::TransparentAsHelper for PacketFlags {}
99
100#[cfg(feature = "frozen-abi")]
101impl ::solana_frozen_abi::abi_example::EvenAsOpaque for PacketFlags {
102    const TYPE_NAME_MATCHER: &'static str = "::_::InternalBitFlags";
103}
104
105#[cfg(feature = "frozen-abi")]
106impl ::solana_frozen_abi::stable_abi::StableAbi for PacketFlags {
107    fn random_with_context(
108        rng: &mut (impl ::solana_frozen_abi::rand::RngCore + ?Sized),
109        _ctx: (),
110    ) -> Self {
111        // All bits are defined, but truncate making it future-proof.
112        Self::from_bits_truncate(::solana_frozen_abi::rand::Rng::random(rng))
113    }
114}
115
116// Every bit is a defined flag, so any byte is a valid `PacketFlags`; it is a
117// single `u8` in memory and can be serialized as raw bytes.
118#[cfg(feature = "wincode")]
119wincode::pod_wrapper! {
120    unsafe struct PodPacketFlags(PacketFlags);
121}
122
123/// Wincode schema adapter for a fixed `[u8; N]` written as bincode serializes it
124/// through `serde`'s `serialize_bytes`: a `u64` length prefix followed by the raw
125/// bytes (a bare `[u8; N]` is otherwise written without a length).
126#[cfg(feature = "wincode")]
127struct LenPrefixedByteArray<const N: usize>;
128
129#[cfg(feature = "wincode")]
130unsafe impl<const N: usize, C: ConfigCore> SchemaWrite<C> for LenPrefixedByteArray<N> {
131    type Src = [u8; N];
132
133    const TYPE_META: TypeMeta = TypeMeta::join_types([
134        <u64 as SchemaWrite<C>>::TYPE_META,
135        <[u8; N] as SchemaWrite<C>>::TYPE_META,
136    ])
137    .keep_zero_copy(false);
138
139    fn size_of(src: &Self::Src) -> WriteResult<usize> {
140        Ok(<u64 as SchemaWrite<C>>::size_of(&(N as u64))?
141            .saturating_add(<[u8; N] as SchemaWrite<C>>::size_of(src)?))
142    }
143
144    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
145        <u64 as SchemaWrite<C>>::write(writer.by_ref(), &(N as u64))?;
146        <[u8; N] as SchemaWrite<C>>::write(writer, src)
147    }
148}
149
150#[cfg(feature = "wincode")]
151unsafe impl<'de, const N: usize, C: ConfigCore> SchemaRead<'de, C> for LenPrefixedByteArray<N> {
152    type Dst = [u8; N];
153
154    const TYPE_META: TypeMeta = TypeMeta::join_types([
155        <u64 as SchemaRead<'de, C>>::TYPE_META,
156        <[u8; N] as SchemaRead<'de, C>>::TYPE_META,
157    ])
158    .keep_zero_copy(false);
159
160    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
161        let len = <u64 as SchemaRead<'de, C>>::get(reader.by_ref())?;
162        if len != N as u64 {
163            return Err(wincode::error::invalid_value(
164                "unexpected packet buffer length",
165            ));
166        }
167        <[u8; N] as SchemaRead<'de, C>>::read(reader, dst)
168    }
169}
170
171// serde_as is used as a work around because array isn't supported by serde
172// (and serde_bytes).
173//
174// the root cause is of a historical special handling for [T; 0] in rust's
175// `Default` and supposedly mirrored serde's `Serialize` (macro) impls,
176// pre-dating stabilized const generics, meaning it'll take long time...:
177//   https://github.com/rust-lang/rust/issues/61415
178//   https://github.com/rust-lang/rust/issues/88744#issuecomment-1138678928
179//
180// Due to the nature of the root cause, the current situation is complicated.
181// All in all, the serde_as solution is chosen for good perf and low maintenance
182// need at the cost of another crate dependency..
183//
184// For details, please refer to the below various links...
185//
186// relevant merged/published pr for this serde_as functionality used here:
187//   https://github.com/jonasbb/serde_with/pull/277
188// open pr at serde_bytes:
189//   https://github.com/serde-rs/bytes/pull/28
190// open issue at serde:
191//   https://github.com/serde-rs/serde/issues/1937
192// closed pr at serde (due to the above mentioned [N; 0] issue):
193//   https://github.com/serde-rs/serde/pull/1860
194// ryoqun's dirty experiments:
195//   https://github.com/ryoqun/serde-array-comparisons
196//
197// We use the cfg_eval crate as advised by the serde_with guide:
198// https://docs.rs/serde_with/latest/serde_with/guide/serde_as/index.html#gating-serde_as-on-features
199#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)]
200#[cfg_attr(
201    feature = "frozen-abi",
202    derive(AbiExample, StableAbi, StableAbiSample),
203    frozen_abi(
204        abi_digest = "5MtHLJ3g6mJfsz9KfxnUgjksRUXSETinR9jZZiYuE7fh",
205        abi_serializer = ["bincode", "wincode"],
206        test_roundtrip = "eq_and_wire"
207    )
208)]
209#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
210#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
211#[derive(Clone, Eq)]
212#[repr(C)]
213pub struct Packet {
214    // Bytes past Packet.meta.size are not valid to read from.
215    // Use Packet.data(index) to read from the buffer.
216    #[cfg_attr(feature = "serde", serde_as(as = "Bytes"))]
217    #[cfg_attr(
218        feature = "wincode",
219        wincode(with = "LenPrefixedByteArray<PACKET_DATA_SIZE>")
220    )]
221    buffer: [u8; PACKET_DATA_SIZE],
222    meta: Meta,
223}
224
225impl Packet {
226    pub fn new(buffer: [u8; PACKET_DATA_SIZE], meta: Meta) -> Self {
227        Self { buffer, meta }
228    }
229
230    /// Returns an immutable reference to the underlying buffer up to
231    /// packet.meta.size. The rest of the buffer is not valid to read from.
232    /// packet.data(..) returns packet.buffer.get(..packet.meta.size).
233    /// Returns None if the index is invalid or if the packet is already marked
234    /// as discard.
235    #[inline]
236    pub fn data<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
237    where
238        I: SliceIndex<[u8]>,
239    {
240        // If the packet is marked as discard, it is either invalid or
241        // otherwise should be ignored, and so the payload should not be read
242        // from.
243        if self.meta.discard() {
244            None
245        } else {
246            self.buffer.get(..self.meta.size)?.get(index)
247        }
248    }
249
250    /// Returns a mutable reference to the entirety of the underlying buffer to
251    /// write into. The caller is responsible for updating Packet.meta.size
252    /// after writing to the buffer.
253    #[inline]
254    pub fn buffer_mut(&mut self) -> &mut [u8] {
255        debug_assert!(!self.meta.discard());
256        &mut self.buffer[..]
257    }
258
259    #[inline]
260    pub fn meta(&self) -> &Meta {
261        &self.meta
262    }
263
264    #[inline]
265    pub fn meta_mut(&mut self) -> &mut Meta {
266        &mut self.meta
267    }
268
269    #[cfg(feature = "bincode")]
270    pub fn from_data<T: Encode>(dest: Option<&SocketAddr>, data: T) -> Result<Self> {
271        let mut packet = Self::default();
272        Self::populate_packet(&mut packet, dest, &data)?;
273        Ok(packet)
274    }
275
276    #[cfg(feature = "bincode")]
277    pub fn populate_packet<T: Encode>(
278        &mut self,
279        dest: Option<&SocketAddr>,
280        data: &T,
281    ) -> Result<()> {
282        debug_assert!(!self.meta.discard());
283        let mut wr = std::io::Cursor::new(self.buffer_mut());
284        <T as Encode>::encode(data, &mut wr)?;
285        self.meta.size = wr.position() as usize;
286        if let Some(dest) = dest {
287            self.meta.set_socket_addr(dest);
288        }
289        Ok(())
290    }
291
292    #[cfg(feature = "bincode")]
293    pub fn deserialize_slice<T, I>(&self, index: I) -> Result<T>
294    where
295        T: serde::de::DeserializeOwned,
296        I: SliceIndex<[u8], Output = [u8]>,
297    {
298        let bytes = self.data(index).ok_or(bincode::ErrorKind::SizeLimit)?;
299        bincode::options()
300            .with_limit(PACKET_DATA_SIZE as u64)
301            .with_fixint_encoding()
302            .reject_trailing_bytes()
303            .deserialize(bytes)
304    }
305}
306
307impl fmt::Debug for Packet {
308    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309        write!(
310            f,
311            "Packet {{ size: {:?}, addr: {:?} }}",
312            self.meta.size,
313            self.meta.socket_addr()
314        )
315    }
316}
317
318impl Default for Packet {
319    fn default() -> Self {
320        Self {
321            buffer: [0; PACKET_DATA_SIZE],
322            meta: Meta::default(),
323        }
324    }
325}
326
327impl PartialEq for Packet {
328    fn eq(&self, other: &Self) -> bool {
329        self.meta() == other.meta() && self.data(..) == other.data(..)
330    }
331}
332
333impl Meta {
334    pub fn new(
335        size: usize,
336        addr: IpAddr,
337        port: u16,
338        flags: PacketFlags,
339        remote_pubkey: Option<Pubkey>,
340    ) -> Self {
341        Self {
342            size,
343            addr,
344            port,
345            flags,
346            remote_pubkey: remote_pubkey.unwrap_or_default(),
347        }
348    }
349
350    pub fn socket_addr(&self) -> SocketAddr {
351        SocketAddr::new(self.addr, self.port)
352    }
353
354    pub fn set_socket_addr(&mut self, socket_addr: &SocketAddr) {
355        self.addr = socket_addr.ip();
356        self.port = socket_addr.port();
357    }
358
359    pub fn set_from_staked_node(&mut self, from_staked_node: bool) {
360        self.flags
361            .set(PacketFlags::FROM_STAKED_NODE, from_staked_node);
362    }
363
364    #[inline]
365    pub fn discard(&self) -> bool {
366        self.flags.contains(PacketFlags::DISCARD)
367    }
368
369    #[inline]
370    pub fn set_discard(&mut self, discard: bool) {
371        self.flags.set(PacketFlags::DISCARD, discard);
372    }
373
374    #[deprecated(since = "4.2.0", note = "Not in use anymore")]
375    #[inline]
376    pub fn set_track_performance(&mut self, is_performance_track: bool) {
377        self.flags
378            .set(PacketFlags::PERF_TRACK_PACKET, is_performance_track);
379    }
380
381    #[inline]
382    pub fn set_simple_vote(&mut self, is_simple_vote: bool) {
383        self.flags.set(PacketFlags::SIMPLE_VOTE_TX, is_simple_vote);
384    }
385
386    #[inline]
387    pub fn forwarded(&self) -> bool {
388        self.flags.contains(PacketFlags::FORWARDED)
389    }
390
391    #[inline]
392    pub fn repair(&self) -> bool {
393        self.flags.contains(PacketFlags::REPAIR)
394    }
395
396    #[inline]
397    pub fn is_simple_vote_tx(&self) -> bool {
398        self.flags.contains(PacketFlags::SIMPLE_VOTE_TX)
399    }
400
401    #[deprecated(since = "4.2.0", note = "Not in use anymore")]
402    #[inline]
403    pub fn is_perf_track_packet(&self) -> bool {
404        self.flags.contains(PacketFlags::PERF_TRACK_PACKET)
405    }
406
407    #[inline]
408    pub fn is_from_staked_node(&self) -> bool {
409        self.flags.contains(PacketFlags::FROM_STAKED_NODE)
410    }
411
412    #[inline]
413    pub fn remote_pubkey(&self) -> Option<Pubkey> {
414        if self.remote_pubkey == Pubkey::default() {
415            None
416        } else {
417            Some(self.remote_pubkey)
418        }
419    }
420
421    /// Sets the remote pubkey. Use Pubkey::default() to clear.
422    #[inline]
423    pub fn set_remote_pubkey(&mut self, pubkey: Pubkey) {
424        self.remote_pubkey = pubkey;
425    }
426}
427
428impl Default for Meta {
429    fn default() -> Self {
430        Self {
431            size: 0,
432            addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
433            port: 0,
434            flags: PacketFlags::empty(),
435            remote_pubkey: Pubkey::default(),
436        }
437    }
438}
439
440#[cfg(test)]
441mod tests {
442    use super::*;
443
444    #[test]
445    fn test_deserialize_slice() {
446        let p = Packet::from_data(None, u32::MAX).unwrap();
447        assert_eq!(p.deserialize_slice(..).ok(), Some(u32::MAX));
448        assert_eq!(p.deserialize_slice(0..4).ok(), Some(u32::MAX));
449        assert_eq!(
450            p.deserialize_slice::<u16, _>(0..4)
451                .map_err(|e| e.to_string()),
452            Err("Slice had bytes remaining after deserialization".to_string()),
453        );
454        assert_eq!(
455            p.deserialize_slice::<u32, _>(0..0)
456                .map_err(|e| e.to_string()),
457            Err("io error: unexpected end of file".to_string()),
458        );
459        assert_eq!(
460            p.deserialize_slice::<u32, _>(0..1)
461                .map_err(|e| e.to_string()),
462            Err("io error: unexpected end of file".to_string()),
463        );
464        assert_eq!(
465            p.deserialize_slice::<u32, _>(0..5)
466                .map_err(|e| e.to_string()),
467            Err("the size limit has been reached".to_string()),
468        );
469        #[allow(clippy::reversed_empty_ranges)]
470        let reversed_empty_range = 4..0;
471        assert_eq!(
472            p.deserialize_slice::<u32, _>(reversed_empty_range)
473                .map_err(|e| e.to_string()),
474            Err("the size limit has been reached".to_string()),
475        );
476        assert_eq!(
477            p.deserialize_slice::<u32, _>(4..5)
478                .map_err(|e| e.to_string()),
479            Err("the size limit has been reached".to_string()),
480        );
481    }
482
483    #[test]
484    fn test_remote_pubkey() {
485        let mut meta = Meta::default();
486        assert!(meta.remote_pubkey().is_none());
487        let pubkey = Pubkey::new_unique();
488        meta.set_remote_pubkey(pubkey);
489        assert_eq!(meta.remote_pubkey(), Some(pubkey));
490        let pubkey = Pubkey::default();
491        meta.set_remote_pubkey(pubkey);
492        assert!(meta.remote_pubkey().is_none());
493    }
494
495    #[test]
496    fn test_meta_new() {
497        let size = 1024;
498        let addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
499        let port = 8080;
500        let flags = PacketFlags::FROM_STAKED_NODE | PacketFlags::REPAIR;
501        let pubkey = Pubkey::new_unique();
502
503        let meta = Meta::new(size, addr, port, flags, Some(pubkey));
504
505        assert_eq!(meta.size, size);
506        assert_eq!(meta.addr, addr);
507        assert_eq!(meta.port, port);
508        assert_eq!(meta.flags, flags);
509        assert_eq!(meta.remote_pubkey, pubkey);
510        assert_eq!(meta.remote_pubkey(), Some(pubkey));
511        let meta = Meta::new(size, addr, port, flags, None);
512        assert_eq!(meta.remote_pubkey, Pubkey::default());
513        assert_eq!(meta.remote_pubkey(), None);
514    }
515}