Skip to content

Commit

Permalink
Shelley genesis use serde json arbitrary precision (#363)
Browse files Browse the repository at this point in the history
* remove serde_aux and use arbitrary_precision feature for decimals

* handle exponential notation
  • Loading branch information
ecioppettini authored Oct 1, 2024
1 parent b7acbd3 commit c6a6d11
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 33 deletions.
3 changes: 1 addition & 2 deletions chain/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ cbor_event = "2.2.0"
linked-hash-map = "0.5.3"
derivative = "2.2.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.57"
serde_json = { version = "1.0.57", features = ["arbitrary_precision"] }
schemars = "0.8.8"

bech32 = "0.7.2"
Expand All @@ -38,7 +38,6 @@ num-integer = "0.1.45"
thiserror = "1.0.37"
num = "0.4"
unicode-segmentation = "1.10.1"
serde-aux = "4.5.0"
chrono = "0.4.38"

# non-wasm
Expand Down
36 changes: 25 additions & 11 deletions chain/rust/src/genesis/shelley/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use cml_core::DeserializeError;
use cml_crypto::{
chain_crypto::Blake2b256, Ed25519KeyHash, PoolMetadataHash, TransactionHash, VRFKeyHash,
};
use num::traits::Pow as _;
use serde_json;
use std::collections::BTreeMap;
use std::io::Read;
Expand Down Expand Up @@ -36,8 +37,7 @@ pub enum GenesisJSONError {
pub fn parse_genesis_data<R: Read>(
json: R,
) -> Result<config::ShelleyGenesisData, GenesisJSONError> {
let data_value: serde_json::Value = serde_json::from_reader(json)?;
let data: raw::ShelleyGenesisData = serde_json::from_value(data_value)?;
let data: raw::ShelleyGenesisData = serde_json::from_reader(json)?;

let mut initial_funds = BTreeMap::new();
for (addr_hex, balance) in &data.initialFunds {
Expand All @@ -55,7 +55,7 @@ pub fn parse_genesis_data<R: Read>(
// 1) Get stake pools
let mut pools: BTreeMap<Ed25519KeyHash, PoolParams> = BTreeMap::new();
for (pool_id, params) in &raw.pools {
let ration = fraction::Fraction::from_str(&params.margin).unwrap();
let ration = json_number_to_fraction(&params.margin);
let mut owners = Vec::<Ed25519KeyHash>::new();
for owner in &params.owners {
owners.push(Ed25519KeyHash::from_hex(owner)?);
Expand Down Expand Up @@ -136,7 +136,7 @@ pub fn parse_genesis_data<R: Read>(
);
}
Ok(config::ShelleyGenesisData {
active_slots_coeff: fraction::Fraction::from_str(&data.activeSlotsCoeff).unwrap(),
active_slots_coeff: json_number_to_fraction(&data.activeSlotsCoeff),
epoch_length: data.epochLength,
gen_delegs,
initial_funds,
Expand All @@ -145,11 +145,10 @@ pub fn parse_genesis_data<R: Read>(
network_id,
network_magic: data.networkMagic,
protocol_params: config::ShelleyGenesisProtocolParameters {
a0: fraction::Fraction::from_str(&data.protocolParams.a0).unwrap(),
decentralisation_param: fraction::Fraction::from_str(
a0: json_number_to_fraction(&data.protocolParams.a0),
decentralisation_param: json_number_to_fraction(
&data.protocolParams.decentralisationParam,
)
.unwrap(),
),
e_max: data.protocolParams.eMax,
extra_entropy: config::ShelleyGenesisExtraEntropy {
tag: data.protocolParams.extraEntropy.tag,
Expand All @@ -168,18 +167,33 @@ pub fn parse_genesis_data<R: Read>(
data.protocolParams.protocolVersion.major,
data.protocolParams.protocolVersion.minor,
),
rho: fraction::Fraction::from_str(&data.protocolParams.rho).unwrap(),
tau: fraction::Fraction::from_str(&data.protocolParams.tau).unwrap(),
rho: json_number_to_fraction(&data.protocolParams.rho),
tau: json_number_to_fraction(&data.protocolParams.tau),
},
security_param: data.securityParam,
slot_length: fraction::Fraction::from_str(&data.slotLength).unwrap(),
slot_length: json_number_to_fraction(&data.slotLength),
slots_per_kes_period: data.slotsPerKESPeriod,
staking,
system_start: data.systemStart.parse().expect("Failed to parse date"),
update_quorum: data.updateQuorum,
})
}

fn json_number_to_fraction(param: &serde_json::Number) -> fraction::GenericFraction<u64> {
let s = param.to_string();

if let Some(exp_position) = s.find('e').or_else(|| s.find('E')) {
let (a, b) = s.split_at_checked(exp_position).unwrap();

let exp = fraction::Ratio::from(10u64).pow(i32::from_str(&b[1..]).unwrap());

fraction::Fraction::from_str(a).unwrap()
* fraction::Fraction::new(*exp.numer(), *exp.denom())
} else {
fraction::Fraction::from_str(&param.to_string()).unwrap()
}
}

pub fn redeem_address_to_txid(pubkey: &Address) -> TransactionHash {
let txid = Blake2b256::new(&pubkey.to_raw_bytes());
TransactionHash::from(*txid.as_hash_bytes())
Expand Down
32 changes: 12 additions & 20 deletions chain/rust/src/genesis/shelley/raw.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::assets::Coin;
use serde::{Deserialize, Serialize};
use serde_aux::prelude::*;
use std::collections::HashMap;

/// Parsing of the JSON representation of the Shelley genesis block
Expand All @@ -11,8 +10,7 @@ use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug)]
pub struct ShelleyGenesisData {
// convert lossless JSON floats to string to avoid lossy Rust f64
#[serde(deserialize_with = "deserialize_string_from_number")]
pub activeSlotsCoeff: String,
pub activeSlotsCoeff: serde_json::Number,
pub epochLength: u64,
pub genDelegs: HashMap<String, ShelleyGenesisDelegations>,
pub initialFunds: HashMap<String, Coin>,
Expand All @@ -22,8 +20,7 @@ pub struct ShelleyGenesisData {
pub networkMagic: u64,
pub protocolParams: ShelleyGenesisProtocolParameters,
pub securityParam: u64,
#[serde(deserialize_with = "deserialize_string_from_number")]
pub slotLength: String,
pub slotLength: serde_json::Number,
pub slotsPerKESPeriod: u64,
pub staking: Option<ShelleyGenesisStaking>,
pub systemStart: String,
Expand All @@ -40,12 +37,10 @@ pub struct ShelleyGenesisDelegations {
#[allow(non_snake_case)]
#[derive(Serialize, Deserialize, Debug)]
pub struct ShelleyGenesisProtocolParameters {
// convert lossless JSON floats to string to avoid lossy Rust f64
#[serde(deserialize_with = "deserialize_string_from_number")]
pub a0: String,
// convert lossless JSON floats to string to avoid lossy Rust f64
#[serde(deserialize_with = "deserialize_string_from_number")]
pub decentralisationParam: String,
// this uses the serde_json arbitrary_precision feature to avoid lossy Rust f64
pub a0: serde_json::Number,
// this uses the serde_json arbitrary_precision feature to avoid lossy Rust f64
pub decentralisationParam: serde_json::Number,
pub eMax: u64,
pub extraEntropy: ShelleyGenesisExtraEntropy,
pub keyDeposit: Coin,
Expand All @@ -59,12 +54,10 @@ pub struct ShelleyGenesisProtocolParameters {
pub nOpt: u64,
pub poolDeposit: Coin,
pub protocolVersion: ShelleyGenesisProtocolVersion,
// convert lossless JSON floats to string to avoid lossy Rust f64
#[serde(deserialize_with = "deserialize_string_from_number")]
pub rho: String,
// convert lossless JSON floats to string to avoid lossy Rust f64
#[serde(deserialize_with = "deserialize_string_from_number")]
pub tau: String,
// this uses the serde_json arbitrary_precision feature to avoid lossy Rust f64
pub rho: serde_json::Number,
// this uses the serde_json arbitrary_precision feature to avoid lossy Rust f64
pub tau: serde_json::Number,
}

#[allow(non_snake_case)]
Expand All @@ -91,9 +84,8 @@ pub struct ShelleyGenesisStaking {
#[derive(Serialize, Deserialize, Debug)]
pub struct ShelleyGenesisPool {
pub cost: Coin,
// convert lossless JSON floats to string to avoid lossy Rust f64
#[serde(deserialize_with = "deserialize_string_from_number")]
pub margin: String,
// this uses the serde_json arbitrary_precision feature to avoid lossy Rust f64
pub margin: serde_json::Number,
pub metadata: Option<ShelleyGenesisPoolMetadata>,
pub owners: Vec<String>,
pub pledge: Coin,
Expand Down

0 comments on commit c6a6d11

Please sign in to comment.