Skip to main content

radix_engine/updates/
protocol_builder.rs

1use super::*;
2use crate::internal_prelude::*;
3
4#[derive(Clone)]
5pub struct ProtocolBuilder {
6    settings: ProtocolSettings,
7}
8
9#[derive(Clone)]
10pub struct ProtocolSettings {
11    pub network_definition: NetworkDefinition,
12    pub babylon: BabylonSettings,
13    pub anemone: AnemoneSettings,
14    pub bottlenose: BottlenoseSettings,
15    pub cuttlefish_part1: CuttlefishPart1Settings,
16    pub cuttlefish_part2: CuttlefishPart2Settings,
17    pub dugong: DugongSettings,
18    pub eagle_ray: EagleRaySettings,
19}
20
21impl ProtocolSettings {
22    pub fn resolve_generator_for_update(
23        &self,
24        protocol_version: &ProtocolVersion,
25    ) -> Box<dyn ProtocolUpdateGenerator> {
26        match protocol_version {
27            ProtocolVersion::Unbootstrapped => Box::new(NoOpGenerator),
28            ProtocolVersion::Babylon => Box::new(self.babylon.create_generator()),
29            ProtocolVersion::Anemone => Box::new(self.anemone.create_generator()),
30            ProtocolVersion::Bottlenose => Box::new(self.bottlenose.create_generator()),
31            ProtocolVersion::CuttlefishPart1 => Box::new(self.cuttlefish_part1.create_generator()),
32            ProtocolVersion::CuttlefishPart2 => Box::new(self.cuttlefish_part2.create_generator()),
33            ProtocolVersion::Dugong => Box::new(self.dugong.create_generator()),
34            ProtocolVersion::EagleRay => Box::new(self.eagle_ray.create_generator()),
35        }
36    }
37}
38
39impl ProtocolBuilder {
40    pub fn for_simulator() -> Self {
41        Self::for_network(&NetworkDefinition::simulator())
42    }
43
44    pub fn for_network(network_definition: &NetworkDefinition) -> Self {
45        Self {
46            settings: ProtocolSettings {
47                network_definition: network_definition.clone(),
48                babylon: BabylonSettings::all_enabled_as_default_for_network(network_definition),
49                anemone: AnemoneSettings::all_enabled_as_default_for_network(network_definition),
50                bottlenose: BottlenoseSettings::all_enabled_as_default_for_network(
51                    network_definition,
52                ),
53                cuttlefish_part1: CuttlefishPart1Settings::all_enabled_as_default_for_network(
54                    network_definition,
55                ),
56                cuttlefish_part2: CuttlefishPart2Settings::all_enabled_as_default_for_network(
57                    network_definition,
58                ),
59                dugong: DugongSettings::all_enabled_as_default_for_network(network_definition),
60                eagle_ray: EagleRaySettings::all_enabled_as_default_for_network(network_definition),
61            },
62        }
63    }
64
65    pub fn configure_babylon(
66        mut self,
67        creator: impl FnOnce(BabylonSettings) -> BabylonSettings,
68    ) -> Self {
69        self.settings.babylon = creator(self.settings.babylon);
70        self
71    }
72
73    pub fn configure_anemone(
74        mut self,
75        creator: impl FnOnce(AnemoneSettings) -> AnemoneSettings,
76    ) -> Self {
77        self.settings.anemone = creator(self.settings.anemone);
78        self
79    }
80
81    pub fn configure_bottlenose(
82        mut self,
83        creator: impl FnOnce(BottlenoseSettings) -> BottlenoseSettings,
84    ) -> Self {
85        self.settings.bottlenose = creator(self.settings.bottlenose);
86        self
87    }
88
89    pub fn configure_cuttlefish(
90        mut self,
91        creator: impl FnOnce(CuttlefishPart1Settings) -> CuttlefishPart1Settings,
92    ) -> Self {
93        self.settings.cuttlefish_part1 = creator(self.settings.cuttlefish_part1);
94        self
95    }
96
97    pub fn configure_dugong(
98        mut self,
99        creator: impl FnOnce(DugongSettings) -> DugongSettings,
100    ) -> Self {
101        self.settings.dugong = creator(self.settings.dugong);
102        self
103    }
104
105    pub fn configure_eagle_ray(
106        mut self,
107        creator: impl FnOnce(EagleRaySettings) -> EagleRaySettings,
108    ) -> Self {
109        self.settings.eagle_ray = creator(self.settings.eagle_ray);
110        self
111    }
112
113    pub fn unbootstrapped(self) -> ProtocolExecutor {
114        self.from_to(
115            ProtocolVersion::Unbootstrapped,
116            ProtocolVersion::Unbootstrapped,
117        )
118    }
119
120    pub fn from_bootstrap_to(self, protocol_version: ProtocolVersion) -> ProtocolExecutor {
121        self.from_to(ProtocolVersion::Unbootstrapped, protocol_version)
122    }
123
124    pub fn from_bootstrap_to_latest(self) -> ProtocolExecutor {
125        self.from_bootstrap_to(ProtocolVersion::LATEST)
126    }
127
128    pub fn only_babylon(self) -> ProtocolExecutor {
129        self.from_bootstrap_to(ProtocolVersion::Babylon)
130    }
131
132    /// The `start_protocol_version` is assumed to be currently active.
133    /// If you want to also run bootstrap (i.e. enact `ProtocolVersion::Babylon`), use the `from_bootstrap_to` method.
134    pub fn from_to(
135        self,
136        start_protocol_version: ProtocolVersion,
137        end_protocol_version: ProtocolVersion,
138    ) -> ProtocolExecutor {
139        ProtocolExecutor::new(
140            ProtocolExecutorStart::FromCompleted(start_protocol_version),
141            end_protocol_version,
142            self.settings,
143        )
144    }
145
146    /// Discovers the start point from the database
147    pub fn from_current_to_latest(self) -> ProtocolExecutor {
148        self.from_current_to(ProtocolVersion::LATEST)
149    }
150
151    /// Discovers the start point from the database
152    pub fn from_current_to(self, end_protocol_version: ProtocolVersion) -> ProtocolExecutor {
153        ProtocolExecutor::new(
154            ProtocolExecutorStart::ResumeFromCurrent,
155            end_protocol_version,
156            self.settings,
157        )
158    }
159}
160
161enum ProtocolExecutorStart {
162    FromCompleted(ProtocolVersion),
163    ResumeFromCurrent,
164}
165
166pub struct ProtocolExecutor {
167    starting_at: ProtocolExecutorStart,
168    update_until: ProtocolVersion,
169    settings: ProtocolSettings,
170}
171
172impl ProtocolExecutor {
173    fn new(
174        starting_at: ProtocolExecutorStart,
175        update_until: ProtocolVersion,
176        settings: ProtocolSettings,
177    ) -> Self {
178        Self {
179            starting_at,
180            update_until,
181            settings,
182        }
183    }
184
185    pub fn commit_each_protocol_update(
186        self,
187        store: &mut (impl SubstateDatabase + CommittableSubstateDatabase),
188    ) {
189        for update_execution in self.each_protocol_update_executor(&*store) {
190            update_execution.run_and_commit(store);
191        }
192    }
193
194    /// For defaults:
195    /// * For the hooks, you can use `&mut ()`
196    /// * For the modules you can use `&mut VmModules::default()`
197    pub fn commit_each_protocol_update_advanced(
198        self,
199        store: &mut (impl SubstateDatabase + CommittableSubstateDatabase),
200        hooks: &mut impl ProtocolUpdateExecutionHooks,
201        modules: &impl VmInitialize,
202    ) {
203        for update_execution in self.each_protocol_update_executor(&*store) {
204            update_execution.run_and_commit_advanced(store, hooks, modules);
205        }
206    }
207
208    pub fn each_target_protocol_version(
209        &self,
210        store: &impl SubstateDatabase,
211    ) -> impl Iterator<Item = (ProtocolVersion, (usize, usize))> {
212        let starting_at = match self.starting_at {
213            ProtocolExecutorStart::FromCompleted(protocol_version) => ProtocolUpdateStatusSummary {
214                protocol_version,
215                update_status: ProtocolUpdateStatus::Complete,
216            },
217            ProtocolExecutorStart::ResumeFromCurrent => {
218                ProtocolUpdateStatusSummarySubstate::load(store).into_unique_version()
219            }
220        };
221        let from_protocol_version = starting_at.protocol_version;
222        ProtocolVersion::all_between_inclusive(starting_at.protocol_version, self.update_until)
223            .filter_map(move |version| {
224                if from_protocol_version == version {
225                    match &starting_at.update_status {
226                        ProtocolUpdateStatus::Complete => None,
227                        ProtocolUpdateStatus::InProgress { latest_commit } => Some((
228                            version,
229                            (
230                                latest_commit.batch_group_index,
231                                latest_commit.batch_index + 1,
232                            ),
233                        )),
234                    }
235                } else {
236                    Some((version, (0, 0)))
237                }
238            })
239    }
240
241    pub fn each_protocol_update_executor(
242        self,
243        store: &impl SubstateDatabase,
244    ) -> impl Iterator<Item = ProtocolUpdateExecutor> {
245        self.each_target_protocol_version(store)
246            .map(move |(version, start_from_inclusive)| {
247                ProtocolUpdateExecutor::continue_for_version(
248                    version,
249                    &self.settings,
250                    start_from_inclusive,
251                )
252            })
253    }
254}