radix_engine/updates/
babylon.rs

1use super::*;
2use crate::internal_prelude::*;
3use crate::system::bootstrap::*;
4
5#[derive(Debug, Clone, ScryptoSbor)]
6pub struct BabylonSettings {
7    pub genesis_data_chunks: Vec<GenesisDataChunk>,
8    pub genesis_epoch: Epoch,
9    pub consensus_manager_config: ConsensusManagerConfig,
10    pub initial_time_ms: i64,
11    pub initial_current_leader: Option<ValidatorIndex>,
12    pub faucet_supply: Decimal,
13}
14
15impl BabylonSettings {
16    /// Note - this is traditionally the basic version used for tests, but it fails
17    /// to execute any round changes due to a validator error.
18    ///
19    /// So instead, we have changed to using test_default
20    pub fn test_minimal() -> Self {
21        Self {
22            genesis_data_chunks: vec![],
23            genesis_epoch: Epoch::of(1),
24            consensus_manager_config: ConsensusManagerConfig::test_default(),
25            initial_time_ms: 1,
26            initial_current_leader: Some(0),
27            faucet_supply: *DEFAULT_TESTING_FAUCET_SUPPLY,
28        }
29    }
30
31    pub fn test_mainnet() -> Self {
32        let pub_key = Secp256k1PrivateKey::from_u64(1u64).unwrap().public_key();
33        let genesis_epoch = Epoch::of(1);
34        let consensus_manager_config = ConsensusManagerConfig::mainnet_genesis();
35        Self::single_validator_and_staker(
36            pub_key,
37            Decimal::one(),
38            Decimal::zero(),
39            ComponentAddress::preallocated_account_from_public_key(&pub_key),
40            genesis_epoch,
41            consensus_manager_config,
42        )
43    }
44
45    pub fn test_default() -> Self {
46        let pub_key = Secp256k1PrivateKey::from_u64(1u64).unwrap().public_key();
47        let genesis_epoch = Epoch::of(1);
48        let consensus_manager_config = ConsensusManagerConfig::test_default();
49        Self::single_validator_and_staker(
50            pub_key,
51            Decimal::one(),
52            Decimal::zero(),
53            ComponentAddress::preallocated_account_from_public_key(&pub_key),
54            genesis_epoch,
55            consensus_manager_config,
56        )
57    }
58
59    pub fn single_validator_and_staker(
60        validator_public_key: Secp256k1PublicKey,
61        stake_xrd_amount: Decimal,
62        staker_account_xrd_amount: Decimal,
63        staker_account: ComponentAddress,
64        genesis_epoch: Epoch,
65        consensus_manager_config: ConsensusManagerConfig,
66    ) -> Self {
67        Self::validators_and_single_staker(
68            vec![(validator_public_key, stake_xrd_amount)],
69            staker_account,
70            staker_account_xrd_amount,
71            genesis_epoch,
72            consensus_manager_config,
73        )
74    }
75
76    pub fn validators_and_single_staker(
77        validators_and_stakes: Vec<(Secp256k1PublicKey, Decimal)>,
78        staker_account: ComponentAddress,
79        staker_account_xrd_amount: Decimal,
80        genesis_epoch: Epoch,
81        consensus_manager_config: ConsensusManagerConfig,
82    ) -> Self {
83        let genesis_validators: Vec<GenesisValidator> = validators_and_stakes
84            .iter()
85            .map(|(key, _)| key.clone().into())
86            .collect();
87        let stake_allocations: Vec<(Secp256k1PublicKey, Vec<GenesisStakeAllocation>)> =
88            validators_and_stakes
89                .into_iter()
90                .map(|(key, stake_xrd_amount)| {
91                    (
92                        key,
93                        vec![GenesisStakeAllocation {
94                            account_index: 0,
95                            xrd_amount: stake_xrd_amount,
96                        }],
97                    )
98                })
99                .collect();
100        let genesis_data_chunks = vec![
101            GenesisDataChunk::Validators(genesis_validators),
102            GenesisDataChunk::Stakes {
103                accounts: vec![staker_account],
104                allocations: stake_allocations,
105            },
106            GenesisDataChunk::ResourceBalances {
107                accounts: vec![staker_account],
108                allocations: vec![(
109                    XRD,
110                    vec![GenesisResourceAllocation {
111                        account_index: 0u32,
112                        amount: staker_account_xrd_amount,
113                    }],
114                )],
115            },
116        ];
117        Self {
118            genesis_data_chunks,
119            genesis_epoch,
120            consensus_manager_config,
121            initial_time_ms: 0,
122            initial_current_leader: Some(0),
123            faucet_supply: *DEFAULT_TESTING_FAUCET_SUPPLY,
124        }
125    }
126
127    pub fn test_complex() -> Self {
128        let validator_key = Secp256k1PublicKey([0; 33]);
129        let staker_address = ComponentAddress::preallocated_account_from_public_key(
130            &Secp256k1PrivateKey::from_u64(1).unwrap().public_key(),
131        );
132        let token_holder = ComponentAddress::preallocated_account_from_public_key(
133            &PublicKey::Secp256k1(Secp256k1PrivateKey::from_u64(1).unwrap().public_key()),
134        );
135        let resource_address = ResourceAddress::new_or_panic(
136            NodeId::new(
137                EntityType::GlobalFungibleResourceManager as u8,
138                &hash(vec![1, 2, 3]).lower_bytes(),
139            )
140            .0,
141        );
142        let stake = GenesisStakeAllocation {
143            account_index: 0,
144            xrd_amount: Decimal::one(),
145        };
146        let mut xrd_balances = Vec::new();
147        let mut pub_key_accounts = Vec::new();
148
149        for i in 0..20 {
150            let pub_key = Secp256k1PrivateKey::from_u64((i + 1).try_into().unwrap())
151                .unwrap()
152                .public_key();
153            let account_address = ComponentAddress::preallocated_account_from_public_key(&pub_key);
154            pub_key_accounts.push((pub_key, account_address));
155            xrd_balances.push((account_address, dec!("10")));
156        }
157        let genesis_resource = GenesisResource {
158            reserved_resource_address: resource_address,
159            metadata: vec![(
160                "symbol".to_string(),
161                MetadataValue::String("TST".to_string()),
162            )],
163            owner: None,
164        };
165        let resource_allocation = GenesisResourceAllocation {
166            account_index: 0,
167            amount: dec!("10"),
168        };
169        let genesis_data_chunks = vec![
170            GenesisDataChunk::Validators(vec![validator_key.clone().into()]),
171            GenesisDataChunk::Stakes {
172                accounts: vec![staker_address],
173                allocations: vec![(validator_key, vec![stake])],
174            },
175            GenesisDataChunk::XrdBalances(xrd_balances),
176            GenesisDataChunk::Resources(vec![genesis_resource]),
177            GenesisDataChunk::ResourceBalances {
178                accounts: vec![token_holder.clone()],
179                allocations: vec![(resource_address.clone(), vec![resource_allocation])],
180            },
181        ];
182        Self {
183            genesis_data_chunks,
184            genesis_epoch: Epoch::of(1),
185            consensus_manager_config: ConsensusManagerConfig::mainnet_genesis(),
186            initial_time_ms: 1,
187            initial_current_leader: Some(0),
188            faucet_supply: Decimal::zero(),
189        }
190    }
191
192    pub fn with_faucet_supply(mut self, faucet_supply: Decimal) -> Self {
193        self.faucet_supply = faucet_supply;
194        self
195    }
196
197    pub fn with_genesis_epoch(mut self, genesis_epoch: Epoch) -> Self {
198        self.genesis_epoch = genesis_epoch;
199        self
200    }
201
202    pub fn with_consensus_manager_config(
203        mut self,
204        consensus_manager_config: ConsensusManagerConfig,
205    ) -> Self {
206        self.consensus_manager_config = consensus_manager_config;
207        self
208    }
209}
210
211impl UpdateSettings for BabylonSettings {
212    type UpdateGenerator = BabylonGenerator;
213
214    fn protocol_version() -> ProtocolVersion {
215        ProtocolVersion::Babylon
216    }
217
218    fn all_enabled_as_default_for_network(_network: &NetworkDefinition) -> Self {
219        Self::test_default()
220    }
221
222    fn all_disabled() -> Self {
223        Self::test_default()
224    }
225
226    fn create_generator(&self) -> Self::UpdateGenerator {
227        Self::UpdateGenerator {
228            settings: self.clone(),
229        }
230    }
231}
232
233pub struct BabylonGenerator {
234    settings: BabylonSettings,
235}
236
237impl ProtocolUpdateGenerator for BabylonGenerator {
238    fn insert_status_tracking_flash_transactions(&self) -> bool {
239        // This was launched without status tracking, so we can't add it in later to avoid divergence
240        false
241    }
242
243    fn batch_groups(&self) -> Vec<Box<dyn ProtocolUpdateBatchGroupGenerator + '_>> {
244        let bootstrap = FixedBatchGroupGenerator::named("bootstrap")
245            .add_batch("flash", |_| {
246                ProtocolUpdateBatch::single(ProtocolUpdateTransaction::flash(
247                    "flash",
248                    create_system_bootstrap_flash_state_updates(),
249                ))
250            })
251            .add_batch("bootstrap", |_| {
252                ProtocolUpdateBatch::single(ProtocolUpdateTransaction::genesis_transaction(
253                    "bootstrap",
254                    create_system_bootstrap_transaction(
255                        self.settings.genesis_epoch,
256                        self.settings.consensus_manager_config.clone(),
257                        self.settings.initial_time_ms,
258                        self.settings.initial_current_leader,
259                        self.settings.faucet_supply,
260                    ),
261                ))
262            });
263
264        let mut chunks = FixedBatchGroupGenerator::named("chunks");
265        for (chunk_index, chunk) in self.settings.genesis_data_chunks.iter().enumerate() {
266            let chunk_name = match chunk {
267                GenesisDataChunk::Validators { .. } => "validators",
268                GenesisDataChunk::Stakes { .. } => "stakes",
269                GenesisDataChunk::Resources { .. } => "resources",
270                GenesisDataChunk::ResourceBalances { .. } => "resource-balances",
271                GenesisDataChunk::XrdBalances { .. } => "xrd-balances",
272            };
273            chunks = chunks.add_batch(chunk_name, move |_| {
274                ProtocolUpdateBatch::single(ProtocolUpdateTransaction::genesis_transaction(
275                    &format!("chunk-{chunk_index:04}"),
276                    create_genesis_data_ingestion_transaction(chunk.clone(), chunk_index),
277                ))
278            });
279        }
280
281        let wrap_up = FixedBatchGroupGenerator::named("wrap-up").add_batch("wrap-up", |_| {
282            ProtocolUpdateBatch::single(ProtocolUpdateTransaction::genesis_transaction(
283                "wrap-up",
284                create_genesis_wrap_up_transaction(),
285            ))
286        });
287
288        vec![bootstrap.build(), chunks.build(), wrap_up.build()]
289    }
290}