linera_core/
genesis_config.rs1use linera_base::{
6 crypto::{AccountPublicKey, BcsSignable, CryptoHash},
7 data_types::{
8 Amount, Blob, ChainDescription, ChainOrigin, Epoch, InitialChainConfig, NetworkDescription,
9 Timestamp,
10 },
11 identifiers::ChainId,
12 ownership::ChainOwnership,
13};
14use linera_execution::committee::Committee;
15use linera_storage::Storage;
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, thiserror::Error)]
19pub enum Error {
20 #[error("I/O error: {0}")]
21 IoError(#[from] std::io::Error),
22 #[error("chain error: {0}")]
23 Chain(#[from] linera_chain::ChainError),
24 #[error("storage is already initialized: {0:?}")]
25 StorageIsAlreadyInitialized(Box<NetworkDescription>),
26 #[error("no admin chain configured")]
27 NoAdminChain,
28}
29
30fn make_chain(
31 index: u32,
32 public_key: AccountPublicKey,
33 balance: Amount,
34 timestamp: Timestamp,
35) -> ChainDescription {
36 let origin = ChainOrigin::Root(index);
37 let config = InitialChainConfig {
38 application_permissions: Default::default(),
39 balance,
40 min_active_epoch: Epoch::ZERO,
41 max_active_epoch: Epoch::ZERO,
42 epoch: Epoch::ZERO,
43 ownership: ChainOwnership::single(public_key.into()),
44 };
45 ChainDescription::new(origin, config, timestamp)
46}
47
48#[derive(Clone, Debug, Serialize, Deserialize)]
49pub struct GenesisConfig {
50 pub committee: Committee,
51 pub timestamp: Timestamp,
52 pub chains: Vec<ChainDescription>,
53 pub network_name: String,
54}
55
56impl BcsSignable<'_> for GenesisConfig {}
57
58impl GenesisConfig {
59 pub fn new(
61 committee: Committee,
62 timestamp: Timestamp,
63 network_name: String,
64 admin_public_key: AccountPublicKey,
65 admin_balance: Amount,
66 ) -> Self {
67 let admin_chain = make_chain(0, admin_public_key, admin_balance, timestamp);
68 Self {
69 committee,
70 timestamp,
71 chains: vec![admin_chain],
72 network_name,
73 }
74 }
75
76 pub fn add_root_chain(
77 &mut self,
78 public_key: AccountPublicKey,
79 balance: Amount,
80 ) -> ChainDescription {
81 let description = make_chain(
82 self.chains.len() as u32,
83 public_key,
84 balance,
85 self.timestamp,
86 );
87 self.chains.push(description.clone());
88 description
89 }
90
91 pub fn admin_chain_description(&self) -> &ChainDescription {
92 &self.chains[0]
93 }
94
95 pub fn admin_chain_id(&self) -> ChainId {
96 self.admin_chain_description().id()
97 }
98
99 pub async fn initialize_storage<S>(&self, storage: &mut S) -> Result<(), Error>
100 where
101 S: Storage + Clone + 'static,
102 {
103 if let Some(description) = storage
104 .read_network_description()
105 .await
106 .map_err(linera_chain::ChainError::from)?
107 {
108 if description != self.network_description() {
109 tracing::error!(
110 current_network=?description,
111 new_network=?self.network_description(),
112 "storage already initialized"
113 );
114 return Err(Error::StorageIsAlreadyInitialized(Box::new(description)));
115 }
116 tracing::debug!(?description, "storage already initialized");
117 return Ok(());
118 }
119 let network_description = self.network_description();
120 storage
121 .write_blob(&self.committee_blob())
122 .await
123 .map_err(linera_chain::ChainError::from)?;
124 storage
125 .write_network_description(&network_description)
126 .await
127 .map_err(linera_chain::ChainError::from)?;
128 for description in &self.chains {
129 storage.create_chain(description.clone()).await?;
130 }
131 Ok(())
132 }
133
134 pub fn hash(&self) -> CryptoHash {
135 CryptoHash::new(self)
136 }
137
138 pub fn committee_blob(&self) -> Blob {
139 Blob::new_committee(
140 bcs::to_bytes(&self.committee).expect("serializing a committee should succeed"),
141 )
142 }
143
144 pub fn network_description(&self) -> NetworkDescription {
145 NetworkDescription {
146 name: self.network_name.clone(),
147 genesis_config_hash: CryptoHash::new(self),
148 genesis_timestamp: self.timestamp,
149 genesis_committee_blob_hash: self.committee_blob().id().hash,
150 admin_chain_id: self.admin_chain_id(),
151 }
152 }
153
154 #[cfg(with_testing)]
156 pub fn new_for_testing<B: crate::test_utils::StorageBuilder>(
157 builder: &crate::test_utils::TestBuilder<B>,
158 ) -> Self {
159 let mut genesis_chains = builder.genesis_chains().into_iter();
160 let (admin_public_key, admin_balance) = genesis_chains
161 .next()
162 .expect("should have at least one chain");
163 let mut genesis_config = Self::new(
164 builder.initial_committee.clone(),
165 Timestamp::from(0),
166 "test network".to_string(),
167 admin_public_key,
168 admin_balance,
169 );
170 for (public_key, amount) in genesis_chains {
171 genesis_config.add_root_chain(public_key, amount);
172 }
173 genesis_config
174 }
175}