1use base64::{
2 engine::general_purpose::{STANDARD, URL_SAFE},
3 Engine,
4};
5use cbor_event::cbor;
6use cml_core::DeserializeError;
7use cml_crypto::{CryptoError, RawBytesEncoding};
8use serde_json;
9use std::collections::BTreeMap;
10use std::io::Read;
11use std::str::FromStr;
12use std::time::{Duration, SystemTime};
13
14use crate::byron::{
15 AddressContent, ByronAddress, ParseExtendedAddrError, ProtocolMagic, StakeholderId,
16};
17use crate::crypto::{BlockHeaderHash, TransactionHash};
18use crate::fees::LinearFee;
19use cml_crypto::chain_crypto::byron_proxy_key::ByronProxySecretKey;
20use cml_crypto::chain_crypto::{
21 self, Blake2b256, Ed25519, Ed25519Bip32, Signature, SignatureFromStrError,
22};
23use cml_crypto::{blake2b256, Bip32PublicKey};
24
25use super::{config, raw};
26
27#[derive(Debug, thiserror::Error)]
28pub enum GenesisJSONError {
29 #[error("JSON: {0:?}")]
30 Serde(#[from] serde_json::Error),
31 #[error("Crypto: {0:?}")]
32 CryptoError(#[from] CryptoError),
33 #[error("Deserialize: {0:?}")]
34 DeserializeError(#[from] DeserializeError),
35 #[error("Base64: {0:?}")]
36 Base64(#[from] base64::DecodeError),
37 #[error("ParseInt: {0:?}")]
38 ParseInt(#[from] std::num::ParseIntError),
39 #[error("ByronAddress: {0:?}")]
40 ByronAddress(#[from] ParseExtendedAddrError),
41 #[error("SignatureParse: {0:?}")]
42 SignatureParse(#[from] SignatureFromStrError),
43 #[error("Stakeholder not found: {0}")]
44 StakeholderMissing(String),
45}
46
47pub fn parse_genesis_data<R: Read>(json: R) -> Result<config::GenesisData, GenesisJSONError> {
48 let data_value: serde_json::Value = serde_json::from_reader(json)?;
49 let genesis_prev =
50 BlockHeaderHash::from_raw_bytes(&blake2b256(data_value.to_string().as_bytes()))?;
51 let data: raw::GenesisData = serde_json::from_value(data_value.clone())?;
52
53 let protocol_magic = ProtocolMagic::from(data.protocolConsts.protocolMagic);
54
55 let parse_fee_constant = |s: &str| s.parse::<u64>();
56
57 let mut avvm_distr = BTreeMap::new();
58 for (avvm, balance) in &data.avvmDistr {
59 avvm_distr.insert(
60 chain_crypto::PublicKey::<Ed25519>::from_binary(&URL_SAFE.decode(avvm)?)
61 .map_err(CryptoError::from)?,
62 balance.parse::<u64>()?,
63 );
64 }
65
66 let slot_duration = {
67 let v = data.blockVersionData.slotDuration.parse::<u64>()?;
68 Duration::from_millis(v)
69 };
70
71 let start_time = {
72 let unix_displacement = Duration::from_secs(data.startTime);
73 SystemTime::UNIX_EPOCH + unix_displacement
74 };
75
76 let mut non_avvm_balances = BTreeMap::new();
77 for (address, balance) in &data.nonAvvmBalances {
78 non_avvm_balances.insert(ByronAddress::from_str(address)?, balance.parse::<u64>()?);
79 }
80
81 let mut boot_stakeholders = BTreeMap::new();
82
83 for (stakeholder_id, weight) in &data.bootStakeholders {
84 let heavy = data
85 .heavyDelegation
86 .get(stakeholder_id)
87 .ok_or_else(|| GenesisJSONError::StakeholderMissing(stakeholder_id.clone()))?;
88
89 let stakeholder_id = StakeholderId::from_hex(stakeholder_id)?;
90
91 let psk = ByronProxySecretKey {
92 omega: 0,
93 issuer_pk: chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(
94 &STANDARD.decode(&heavy.issuerPk)?,
95 )
96 .map_err(CryptoError::from)?,
97 delegate_pk: chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(
98 &STANDARD.decode(&heavy.delegatePk)?,
99 )
100 .map_err(CryptoError::from)?,
101 cert: Signature::<(), Ed25519Bip32>::from_str(&heavy.cert)?,
102 };
103
104 assert_eq!(
106 stakeholder_id,
107 StakeholderId::new(&Bip32PublicKey(psk.issuer_pk.clone()))
108 );
109
110 assert!(psk.verify(protocol_magic));
112
113 boot_stakeholders.insert(
114 stakeholder_id,
115 config::BootStakeholder {
116 weight: *weight,
117 issuer_pk: psk.issuer_pk,
118 delegate_pk: psk.delegate_pk,
119 cert: psk.cert,
120 },
121 );
122 }
123
124 Ok(config::GenesisData {
125 genesis_prev,
126 epoch_stability_depth: data.protocolConsts.k,
127 protocol_magic,
128 fee_policy: LinearFee::new(
129 parse_fee_constant(&data.blockVersionData.txFeePolicy.multiplier)?,
130 parse_fee_constant(&data.blockVersionData.txFeePolicy.summand)?,
131 0,
132 ),
133 avvm_distr,
134 non_avvm_balances,
135 start_time,
136 slot_duration,
137 boot_stakeholders,
138 })
139}
140
141pub fn canonicalize_json<R: Read>(json: R) -> Result<String, GenesisJSONError> {
142 let data: serde_json::Value = serde_json::from_reader(json)?;
143 Ok(data.to_string())
144}
145
146pub fn redeem_pubkey_to_txid(
147 pubkey: &chain_crypto::PublicKey<Ed25519>,
148 protocol_magic: Option<ProtocolMagic>,
149) -> (TransactionHash, ByronAddress) {
150 let address_content =
151 AddressContent::new_redeem(cml_crypto::PublicKey(pubkey.clone()), protocol_magic);
152 let byron_address = address_content.to_address();
153 let txid = Blake2b256::new(&cbor!(&byron_address).unwrap());
154 (TransactionHash::from(*txid.as_hash_bytes()), byron_address)
155}
156
157#[cfg(test)]
158mod test {
159 use super::*;
160
161 use crate::crypto::BlockHeaderHash;
162
163 fn get_test_genesis_data(genesis_prev: &BlockHeaderHash) -> Result<&str, BlockHeaderHash> {
164 if genesis_prev
165 == &BlockHeaderHash::from_hex(
166 "5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb",
167 )
168 .unwrap()
169 {
170 Ok(include_str!(
171 "./test_data/5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb.json"
172 ))
173 } else if genesis_prev
174 == &BlockHeaderHash::from_hex(
175 "b7f76950bc4866423538ab7764fc1c7020b24a5f717a5bee3109ff2796567214",
176 )
177 .unwrap()
178 {
179 Ok(include_str!(
180 "./test_data/b7f76950bc4866423538ab7764fc1c7020b24a5f717a5bee3109ff2796567214.json"
181 ))
182 } else if genesis_prev
183 == &BlockHeaderHash::from_hex(
184 "c6a004d3d178f600cd8caa10abbebe1549bef878f0665aea2903472d5abf7323",
185 )
186 .unwrap()
187 {
188 Ok(include_str!(
189 "./test_data/c6a004d3d178f600cd8caa10abbebe1549bef878f0665aea2903472d5abf7323.json"
190 ))
191 } else if genesis_prev
192 == &BlockHeaderHash::from_hex(
193 "96fceff972c2c06bd3bb5243c39215333be6d56aaf4823073dca31afe5038471",
194 )
195 .unwrap()
196 {
197 Ok(include_str!(
198 "./test_data/96fceff972c2c06bd3bb5243c39215333be6d56aaf4823073dca31afe5038471.json"
199 ))
200 } else {
201 Err(*genesis_prev)
202 }
203 }
204
205 #[test]
206 pub fn calc_redeem_txid() {
207 let (hash, address) = redeem_pubkey_to_txid(
208 &chain_crypto::PublicKey::<Ed25519>::from_binary(
209 &URL_SAFE
210 .decode("AAG3vJwTzCcL0zp2-1yfI-mn_7haYvSYJln2xR_aBS8=")
211 .unwrap(),
212 )
213 .unwrap(),
214 None,
215 );
216 assert_eq!(
217 hash.to_hex(),
218 "927edb96f3386ab91b5f5d85d84cb4253c65b1c2f65fa7df25f81fab1d62987a"
219 );
220 assert_eq!(
221 address.to_base58(),
222 "Ae2tdPwUPEZ9vtyppa1FdJzvqJZkEcXgdHxVYAzTWcPaoNycVq5rc36LC1S"
223 );
224 }
225
226 #[test]
227 pub fn parse_test_genesis_files() {
228 let genesis_hash = BlockHeaderHash::from_hex(
229 "c6a004d3d178f600cd8caa10abbebe1549bef878f0665aea2903472d5abf7323",
230 )
231 .unwrap();
232
233 let genesis_data =
234 super::parse_genesis_data(get_test_genesis_data(&genesis_hash).unwrap().as_bytes())
235 .unwrap();
236
237 assert_eq!(genesis_data.epoch_stability_depth, 2160);
238 assert_eq!(
239 genesis_data
240 .start_time
241 .duration_since(SystemTime::UNIX_EPOCH)
242 .unwrap()
243 .as_secs(),
244 1506450213
245 );
246 assert_eq!(genesis_data.slot_duration.as_secs(), 20);
247 assert_eq!(genesis_data.slot_duration.subsec_millis(), 0);
248 assert_eq!(genesis_data.protocol_magic, 633343913.into());
249 assert_eq!(genesis_data.fee_policy.coefficient, 43946 * 1_000_000u64);
250 assert_eq!(genesis_data.fee_policy.constant, 155381 * 1_000_000_000u64);
251
252 assert_eq!(
253 URL_SAFE.encode(
254 genesis_data
255 .avvm_distr
256 .iter()
257 .find(|(_, v)| **v == 9999300000000u64)
258 .unwrap()
259 .0
260 ),
261 "-0BJDi-gauylk4LptQTgjMeo7kY9lTCbZv12vwOSTZk="
262 );
263
264 let genesis_hash = BlockHeaderHash::from_hex(
265 "b7f76950bc4866423538ab7764fc1c7020b24a5f717a5bee3109ff2796567214",
266 )
267 .unwrap();
268
269 let genesis_data =
270 super::parse_genesis_data(get_test_genesis_data(&genesis_hash).unwrap().as_bytes())
271 .unwrap();
272
273 assert_eq!(
274 *genesis_data
275 .non_avvm_balances
276 .iter()
277 .find(|(n, _)| n.to_string()
278 == "2cWKMJemoBaheSTiK9XEtQDf47Z3My8jwN25o5jjm7s7jaXin2nothhWQrTDd8m433M8K")
279 .unwrap()
280 .1,
281 5428571428571429u64
282 );
283 }
284}