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