kaspa_consensus_core/
subnets.rs

1use std::fmt::{Debug, Display, Formatter};
2use std::str::{self, FromStr};
3
4use borsh::{BorshDeserialize, BorshSerialize};
5use kaspa_utils::hex::{FromHex, ToHex};
6use kaspa_utils::{serde_impl_deser_fixed_bytes_ref, serde_impl_ser_fixed_bytes_ref};
7use thiserror::Error;
8
9/// The size of the array used to store subnetwork IDs.
10pub const SUBNETWORK_ID_SIZE: usize = 20;
11
12/// The domain representation of a Subnetwork ID
13#[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, BorshSerialize, BorshDeserialize)]
14pub struct SubnetworkId([u8; SUBNETWORK_ID_SIZE]);
15
16impl Debug for SubnetworkId {
17    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("SubnetworkId").field("", &self.to_hex()).finish()
19    }
20}
21
22serde_impl_ser_fixed_bytes_ref!(SubnetworkId, SUBNETWORK_ID_SIZE);
23serde_impl_deser_fixed_bytes_ref!(SubnetworkId, SUBNETWORK_ID_SIZE);
24
25impl AsRef<[u8; SUBNETWORK_ID_SIZE]> for SubnetworkId {
26    fn as_ref(&self) -> &[u8; SUBNETWORK_ID_SIZE] {
27        &self.0
28    }
29}
30
31impl AsRef<[u8]> for SubnetworkId {
32    fn as_ref(&self) -> &[u8] {
33        &self.0
34    }
35}
36
37impl From<[u8; SUBNETWORK_ID_SIZE]> for SubnetworkId {
38    fn from(value: [u8; SUBNETWORK_ID_SIZE]) -> Self {
39        Self::from_bytes(value)
40    }
41}
42
43impl SubnetworkId {
44    pub const fn from_byte(b: u8) -> SubnetworkId {
45        let mut bytes = [0u8; SUBNETWORK_ID_SIZE];
46        bytes[0] = b;
47        SubnetworkId(bytes)
48    }
49
50    pub const fn from_bytes(bytes: [u8; SUBNETWORK_ID_SIZE]) -> SubnetworkId {
51        SubnetworkId(bytes)
52    }
53
54    /// Returns true if the subnetwork is a built-in subnetwork, which
55    /// means all nodes, including partial nodes, must validate it, and its transactions
56    /// always use 0 gas.
57    #[inline]
58    pub fn is_builtin(&self) -> bool {
59        *self == SUBNETWORK_ID_COINBASE || *self == SUBNETWORK_ID_REGISTRY
60    }
61
62    /// Returns true if the subnetwork is the native subnetwork
63    #[inline]
64    pub fn is_native(&self) -> bool {
65        *self == SUBNETWORK_ID_NATIVE
66    }
67
68    /// Returns true if the subnetwork is the native or a built-in subnetwork
69    #[inline]
70    pub fn is_builtin_or_native(&self) -> bool {
71        self.is_native() || self.is_builtin()
72    }
73}
74
75#[derive(Error, Debug, Clone)]
76pub enum SubnetworkConversionError {
77    #[error(transparent)]
78    SliceError(#[from] std::array::TryFromSliceError),
79
80    #[error(transparent)]
81    HexError(#[from] faster_hex::Error),
82}
83
84impl TryFrom<&[u8]> for SubnetworkId {
85    type Error = SubnetworkConversionError;
86
87    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
88        let bytes = <[u8; SUBNETWORK_ID_SIZE]>::try_from(value)?;
89        Ok(Self(bytes))
90    }
91}
92
93impl Display for SubnetworkId {
94    #[inline]
95    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96        let mut hex = [0u8; SUBNETWORK_ID_SIZE * 2];
97        faster_hex::hex_encode(&self.0, &mut hex).expect("The output is exactly twice the size of the input");
98        f.write_str(str::from_utf8(&hex).expect("hex is always valid UTF-8"))
99    }
100}
101
102impl ToHex for SubnetworkId {
103    fn to_hex(&self) -> String {
104        let mut hex = [0u8; SUBNETWORK_ID_SIZE * 2];
105        faster_hex::hex_encode(&self.0, &mut hex).expect("The output is exactly twice the size of the input");
106        str::from_utf8(&hex).expect("hex is always valid UTF-8").to_string()
107    }
108}
109
110impl FromStr for SubnetworkId {
111    type Err = SubnetworkConversionError;
112
113    #[inline]
114    fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
115        let mut bytes = [0u8; SUBNETWORK_ID_SIZE];
116        faster_hex::hex_decode(hex_str.as_bytes(), &mut bytes)?;
117        Ok(Self(bytes))
118    }
119}
120
121impl FromHex for SubnetworkId {
122    type Error = SubnetworkConversionError;
123    fn from_hex(hex_str: &str) -> Result<Self, Self::Error> {
124        let mut bytes = [0u8; SUBNETWORK_ID_SIZE];
125        faster_hex::hex_decode(hex_str.as_bytes(), &mut bytes)?;
126        Ok(Self(bytes))
127    }
128}
129
130/// The default subnetwork ID which is used for transactions without related payload data
131pub const SUBNETWORK_ID_NATIVE: SubnetworkId = SubnetworkId::from_byte(0);
132
133/// The subnetwork ID which is used for the coinbase transaction
134pub const SUBNETWORK_ID_COINBASE: SubnetworkId = SubnetworkId::from_byte(1);
135
136/// The subnetwork ID which is used for adding new sub networks to the registry
137pub const SUBNETWORK_ID_REGISTRY: SubnetworkId = SubnetworkId::from_byte(2);