casper_storage/data_access_layer/
key_prefix.rs1use casper_types::{
2 account::AccountHash,
3 bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
4 contract_messages::TopicNameHash,
5 system::{auction::BidAddrTag, mint::BalanceHoldAddrTag},
6 EntityAddr, KeyTag, URefAddr,
7};
8
9#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
11pub enum KeyPrefix {
12 DelegatorBidAddrsByValidator(AccountHash),
14 MessageEntriesByEntity(EntityAddr),
16 MessagesByEntityAndTopic(EntityAddr, TopicNameHash),
18 NamedKeysByEntity(EntityAddr),
20 GasBalanceHoldsByPurse(URefAddr),
22 ProcessingBalanceHoldsByPurse(URefAddr),
24 EntryPointsV1ByEntity(EntityAddr),
26 EntryPointsV2ByEntity(EntityAddr),
28}
29
30impl ToBytes for KeyPrefix {
31 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
32 let mut result = bytesrepr::unchecked_allocate_buffer(self);
33 self.write_bytes(&mut result)?;
34 Ok(result)
35 }
36
37 fn serialized_length(&self) -> usize {
38 U8_SERIALIZED_LENGTH
39 + match self {
40 KeyPrefix::DelegatorBidAddrsByValidator(validator) => {
41 U8_SERIALIZED_LENGTH + validator.serialized_length()
42 }
43 KeyPrefix::MessageEntriesByEntity(hash_addr) => hash_addr.serialized_length(),
44 KeyPrefix::MessagesByEntityAndTopic(hash_addr, topic) => {
45 hash_addr.serialized_length() + topic.serialized_length()
46 }
47 KeyPrefix::NamedKeysByEntity(entity) => entity.serialized_length(),
48 KeyPrefix::GasBalanceHoldsByPurse(uref) => {
49 U8_SERIALIZED_LENGTH + uref.serialized_length()
50 }
51 KeyPrefix::ProcessingBalanceHoldsByPurse(uref) => {
52 U8_SERIALIZED_LENGTH + uref.serialized_length()
53 }
54 KeyPrefix::EntryPointsV1ByEntity(entity) => {
55 U8_SERIALIZED_LENGTH + entity.serialized_length()
56 }
57 KeyPrefix::EntryPointsV2ByEntity(entity) => {
58 U8_SERIALIZED_LENGTH + entity.serialized_length()
59 }
60 }
61 }
62
63 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
64 match self {
65 KeyPrefix::DelegatorBidAddrsByValidator(validator) => {
66 writer.push(KeyTag::BidAddr as u8);
67 writer.push(BidAddrTag::DelegatedAccount as u8);
68 validator.write_bytes(writer)?;
69 }
70 KeyPrefix::MessageEntriesByEntity(hash_addr) => {
71 writer.push(KeyTag::Message as u8);
72 hash_addr.write_bytes(writer)?;
73 }
74 KeyPrefix::MessagesByEntityAndTopic(hash_addr, topic) => {
75 writer.push(KeyTag::Message as u8);
76 hash_addr.write_bytes(writer)?;
77 topic.write_bytes(writer)?;
78 }
79 KeyPrefix::NamedKeysByEntity(entity) => {
80 writer.push(KeyTag::NamedKey as u8);
81 entity.write_bytes(writer)?;
82 }
83 KeyPrefix::GasBalanceHoldsByPurse(uref) => {
84 writer.push(KeyTag::BalanceHold as u8);
85 writer.push(BalanceHoldAddrTag::Gas as u8);
86 uref.write_bytes(writer)?;
87 }
88 KeyPrefix::ProcessingBalanceHoldsByPurse(uref) => {
89 writer.push(KeyTag::BalanceHold as u8);
90 writer.push(BalanceHoldAddrTag::Processing as u8);
91 uref.write_bytes(writer)?;
92 }
93 KeyPrefix::EntryPointsV1ByEntity(entity) => {
94 writer.push(KeyTag::EntryPoint as u8);
95 writer.push(0);
96 entity.write_bytes(writer)?;
97 }
98 KeyPrefix::EntryPointsV2ByEntity(entity) => {
99 writer.push(KeyTag::EntryPoint as u8);
100 writer.push(1);
101 entity.write_bytes(writer)?;
102 }
103 }
104 Ok(())
105 }
106}
107
108impl FromBytes for KeyPrefix {
109 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
110 let (tag, remainder) = u8::from_bytes(bytes)?;
111 let result = match tag {
112 tag if tag == KeyTag::BidAddr as u8 => {
113 let (bid_addr_tag, remainder) = u8::from_bytes(remainder)?;
114 match bid_addr_tag {
115 tag if tag == BidAddrTag::DelegatedAccount as u8 => {
116 let (validator, remainder) = AccountHash::from_bytes(remainder)?;
117 (
118 KeyPrefix::DelegatorBidAddrsByValidator(validator),
119 remainder,
120 )
121 }
122 _ => return Err(bytesrepr::Error::Formatting),
123 }
124 }
125 tag if tag == KeyTag::Message as u8 => {
126 let (hash_addr, remainder) = EntityAddr::from_bytes(remainder)?;
127 if remainder.is_empty() {
128 (KeyPrefix::MessageEntriesByEntity(hash_addr), remainder)
129 } else {
130 let (topic, remainder) = TopicNameHash::from_bytes(remainder)?;
131 (
132 KeyPrefix::MessagesByEntityAndTopic(hash_addr, topic),
133 remainder,
134 )
135 }
136 }
137 tag if tag == KeyTag::NamedKey as u8 => {
138 let (entity, remainder) = EntityAddr::from_bytes(remainder)?;
139 (KeyPrefix::NamedKeysByEntity(entity), remainder)
140 }
141 tag if tag == KeyTag::BalanceHold as u8 => {
142 let (balance_hold_addr_tag, remainder) = u8::from_bytes(remainder)?;
143 let (uref, remainder) = URefAddr::from_bytes(remainder)?;
144 match balance_hold_addr_tag {
145 tag if tag == BalanceHoldAddrTag::Gas as u8 => {
146 (KeyPrefix::GasBalanceHoldsByPurse(uref), remainder)
147 }
148 tag if tag == BalanceHoldAddrTag::Processing as u8 => {
149 (KeyPrefix::ProcessingBalanceHoldsByPurse(uref), remainder)
150 }
151 _ => return Err(bytesrepr::Error::Formatting),
152 }
153 }
154 tag if tag == KeyTag::EntryPoint as u8 => {
155 let (entry_point_type, remainder) = u8::from_bytes(remainder)?;
156 let (entity, remainder) = EntityAddr::from_bytes(remainder)?;
157 match entry_point_type {
158 0 => (KeyPrefix::EntryPointsV1ByEntity(entity), remainder),
159 1 => (KeyPrefix::EntryPointsV2ByEntity(entity), remainder),
160 _ => return Err(bytesrepr::Error::Formatting),
161 }
162 }
163 _ => return Err(bytesrepr::Error::Formatting),
164 };
165 Ok(result)
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use casper_types::testing::TestRng;
172 use rand::Rng;
173
174 use casper_types::{
175 addressable_entity::NamedKeyAddr,
176 contract_messages::MessageAddr,
177 gens::{account_hash_arb, entity_addr_arb, topic_name_hash_arb, u8_slice_32},
178 system::{auction::BidAddr, mint::BalanceHoldAddr},
179 BlockTime, EntryPointAddr, Key,
180 };
181
182 use super::*;
183 use proptest::prelude::*;
184
185 pub fn key_prefix_arb() -> impl Strategy<Value = KeyPrefix> {
186 prop_oneof![
187 account_hash_arb().prop_map(KeyPrefix::DelegatorBidAddrsByValidator),
188 entity_addr_arb().prop_map(KeyPrefix::MessageEntriesByEntity),
189 (entity_addr_arb(), topic_name_hash_arb()).prop_map(|(entity_addr, topic)| {
190 KeyPrefix::MessagesByEntityAndTopic(entity_addr, topic)
191 }),
192 entity_addr_arb().prop_map(KeyPrefix::NamedKeysByEntity),
193 u8_slice_32().prop_map(KeyPrefix::GasBalanceHoldsByPurse),
194 u8_slice_32().prop_map(KeyPrefix::ProcessingBalanceHoldsByPurse),
195 entity_addr_arb().prop_map(KeyPrefix::EntryPointsV1ByEntity),
196 entity_addr_arb().prop_map(KeyPrefix::EntryPointsV2ByEntity),
197 ]
198 }
199
200 proptest! {
201 #[test]
202 fn bytesrepr_roundtrip(key_prefix in key_prefix_arb()) {
203 bytesrepr::test_serialization_roundtrip(&key_prefix);
204 }
205 }
206
207 #[test]
208 fn key_serializer_compat() {
209 let rng = &mut TestRng::new();
214
215 let hash1 = rng.gen();
216 let hash2 = rng.gen();
217
218 for (key, prefix) in [
219 (
220 Key::BidAddr(BidAddr::new_delegator_account_addr((hash1, hash2))),
221 KeyPrefix::DelegatorBidAddrsByValidator(AccountHash::new(hash1)),
222 ),
223 (
224 Key::Message(MessageAddr::new_message_addr(
225 EntityAddr::SmartContract(hash1),
226 TopicNameHash::new(hash2),
227 0,
228 )),
229 KeyPrefix::MessagesByEntityAndTopic(
230 EntityAddr::SmartContract(hash1),
231 TopicNameHash::new(hash2),
232 ),
233 ),
234 (
235 Key::NamedKey(NamedKeyAddr::new_named_key_entry(
236 EntityAddr::Account(hash1),
237 hash2,
238 )),
239 KeyPrefix::NamedKeysByEntity(EntityAddr::Account(hash1)),
240 ),
241 (
242 Key::BalanceHold(BalanceHoldAddr::new_gas(hash1, BlockTime::new(0))),
243 KeyPrefix::GasBalanceHoldsByPurse(hash1),
244 ),
245 (
246 Key::BalanceHold(BalanceHoldAddr::new_processing(hash1, BlockTime::new(0))),
247 KeyPrefix::ProcessingBalanceHoldsByPurse(hash1),
248 ),
249 (
250 Key::EntryPoint(
251 EntryPointAddr::new_v1_entry_point_addr(EntityAddr::Account(hash1), "name")
252 .expect("should create entry point"),
253 ),
254 KeyPrefix::EntryPointsV1ByEntity(EntityAddr::Account(hash1)),
255 ),
256 ] {
257 let key_bytes = key.to_bytes().expect("should serialize key");
258 let (parsed_key_prefix, remainder) =
259 KeyPrefix::from_bytes(&key_bytes).expect("should deserialize key prefix");
260 assert_eq!(parsed_key_prefix, prefix, "key: {:?}", key);
261 assert!(!remainder.is_empty(), "key: {:?}", key);
262 }
263 }
264}