Skip to main content

zombienet_orchestrator/generators/
session_0_overrides.rs

1use array_bytes::bytes2hex;
2use codec::{Decode, Encode};
3use serde_json::json;
4use sp_core::crypto::AccountId32;
5use support::substorage::storage_value_key;
6
7use crate::generators::errors::GeneratorError;
8
9// Extracted and simplified from polkadot-sdk
10
11/// Index of the validator is used as a lightweight replacement of the `ValidatorId` when
12/// appropriate.
13#[derive(PartialEq, Clone, Encode, Decode, Debug)]
14pub struct ValidatorIndex(pub u32);
15
16/// Simple index type with which we can count sessions.
17pub type SessionIndex = u32;
18
19/// The unique (during session) index of a validator group.
20#[derive(Encode, Decode, Default, Clone, Debug, PartialEq)]
21pub struct GroupIndex(pub u32);
22
23#[derive(Clone, Encode, Decode, Debug, PartialEq)]
24pub struct SessionInfo {
25    /// **** New in v2 ******
26    /// All the validators actively participating in parachain consensus.
27    /// Indices are into the broader validator set.
28    pub active_validator_indices: Vec<ValidatorIndex>,
29    /// A secure random seed for the session, gathered from BABE.
30    pub random_seed: [u8; 32],
31    /// The amount of sessions to keep for disputes.
32    pub dispute_period: SessionIndex,
33
34    /// **** Old fields *****
35    /// Validators in canonical ordering.
36    ///
37    /// NOTE: There might be more authorities in the current session, than `validators`
38    /// participating in parachain consensus. See
39    /// [`max_validators`](https://github.com/paritytech/polkadot/blob/a52dca2be7840b23c19c153cf7e110b1e3e475f8/runtime/parachains/src/configuration.rs#L148).
40    ///
41    /// `SessionInfo::validators` will be limited to `max_validators` when set.
42    pub validators: Vec<AccountId32>,
43    /// Validators' authority discovery keys for the session in canonical ordering.
44    ///
45    /// NOTE: The first `validators.len()` entries will match the corresponding validators in
46    /// `validators`, afterwards any remaining authorities can be found. This is any authorities
47    /// not participating in parachain consensus - see
48    /// [`max_validators`](https://github.com/paritytech/polkadot/blob/a52dca2be7840b23c19c153cf7e110b1e3e475f8/runtime/parachains/src/configuration.rs#L148)
49    pub discovery_keys: Vec<AccountId32>,
50    /// The assignment keys for validators.
51    ///
52    /// NOTE: There might be more authorities in the current session, than validators participating
53    /// in parachain consensus. See
54    /// [`max_validators`](https://github.com/paritytech/polkadot/blob/a52dca2be7840b23c19c153cf7e110b1e3e475f8/runtime/parachains/src/configuration.rs#L148).
55    pub assignment_keys: Vec<AccountId32>,
56    /// Validators in shuffled ordering - these are the validator groups as produced
57    /// by the `Scheduler` module for the session and are typically referred to by
58    /// `GroupIndex`.
59    pub validator_groups: Vec<Vec<ValidatorIndex>>,
60    /// The number of availability cores used by the protocol during this session.
61    pub n_cores: u32,
62    /// The zeroth delay tranche width.
63    pub zeroth_delay_tranche_width: u32,
64    /// The number of samples we do of `relay_vrf_modulo`.
65    pub relay_vrf_modulo_samples: u32,
66    /// The number of delay tranches in total.
67    pub n_delay_tranches: u32,
68    /// How many slots (BABE / SASSAFRAS) must pass before an assignment is considered a
69    /// no-show.
70    pub no_show_slots: u32,
71    /// The number of validators needed to approve a block.
72    pub needed_approvals: u32,
73}
74
75pub fn generate_session_0_overrides(
76    raw_spec: &serde_json::Value,
77    num_genesis_cores: u32,
78) -> Result<serde_json::Value, GeneratorError> {
79    let mut overrides = json!({});
80    // get current session 0
81    let sessions_prefix = storage_value_key(&b"ParaSessionInfo"[..], b"Sessions");
82    let session_0_key = format!(
83        "{}{}",
84        bytes2hex("0x", &sessions_prefix),
85        bytes2hex("", 0_u32.encode())
86    );
87
88    let current_value = &raw_spec["genesis"]["raw"]["top"][&session_0_key];
89    let Some(current_value_inner) = current_value.as_str() else {
90        return Err(GeneratorError::OverridingRawSpec(format!(
91            "Session_0 keys {} is missing (in genesis.raw.top)",
92            session_0_key
93        )));
94    };
95
96    let encoded = hex::decode(&current_value_inner[2..]).map_err(|e| {
97        GeneratorError::EncodeDecodeError(format!(
98            "Error decoding hex: {}, err: {e}",
99            current_value_inner
100        ))
101    })?;
102    let mut session: SessionInfo = SessionInfo::decode(&mut encoded.as_slice()).map_err(|e| {
103        GeneratorError::EncodeDecodeError(format!("Error decoding scale: {:?}, err: {e}", encoded))
104    })?;
105
106    // clone keys
107    session.assignment_keys = session.validators.clone();
108    session.discovery_keys = session.validators.clone();
109
110    // generate validator groups
111
112    // some checks first
113    if num_genesis_cores >= session.validators.len() as u32 {
114        return Err(GeneratorError::InvariantError(format!("Num cores in genesis {num_genesis_cores} should be less than the num of validators ({})", session.validators.len())));
115    }
116
117    let groups = genetate_groups(session.validators.len() as u32, num_genesis_cores);
118    session.validator_groups = groups.clone();
119    session.n_cores = num_genesis_cores;
120
121    // done with session
122    let session_0_value = bytes2hex("0x", session.encode());
123    overrides[session_0_key] = json!(session_0_value);
124
125    // paraScheduler.validatorGroups: Vec<Vec<u32>>
126    let para_scheduler_validator_groups_key = bytes2hex(
127        "0x",
128        storage_value_key(&b"ParaScheduler"[..], b"ValidatorGroups"),
129    );
130
131    overrides[para_scheduler_validator_groups_key] = json!(bytes2hex("0x", groups.encode()));
132
133    Ok(overrides)
134}
135
136fn genetate_groups(num_validators: u32, num_cores: u32) -> Vec<Vec<ValidatorIndex>> {
137    let iter = std::iter::repeat(vec![]).take(num_cores as usize);
138    let mut groups: Vec<Vec<ValidatorIndex>> = Vec::from_iter(iter);
139    for i in 0..num_validators {
140        let index = i % num_cores;
141        let group = groups.get_mut(index as usize).expect(&format!(
142            "Group index {index} should be part of groups. qed"
143        ));
144        group.push(ValidatorIndex(i));
145    }
146
147    groups
148}
149
150#[cfg(test)]
151mod test {
152    use tracing::debug;
153
154    use super::*;
155
156    #[test]
157    fn decode_encode_should_work() {
158        use support::substorage::storage_value_key;
159
160        let k = storage_value_key(&b"ParaSessionInfo"[..], b"Sessions");
161        debug!("k: {}{}", bytes2hex("", &k), bytes2hex("", 0_u32.encode()));
162
163        let encoded = hex::decode( "1003000000010000000000000002000000abc3f086f5ac20eaab792c75933b2e196307835a61a955be82aa63bc0ff9617a06000000108eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20000000000000000000000000000000010000000100000000000000").unwrap();
164        let mut session: SessionInfo = SessionInfo::decode(&mut encoded.as_slice()).unwrap();
165
166        debug!("{session:?}");
167
168        session.assignment_keys = session.validators.clone();
169        session.discovery_keys = session.validators.clone();
170
171        let encoded = session.encode();
172        debug!("{}", bytes2hex("", &encoded));
173
174        let session_modified = SessionInfo::decode(&mut &encoded[..]).unwrap();
175
176        debug!("{session_modified:?}");
177    }
178
179    #[test]
180    fn val_groups() {
181        let num_cores = 3_u32;
182        let validators = ["abc", "cds", "qwe", "eds"];
183        let groups = genetate_groups(validators.len() as u32, num_cores);
184
185        debug!("{:?}", groups);
186        assert_eq!(groups.len(), num_cores as usize);
187    }
188
189    #[test]
190    fn generate_should_work() {
191        let sessions_prefix = storage_value_key(&b"ParaSessionInfo"[..], b"Sessions");
192        let session_0_key = format!(
193            "{}{}",
194            bytes2hex("0x", &sessions_prefix),
195            bytes2hex("", 0_u32.encode())
196        );
197
198        let session_value = "0x1003000000010000000000000002000000abc3f086f5ac20eaab792c75933b2e196307835a61a955be82aa63bc0ff9617a06000000108eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20000000000000000000000000000000010000000100000000000000";
199        let mock_spec = json!({
200            "genesis": {
201                "raw": {
202                    "top": {
203                        session_0_key: session_value
204                    }
205                }
206            }
207        });
208
209        debug!("mock {:?}", mock_spec);
210
211        let overrides = generate_session_0_overrides(&mock_spec, 3).unwrap();
212        debug!("{:?}", overrides);
213    }
214}