diem_types/on_chain_config/
mod.rs1use crate::{
9 access_path::AccessPath,
10 account_address::AccountAddress,
11 account_config::CORE_CODE_ADDRESS,
12 event::{EventHandle, EventKey},
13};
14use anyhow::{format_err, Result};
15use move_core_types::{
16 identifier::Identifier,
17 language_storage::{StructTag, TypeTag},
18 move_resource::MoveResource,
19};
20use serde::{de::DeserializeOwned, Deserialize, Serialize};
21use std::{collections::HashMap, fmt, sync::Arc};
22
23mod diem_version;
24mod registered_currencies;
25mod validator_set;
26mod vm_config;
27mod vm_publishing_option;
28
29pub use self::{
30 diem_version::{DiemVersion, DIEM_MAX_KNOWN_VERSION, DIEM_VERSION_2},
31 registered_currencies::RegisteredCurrencies,
32 validator_set::{NextValidatorSetProposal, ValidatorSet},
33 vm_config::VMConfig,
34 vm_publishing_option::VMPublishingOption,
35};
36
37#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
42pub struct ConfigID(&'static str, &'static str);
43
44const CONFIG_ADDRESS_STR: &str = "0xA550C18";
45
46pub fn config_address() -> AccountAddress {
47 AccountAddress::from_hex_literal(CONFIG_ADDRESS_STR)
48 .expect("failed to get address")
49}
50
51impl ConfigID {
52 pub fn access_path(self) -> AccessPath {
53 access_path_for_config(
54 AccountAddress::from_hex_literal(self.0)
55 .expect("failed to get address"),
56 Identifier::new(self.1).expect("failed to get Identifier"),
57 )
58 }
59}
60
61impl fmt::Display for ConfigID {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 write!(
64 f,
65 "OnChain config ID [address: {}, identifier: {}]",
66 self.0, self.1
67 )
68 }
69}
70
71pub const ON_CHAIN_CONFIG_REGISTRY: &[ConfigID] = &[
74 ValidatorSet::CONFIG_ID,
78 ];
80
81#[derive(Clone, Debug, PartialEq)]
82pub struct OnChainConfigPayload {
83 epoch: u64,
84 configs: Arc<HashMap<ConfigID, Vec<u8>>>,
85}
86
87impl OnChainConfigPayload {
88 pub fn new(epoch: u64, configs: Arc<HashMap<ConfigID, Vec<u8>>>) -> Self {
89 Self { epoch, configs }
90 }
91
92 pub fn epoch(&self) -> u64 { self.epoch }
93
94 pub fn get<T: OnChainConfig>(&self) -> Result<T> {
95 let bytes = self.configs.get(&T::CONFIG_ID).ok_or_else(|| {
96 format_err!("[on-chain cfg] config not in payload")
97 })?;
98 T::deserialize_into_config(bytes)
99 }
100
101 pub fn configs(&self) -> &HashMap<ConfigID, Vec<u8>> { &self.configs }
102}
103
104impl fmt::Display for OnChainConfigPayload {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 let mut config_ids = "".to_string();
107 for id in self.configs.keys() {
108 config_ids += &id.to_string();
109 }
110 write!(
111 f,
112 "OnChainConfigPayload [epoch: {}, configs: {}]",
113 self.epoch, config_ids
114 )
115 }
116}
117
118pub trait ConfigStorage {
121 fn fetch_config(&self, access_path: AccessPath) -> Option<Vec<u8>>;
122}
123
124pub trait OnChainConfig: Send + Sync + DeserializeOwned {
127 const ADDRESS: &'static str = CONFIG_ADDRESS_STR;
129 const IDENTIFIER: &'static str;
130 const CONFIG_ID: ConfigID = ConfigID(Self::ADDRESS, Self::IDENTIFIER);
131
132 fn deserialize_default_impl(bytes: &[u8]) -> Result<Self> {
141 bcs::from_bytes::<Self>(&bytes).map_err(|e| {
142 format_err!(
143 "[on-chain config] Failed to deserialize into config: {}",
144 e
145 )
146 })
147 }
148
149 fn deserialize_into_config(bytes: &[u8]) -> Result<Self> {
154 Self::deserialize_default_impl(bytes)
155 }
156
157 fn fetch_config<T>(storage: &T) -> Option<Self>
158 where T: ConfigStorage {
159 storage
160 .fetch_config(Self::CONFIG_ID.access_path())
161 .and_then(|bytes| Self::deserialize_into_config(&bytes).ok())
162 }
163}
164
165pub fn new_epoch_event_key() -> EventKey {
166 EventKey::new_from_address(&config_address(), 4)
167}
168
169pub fn access_path_for_config(
170 address: AccountAddress, config_name: Identifier,
171) -> AccessPath {
172 AccessPath::new(
173 address,
174 AccessPath::resource_access_vec(StructTag {
175 address: CORE_CODE_ADDRESS,
176 module: Identifier::new("DiemConfig").unwrap(),
177 name: Identifier::new("DiemConfig").unwrap(),
178 type_params: vec![TypeTag::Struct(StructTag {
179 address: CORE_CODE_ADDRESS,
180 module: config_name.clone(),
181 name: config_name,
182 type_params: vec![],
183 })],
184 }),
185 )
186}
187
188#[derive(Debug, Deserialize, Serialize)]
189pub struct ConfigurationResource {
190 epoch: u64,
191 last_reconfiguration_time: u64,
192 events: EventHandle,
193}
194
195impl ConfigurationResource {
196 pub fn epoch(&self) -> u64 { self.epoch }
197
198 pub fn last_reconfiguration_time(&self) -> u64 {
199 self.last_reconfiguration_time
200 }
201
202 pub fn events(&self) -> &EventHandle { &self.events }
203
204 #[cfg(feature = "fuzzing")]
205 pub fn bump_epoch_for_test(&self) -> Self {
206 let epoch = self.epoch + 1;
207 let last_reconfiguration_time = self.last_reconfiguration_time + 1;
208 let mut events = self.events.clone();
209 *events.count_mut() += 1;
210
211 Self {
212 epoch,
213 last_reconfiguration_time,
214 events,
215 }
216 }
217}
218
219#[cfg(feature = "fuzzing")]
220impl Default for ConfigurationResource {
221 fn default() -> Self {
222 Self {
223 epoch: 0,
224 last_reconfiguration_time: 0,
225 events: EventHandle::new_from_address(
226 &crate::account_config::diem_root_address(),
227 16,
228 ),
229 }
230 }
231}
232
233impl MoveResource for ConfigurationResource {
234 const MODULE_NAME: &'static str = "DiemConfig";
235 const STRUCT_NAME: &'static str = "Configuration";
236}