1use std::io;
2
3use strum::FromRepr;
4
5use crate::{
6 address::{AddressVersion, StacksAddress},
7 codec::Codec,
8 contract_name::ContractName,
9};
10
11#[derive(PartialEq, Eq, Debug, Clone)]
12pub struct StandardPrincipalData(pub AddressVersion, pub StacksAddress);
14
15impl StandardPrincipalData {
16 pub fn new(version: AddressVersion, address: StacksAddress) -> Self {
19 Self(version, address)
20 }
21}
22
23impl Codec for StandardPrincipalData {
24 fn codec_serialize<W: io::Write>(&self, dest: &mut W) -> io::Result<()> {
25 self.1.codec_serialize(dest)
26 }
27
28 fn codec_deserialize<R: io::Read>(data: &mut R) -> io::Result<Self>
29 where
30 Self: Sized,
31 {
32 let addr = StacksAddress::codec_deserialize(data)?;
33
34 Ok(Self(addr.version(), addr))
35 }
36}
37
38impl From<StacksAddress> for StandardPrincipalData {
39 fn from(address: StacksAddress) -> Self {
40 Self(address.version(), address)
41 }
42}
43
44#[derive(PartialEq, Eq, Debug, Clone)]
45pub enum PrincipalData {
47 Standard(StandardPrincipalData),
49 Contract(StandardPrincipalData, ContractName),
51}
52
53#[repr(u8)]
54#[derive(FromRepr, Debug, Clone, Copy)]
55enum PrincipalTypeByte {
56 Standard = 0x05,
57 Contract = 0x06,
58}
59
60impl Codec for PrincipalData {
61 fn codec_serialize<W: io::Write>(&self, dest: &mut W) -> io::Result<()> {
62 match self {
63 Self::Standard(data) => {
64 dest.write_all(&[PrincipalTypeByte::Standard as u8])?;
65 data.codec_serialize(dest)
66 }
67 Self::Contract(data, contract_name) => {
68 dest.write_all(&[PrincipalTypeByte::Contract as u8])?;
69 data.codec_serialize(dest)?;
70 contract_name.codec_serialize(dest)
71 }
72 }
73 }
74
75 fn codec_deserialize<R: io::Read>(data: &mut R) -> io::Result<Self>
76 where
77 Self: Sized,
78 {
79 let mut type_buffer = [0u8; 1];
80 data.read_exact(&mut type_buffer)?;
81
82 let principal_type = PrincipalTypeByte::from_repr(type_buffer[0])
83 .ok_or_else(|| {
84 io::Error::new(
85 io::ErrorKind::InvalidData,
86 format!("Invalid principal type: {}", type_buffer[0]),
87 )
88 })?;
89
90 match principal_type {
91 PrincipalTypeByte::Standard => {
92 let standard_data =
93 StandardPrincipalData::codec_deserialize(data)?;
94
95 Ok(Self::Standard(standard_data))
96 }
97 PrincipalTypeByte::Contract => {
98 let standard_data =
99 StandardPrincipalData::codec_deserialize(data)?;
100 let contract_name = ContractName::codec_deserialize(data)?;
101
102 Ok(Self::Contract(standard_data, contract_name))
103 }
104 }
105 }
106}
107
108impl From<StacksAddress> for PrincipalData {
109 fn from(address: StacksAddress) -> Self {
110 Self::Standard(StandardPrincipalData::from(address))
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::crypto::hash160::Hash160Hasher;
118
119 #[test]
120 fn should_serialize_standard_principal_data() {
121 let addr = StacksAddress::new(
122 AddressVersion::TestnetSingleSig,
123 Hash160Hasher::default(),
124 );
125 let data = PrincipalData::Standard(StandardPrincipalData(
126 addr.version(),
127 addr.clone(),
128 ));
129
130 let mut expected_bytes = vec![];
131
132 expected_bytes.push(PrincipalTypeByte::Standard as u8);
133 expected_bytes.push(addr.version() as u8);
134 expected_bytes.extend(addr.hash().as_ref());
135
136 let serialized = data.serialize_to_vec();
137
138 assert_eq!(serialized, expected_bytes);
139 }
140
141 #[test]
142 fn should_deserialize_standard_principal_data() {
143 let addr = StacksAddress::new(
144 AddressVersion::TestnetSingleSig,
145 Hash160Hasher::default(),
146 );
147 let expected_principal_data = PrincipalData::Standard(
148 StandardPrincipalData(addr.version(), addr.clone()),
149 );
150
151 let mut expected_bytes = vec![];
152
153 expected_bytes.push(PrincipalTypeByte::Standard as u8);
154 expected_bytes.push(addr.version() as u8);
155 expected_bytes.extend(addr.hash().as_ref());
156
157 let serialized = expected_principal_data.serialize_to_vec();
158 let deserialized =
159 PrincipalData::deserialize(&mut &serialized[..]).unwrap();
160
161 assert_eq!(deserialized, expected_principal_data);
162 }
163
164 #[test]
165 fn should_serialize_contract_principal_data() {
166 let addr = StacksAddress::new(
167 AddressVersion::TestnetSingleSig,
168 Hash160Hasher::default(),
169 );
170 let contract = ContractName::new("helloworld").unwrap();
171 let data = PrincipalData::Contract(
172 StandardPrincipalData(addr.version(), addr.clone()),
173 contract.clone(),
174 );
175
176 let mut expected_bytes = vec![];
177
178 expected_bytes.push(PrincipalTypeByte::Contract as u8);
179 expected_bytes.push(addr.version() as u8);
180 expected_bytes.extend(addr.hash().as_ref());
181 expected_bytes.push(contract.len() as u8);
182 expected_bytes.extend(contract.as_bytes());
183
184 let serialized = data.serialize_to_vec();
185
186 assert_eq!(serialized, expected_bytes);
187 }
188
189 #[test]
190 fn should_deserialize_contract_principal_data() {
191 let addr = StacksAddress::new(
192 AddressVersion::TestnetSingleSig,
193 Hash160Hasher::default(),
194 );
195 let contract = ContractName::new("helloworld").unwrap();
196 let expected_principal_data = PrincipalData::Contract(
197 StandardPrincipalData(addr.version(), addr.clone()),
198 contract.clone(),
199 );
200
201 let mut expected_bytes = vec![];
202
203 expected_bytes.push(PrincipalTypeByte::Contract as u8);
204 expected_bytes.push(addr.version() as u8);
205 expected_bytes.extend(addr.hash().as_ref());
206 expected_bytes.push(contract.len() as u8);
207 expected_bytes.extend(contract.as_bytes());
208
209 let serialized = expected_principal_data.serialize_to_vec();
210 let deserialized =
211 PrincipalData::deserialize(&mut &serialized[..]).unwrap();
212
213 assert_eq!(deserialized, expected_principal_data);
214 }
215}