Skip to content
Snippets Groups Projects
Commit 60b5a7d6 authored by Cédric Moreau's avatar Cédric Moreau
Browse files

fix(#125): GenesisConfig must be derived from GenesisData (GDev)

parent 10eee6cc
No related branches found
No related tags found
No related merge requests found
Pipeline #33318 failed
This diff is collapsed.
...@@ -14,13 +14,14 @@ ...@@ -14,13 +14,14 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. // along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
use crate::chain_spec::gdev::{get_authority_keys_from_seed, get_env, session_keys, AuthorityKeys};
use crate::chain_spec::{clique_wot, get_account_id_from_seed, NAMES};
use common_runtime::*; use common_runtime::*;
use maplit::btreemap; use maplit::btreemap;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sp_core::crypto::AccountId32; use sp_core::crypto::AccountId32;
use sp_core::{blake2_256, Decode, Encode, H256}; use sp_core::{blake2_256, sr25519, Decode, Encode, H256};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::format;
type MembershipData = sp_membership::MembershipData<u32>; type MembershipData = sp_membership::MembershipData<u32>;
...@@ -61,7 +62,7 @@ struct GenesisConfig<Parameters> { ...@@ -61,7 +62,7 @@ struct GenesisConfig<Parameters> {
#[serde(default)] #[serde(default)]
parameters: Parameters, parameters: Parameters,
#[serde(rename = "smiths")] #[serde(rename = "smiths")]
smith_identities: BTreeMap<String, SmithData>, smith_identities: Vec<SmithData>,
sudo_key: Option<AccountId>, sudo_key: Option<AccountId>,
technical_committee: Vec<String>, technical_committee: Vec<String>,
ud: u64, ud: u64,
...@@ -87,9 +88,8 @@ struct Idty { ...@@ -87,9 +88,8 @@ struct Idty {
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
struct SmithData { struct SmithData {
name: String,
session_keys: Option<String>, session_keys: Option<String>,
#[serde(default)]
certs: Vec<Cert>,
} }
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
...@@ -111,8 +111,9 @@ impl From<Cert> for (String, Option<u32>) { ...@@ -111,8 +111,9 @@ impl From<Cert> for (String, Option<u32>) {
/// takes DUNITER_GENESIS_CONFIG env var if present or duniter-gen-conf.json by default /// takes DUNITER_GENESIS_CONFIG env var if present or duniter-gen-conf.json by default
// this function is targeting dev chainspecs, do not use in production network // this function is targeting dev chainspecs, do not use in production network
pub fn generate_genesis_data<CS, P, SK, F>( pub fn generate_genesis_data<CS, P, SK, F>(
json_file_path: String,
f: F, f: F,
maybe_force_authority: Option<Vec<u8>>, maybe_force_authority: Option<(String, Vec<u8>)>,
) -> Result<CS, String> ) -> Result<CS, String>
where where
P: Default + DeserializeOwned, P: Default + DeserializeOwned,
...@@ -138,7 +139,9 @@ where ...@@ -138,7 +139,9 @@ where
technical_committee, technical_committee,
ud, ud,
// wallets, // wallets,
} = get_genesis_config::<P>()?; } = get_genesis_config::<P>(
std::env::var("DUNITER_GENESIS_CONFIG").unwrap_or_else(|_| json_file_path.to_owned()),
)?;
let GenesisMigrationData { let GenesisMigrationData {
identities, identities,
...@@ -247,16 +250,16 @@ where ...@@ -247,16 +250,16 @@ where
} }
// Verify certifications coherence // Verify certifications coherence
let mut not_enough_certs: Vec<u32> = vec![];
for (idty_index, receiver_certs) in &certs_by_receiver { for (idty_index, receiver_certs) in &certs_by_receiver {
if receiver_certs.len() < genesis_certs_min_received as usize { if receiver_certs.len() < genesis_certs_min_received as usize {
return Err(format!( not_enough_certs.push(*idty_index);
"Identity n°{} has received only {}/{} certifications)",
idty_index,
receiver_certs.len(),
genesis_certs_min_received
));
} }
} }
// Trim these identities
not_enough_certs.into_iter().for_each(|idty_index| {
certs_by_receiver.remove(&idty_index);
});
// SMITHS SUB-WOT // // SMITHS SUB-WOT //
...@@ -265,13 +268,25 @@ where ...@@ -265,13 +268,25 @@ where
let mut session_keys_map = BTreeMap::new(); let mut session_keys_map = BTreeMap::new();
let mut smith_memberships = BTreeMap::new(); let mut smith_memberships = BTreeMap::new();
let mut smith_certs_by_receiver = BTreeMap::new(); let mut smith_certs_by_receiver = BTreeMap::new();
for (idty_name, smith_data) in smith_identities {
// Authorities
let authority_idty_index = maybe_force_authority.clone().map(|(name, _)| {
idty_index_of
.get(&name)
.ok_or(format!("Identity '{}' not exist", name))
.expect("Initial authority must have an identity")
});
for SmithData {
name: idty_name,
session_keys,
} in &smith_identities
{
let idty_index = idty_index_of let idty_index = idty_index_of
.get(&idty_name) .get(idty_name)
.ok_or(format!("Identity '{}' not exist", &idty_name))?; .ok_or(format!("Identity '{}' not exist", idty_name))?;
let identity = identities let identity = identities
.get(&idty_name) .get(idty_name)
.ok_or(format!("Identity '{}' not exist", &idty_name))?; .ok_or(format!("Identity '{}' not exist", idty_name))?;
if identity.balance < EXISTENTIAL_DEPOSIT { if identity.balance < EXISTENTIAL_DEPOSIT {
return Err(format!( return Err(format!(
...@@ -281,11 +296,11 @@ where ...@@ -281,11 +296,11 @@ where
} }
// Initial authorities // Initial authorities
if maybe_force_authority.is_some() { if let Some(authority_idty_index) = authority_idty_index {
if smith_data.session_keys.is_some() { if session_keys.is_some() {
return Err("session_keys field forbidden".to_owned()); return Err("session_keys field forbidden".to_owned());
} }
if *idty_index == 1 { if *idty_index == *authority_idty_index {
// online authority // online authority
initial_authorities.insert(1, (identity.pubkey.clone(), true)); initial_authorities.insert(1, (identity.pubkey.clone(), true));
} else { } else {
...@@ -295,16 +310,17 @@ where ...@@ -295,16 +310,17 @@ where
} else { } else {
initial_authorities.insert( initial_authorities.insert(
*idty_index, *idty_index,
(identity.pubkey.clone(), smith_data.session_keys.is_some()), (identity.pubkey.clone(), session_keys.is_some()),
); );
} }
// Session keys // Session keys
let session_keys_bytes = if let Some(ref session_keys) = smith_data.session_keys { let session_keys_bytes = if let Some(ref session_keys) = session_keys {
online_authorities_counter += 1; online_authorities_counter += 1;
hex::decode(&session_keys[2..]) hex::decode(&session_keys[2..])
.map_err(|_| format!("invalid session keys for idty {}", &idty_name))? .map_err(|_| format!("invalid session keys for idty {}", idty_name))?
} else if let (1, Some(ref session_keys_bytes)) = (*idty_index, &maybe_force_authority) { } else if let (1, Some((_, ref session_keys_bytes))) = (*idty_index, &maybe_force_authority)
{
session_keys_bytes.clone() session_keys_bytes.clone()
} else { } else {
// Create fake session keys (must be unique and deterministic) // Create fake session keys (must be unique and deterministic)
...@@ -316,18 +332,22 @@ where ...@@ -316,18 +332,22 @@ where
//vec![initial_authorities.len() as u8; std::mem::size_of::<SK>()] //vec![initial_authorities.len() as u8; std::mem::size_of::<SK>()]
}; };
let session_keys = SK::decode(&mut &session_keys_bytes[..]) let session_keys = SK::decode(&mut &session_keys_bytes[..])
.map_err(|_| format!("invalid session keys for idty {}", &idty_name))?; .map_err(|_| format!("invalid session keys for idty {}", idty_name))?;
session_keys_map.insert(identity.pubkey.clone(), session_keys); session_keys_map.insert(identity.pubkey.clone(), session_keys);
// Certifications // Certifications
let mut receiver_certs = BTreeMap::new(); let mut receiver_certs = BTreeMap::new();
for cert in &smith_data.certs { // All initial smiths are considered to be certifying all each other
let (issuer, maybe_expire_on) = cert.clone().into(); smith_identities
let issuer_index = idty_index_of .iter()
.get(&issuer) .filter(|s| s.name.to_owned() != *idty_name)
.ok_or(format!("Identity '{}' not exist", issuer))?; .for_each(|other_smith| {
receiver_certs.insert(*issuer_index, maybe_expire_on); let issuer_index = idty_index_of
} .get(&other_smith.name)
.ok_or(format!("Identity '{}' not exist", other_smith.name))
.unwrap();
receiver_certs.insert(*issuer_index, None); // TODO: put duration
});
smith_certs_by_receiver.insert(*idty_index, receiver_certs); smith_certs_by_receiver.insert(*idty_index, receiver_certs);
// Memberships // Memberships
...@@ -382,6 +402,173 @@ where ...@@ -382,6 +402,173 @@ where
Ok(f(genesis_data)) Ok(f(genesis_data))
} }
pub fn generate_genesis_data_for_benchmark_chain<CS, P, SK, F>(
initial_authorities_len: usize,
initial_smiths_len: usize,
initial_identities_len: usize,
root_key: AccountId,
_enable_println: bool,
f: F,
) -> Result<CS, String>
where
P: Default + DeserializeOwned,
SK: Decode,
F: Fn(GenesisData<P, SK>) -> CS,
{
// Same as local chain
generate_genesis_data_for_local_chain(
initial_authorities_len,
initial_smiths_len,
initial_identities_len,
root_key,
_enable_println,
f,
)
}
pub fn generate_genesis_data_for_local_chain<CS, P, SK, F>(
initial_authorities_len: usize,
initial_smiths_len: usize,
initial_identities_len: usize,
root_key: AccountId,
_enable_println: bool,
f: F,
) -> Result<CS, String>
where
P: Default + DeserializeOwned,
SK: Decode,
F: Fn(GenesisData<P, SK>) -> CS,
{
assert!(initial_identities_len <= 6);
assert!(initial_smiths_len <= initial_identities_len);
assert!(initial_authorities_len <= initial_smiths_len);
let babe_epoch_duration = get_env("DUNITER_BABE_EPOCH_DURATION", 30) as u64;
let cert_validity_period = get_env("DUNITER_CERT_VALIDITY_PERIOD", 1_000);
let membership_period = get_env("DUNITER_MEMBERSHIP_PERIOD", 1_000);
let smith_cert_validity_period = get_env("DUNITER_SMITH_CERT_VALIDITY_PERIOD", 1_000);
let smith_membership_period = get_env("DUNITER_SMITH_MEMBERSHIP_PERIOD", 1_000);
let ud_creation_period = get_env("DUNITER_UD_CREATION_PERIOD", 60_000);
let ud_reeval_period = get_env("DUNITER_UD_REEEVAL_PERIOD", 1_200_000);
let ud = 1_000;
let initial_smiths = (0..initial_smiths_len)
.map(|i| get_authority_keys_from_seed(NAMES[i]))
.collect::<Vec<AuthorityKeys>>();
let initial_identities = (0..initial_identities_len)
.map(|i| {
(
IdtyName::from(NAMES[i]),
get_account_id_from_seed::<sr25519::Public>(NAMES[i]),
)
})
.collect::<BTreeMap<IdtyName, AccountId>>();
let mut session_keys_map = BTreeMap::new();
initial_smiths.iter().for_each(|x| {
let session_keys_bytes =
session_keys(x.1.clone(), x.2.clone(), x.3.clone(), x.4.clone()).encode();
let sk = SK::decode(&mut &session_keys_bytes[..])
.map_err(|_| format!("invalid session keys for idty {}", x.0.clone()))
.unwrap();
session_keys_map.insert(x.0.clone(), sk);
});
let identities_ = initial_identities
.iter()
.enumerate()
.map(|(_, (name, owner_key))| {
(
String::from_utf8(name.0.clone()).unwrap(),
owner_key.clone(),
)
})
.collect();
let parameters = serde_json::from_slice::<P>(
format!(
"{{
\"babe_epoch_duration\": {},
\"cert_period\": 15,
\"cert_max_by_issuer\": 10,
\"cert_min_received_cert_to_issue_cert\": 2,
\"cert_validity_period\": {},
\"idty_confirm_period\": 40,
\"idty_creation_period\": 50,
\"membership_period\": {},
\"pending_membership_period\": 500,
\"ud_creation_period\": {},
\"ud_reeval_period\": {},
\"smith_cert_period\": 15,
\"smith_cert_max_by_issuer\": 8,
\"smith_cert_min_received_cert_to_issue_cert\": 2,
\"smith_cert_validity_period\": {},
\"smith_membership_period\": {},
\"smith_pending_membership_period\": 500,
\"smith_wot_first_cert_issuable_on\": 20,
\"smith_wot_min_cert_for_membership\": 2,
\"wot_first_cert_issuable_on\": 20,
\"wot_min_cert_for_create_idty_right\": 2,
\"wot_min_cert_for_membership\": 2
}}",
babe_epoch_duration,
cert_validity_period,
membership_period,
ud_creation_period,
ud_reeval_period,
smith_cert_validity_period,
smith_membership_period
)
.as_bytes(),
)
.map_err(|e| format!("Error parsing json conf: {}", e))?;
let genesis_data = GenesisData {
accounts: initial_identities
.iter()
.enumerate()
.map(|(i, (_, owner_key))| {
(
owner_key.clone(),
GenesisAccountData {
random_id: H256(blake2_256(&(i as u32, owner_key).encode())),
balance: ud,
is_identity: true,
},
)
})
.collect(),
certs_by_receiver: clique_wot(initial_identities.len()),
first_ud: None,
first_ud_reeval: None,
identities: identities_,
initial_authorities: initial_smiths
.iter()
.enumerate()
.map(|(i, keys)| (i as u32 + 1, (keys.0.clone(), i < initial_authorities_len)))
.collect(),
initial_monetary_mass: initial_identities_len as u64 * ud,
memberships: (1..=initial_identities.len())
.map(|i| (i as u32, MembershipData { expire_on: 0 }))
.collect(),
// TODO: remove this P generic parameter thats makes this ugly parsing mandatory
parameters,
session_keys_map,
smith_certs_by_receiver: clique_wot(initial_smiths_len),
smith_memberships: (1..=initial_smiths_len)
.map(|i| (i as u32, MembershipData { expire_on: 0 }))
.collect(),
sudo_key: Some(root_key),
technical_committee_members: initial_smiths
.iter()
.map(|x| x.0.clone())
.collect::<Vec<_>>(),
ud,
};
Ok(f(genesis_data))
}
fn check_parameters_consistency( fn check_parameters_consistency(
wallets: &BTreeMap<AccountId32, u64>, wallets: &BTreeMap<AccountId32, u64>,
first_ud: &Option<u64>, first_ud: &Option<u64>,
...@@ -415,9 +602,9 @@ fn check_parameters_consistency( ...@@ -415,9 +602,9 @@ fn check_parameters_consistency(
Ok(()) Ok(())
} }
fn get_genesis_config<P: Default + DeserializeOwned>() -> Result<GenesisConfig<P>, String> { fn get_genesis_config<P: Default + DeserializeOwned>(
let json_file_path = std::env::var("DUNITER_GENESIS_CONFIG") json_file_path: String,
.unwrap_or_else(|_| "duniter-gen-conf.json".to_owned()); ) -> Result<GenesisConfig<P>, String> {
// We mmap the file into memory first, as this is *a lot* faster than using // We mmap the file into memory first, as this is *a lot* faster than using
// `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160 // `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160
let file = std::fs::File::open(&json_file_path) let file = std::fs::File::open(&json_file_path)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment