1use num_rational::Ratio;
3use std::{
4 cell::RefCell,
5 collections::{BTreeMap, BTreeSet},
6 rc::Rc,
7};
8
9use thiserror::Error;
10use tracing::{debug, error, info, warn};
11
12use casper_types::{
13 addressable_entity::{
14 ActionThresholds, AssociatedKeys, EntityKind, NamedKeyAddr, NamedKeyValue, Weight,
15 },
16 bytesrepr::{self, ToBytes},
17 contracts::{ContractHash, ContractPackageStatus, NamedKeys},
18 system::{
19 auction::{
20 BidAddr, BidAddrTag, BidKind, DelegatorBid, DelegatorKind,
21 SeigniorageRecipientsSnapshotV1, SeigniorageRecipientsSnapshotV2,
22 SeigniorageRecipientsV2, Unbond, ValidatorBid, AUCTION_DELAY_KEY,
23 DEFAULT_SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION, LOCKED_FUNDS_PERIOD_KEY,
24 SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY, SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION_KEY,
25 UNBONDING_DELAY_KEY, VALIDATOR_SLOTS_KEY,
26 },
27 handle_payment::{ACCUMULATION_PURSE_KEY, PAYMENT_PURSE_KEY},
28 mint::{
29 MINT_GAS_HOLD_HANDLING_KEY, MINT_GAS_HOLD_INTERVAL_KEY, ROUND_SEIGNIORAGE_RATE_KEY,
30 TOTAL_SUPPLY_KEY,
31 },
32 SystemEntityType, AUCTION, HANDLE_PAYMENT, MINT,
33 },
34 AccessRights, AddressableEntity, AddressableEntityHash, ByteCode, ByteCodeAddr, ByteCodeHash,
35 ByteCodeKind, CLValue, CLValueError, Contract, Digest, EntityAddr, EntityVersionKey,
36 EntityVersions, EntryPointAddr, EntryPointValue, EntryPoints, FeeHandling, Groups, HashAddr,
37 Key, KeyTag, Motes, Package, PackageHash, PackageStatus, Phase, ProtocolUpgradeConfig,
38 ProtocolVersion, PublicKey, StoredValue, SystemHashRegistry, URef, U512,
39};
40
41use crate::{
42 global_state::state::StateProvider,
43 tracking_copy::{TrackingCopy, TrackingCopyEntityExt, TrackingCopyExt},
44 AddressGenerator,
45};
46
47const NO_CARRY_FORWARD: bool = false;
48const CARRY_FORWARD: bool = true;
49
50#[derive(Clone, Error, Debug)]
52pub enum ProtocolUpgradeError {
53 #[error("Invalid protocol version: {0}")]
55 InvalidProtocolVersion(ProtocolVersion),
56 #[error("Invalid upgrade config")]
58 InvalidUpgradeConfig,
59 #[error("Unable to retrieve system contract: {0}")]
61 UnableToRetrieveSystemContract(String),
62 #[error("Unable to retrieve system contract package: {0}")]
64 UnableToRetrieveSystemContractPackage(String),
65 #[error("Failed to disable previous version of system contract: {0}")]
67 FailedToDisablePreviousVersion(String),
68 #[error("Bytesrepr error: {0}")]
70 Bytesrepr(String),
71 #[error("Failed to insert system entity registry")]
73 FailedToCreateSystemRegistry,
74 #[error("Unexpected key variant")]
76 UnexpectedKeyVariant,
77 #[error("Unexpected stored value variant")]
79 UnexpectedStoredValueVariant,
80 #[error("{0}")]
82 CLValue(String),
83 #[error("Missing system contract hash: {0}")]
85 MissingSystemEntityHash(String),
86 #[error("{0}")]
88 TrackingCopy(crate::tracking_copy::TrackingCopyError),
89}
90
91impl From<CLValueError> for ProtocolUpgradeError {
92 fn from(v: CLValueError) -> Self {
93 Self::CLValue(v.to_string())
94 }
95}
96
97impl From<crate::tracking_copy::TrackingCopyError> for ProtocolUpgradeError {
98 fn from(err: crate::tracking_copy::TrackingCopyError) -> Self {
99 ProtocolUpgradeError::TrackingCopy(err)
100 }
101}
102
103impl From<bytesrepr::Error> for ProtocolUpgradeError {
104 fn from(error: bytesrepr::Error) -> Self {
105 ProtocolUpgradeError::Bytesrepr(error.to_string())
106 }
107}
108
109pub struct SystemHashAddresses {
111 mint: HashAddr,
112 auction: HashAddr,
113 handle_payment: HashAddr,
114}
115
116impl SystemHashAddresses {
117 pub fn new(mint: HashAddr, auction: HashAddr, handle_payment: HashAddr) -> Self {
119 SystemHashAddresses {
120 mint,
121 auction,
122 handle_payment,
123 }
124 }
125
126 pub fn mint(&self) -> HashAddr {
128 self.mint
129 }
130
131 pub fn auction(&self) -> HashAddr {
133 self.auction
134 }
135
136 pub fn handle_payment(&self) -> HashAddr {
138 self.handle_payment
139 }
140}
141
142pub struct ProtocolUpgrader<S>
144where
145 S: StateProvider,
146{
147 config: ProtocolUpgradeConfig,
148 address_generator: Rc<RefCell<AddressGenerator>>,
149 tracking_copy: TrackingCopy<<S as StateProvider>::Reader>,
150}
151
152impl<S> ProtocolUpgrader<S>
153where
154 S: StateProvider,
155{
156 pub fn new(
158 config: ProtocolUpgradeConfig,
159 protocol_upgrade_config_hash: Digest,
160 tracking_copy: TrackingCopy<<S as StateProvider>::Reader>,
161 ) -> Self {
162 let phase = Phase::System;
163 let protocol_upgrade_config_hash_bytes = protocol_upgrade_config_hash.as_ref();
164
165 let address_generator = {
166 let generator = AddressGenerator::new(protocol_upgrade_config_hash_bytes, phase);
167 Rc::new(RefCell::new(generator))
168 };
169 ProtocolUpgrader {
170 config,
171 address_generator,
172 tracking_copy,
173 }
174 }
175
176 pub fn upgrade(
178 mut self,
179 pre_state_hash: Digest,
180 ) -> Result<TrackingCopy<<S as StateProvider>::Reader>, ProtocolUpgradeError> {
181 self.check_next_protocol_version_validity()?;
182 self.handle_global_state_updates();
183 let system_entity_addresses = self.handle_system_hashes()?;
184
185 if self.config.enable_addressable_entity() {
186 self.migrate_system_account(pre_state_hash)?;
187 self.create_accumulation_purse_if_required(
188 &system_entity_addresses.handle_payment(),
189 self.config.fee_handling(),
190 )?;
191 self.migrate_or_refresh_system_entities(&system_entity_addresses)?;
192 } else {
193 self.create_accumulation_purse_if_required_by_contract(
194 &system_entity_addresses.handle_payment(),
195 self.config.fee_handling(),
196 )?;
197 self.refresh_system_contracts(&system_entity_addresses)?;
198 }
199
200 self.handle_payment_purse_check(
201 system_entity_addresses.handle_payment(),
202 system_entity_addresses.mint(),
203 )?;
204 self.handle_new_gas_hold_config(system_entity_addresses.mint())?;
205 self.handle_new_validator_slots(system_entity_addresses.auction())?;
206 self.handle_new_auction_delay(system_entity_addresses.auction())?;
207 self.handle_new_locked_funds_period_millis(system_entity_addresses.auction())?;
208 self.handle_new_unbonding_delay(system_entity_addresses.auction())?;
209 self.handle_new_round_seigniorage_rate(system_entity_addresses.mint())?;
210 self.handle_unbonds_migration()?;
211 self.handle_bids_migration(
212 self.config.validator_minimum_bid_amount(),
213 self.config.minimum_delegation_amount(),
214 self.config.maximum_delegation_amount(),
215 )?;
216 self.handle_era_info_migration()?;
217 self.handle_seignorage_snapshot_migration(system_entity_addresses.auction())?;
218
219 Ok(self.tracking_copy)
220 }
221
222 pub fn check_next_protocol_version_validity(&self) -> Result<(), ProtocolUpgradeError> {
224 debug!("check next protocol version validity");
225 let current_protocol_version = self.config.current_protocol_version();
226 let new_protocol_version = self.config.new_protocol_version();
227
228 let upgrade_check_result =
229 current_protocol_version.check_next_version(&new_protocol_version);
230
231 if upgrade_check_result.is_invalid() {
232 Err(ProtocolUpgradeError::InvalidProtocolVersion(
233 new_protocol_version,
234 ))
235 } else {
236 Ok(())
237 }
238 }
239
240 fn system_hash_registry(&self) -> Result<SystemHashRegistry, ProtocolUpgradeError> {
241 debug!("system entity registry");
242 let registry = if let Ok(registry) = self.tracking_copy.get_system_entity_registry() {
243 registry
244 } else {
245 let upgrade_registry = self
247 .config
248 .global_state_update()
249 .get(&Key::SystemEntityRegistry)
250 .ok_or_else(|| {
251 error!("Registry is absent in upgrade config");
252 ProtocolUpgradeError::FailedToCreateSystemRegistry
253 })?
254 .to_owned();
255 if let StoredValue::CLValue(cl_registry) = upgrade_registry {
256 CLValue::into_t::<SystemHashRegistry>(cl_registry).map_err(|error| {
257 let error_msg = format!("Conversion to system registry failed: {:?}", error);
258 error!("{}", error_msg);
259 ProtocolUpgradeError::Bytesrepr(error_msg)
260 })?
261 } else {
262 error!("Failed to create registry as StoreValue in upgrade config is not CLValue");
263 return Err(ProtocolUpgradeError::FailedToCreateSystemRegistry);
264 }
265 };
266 Ok(registry)
267 }
268
269 pub fn handle_system_hashes(&mut self) -> Result<SystemHashAddresses, ProtocolUpgradeError> {
271 debug!("handle system entities");
272 let mut registry = self.system_hash_registry()?;
273
274 let mint = *registry.get(MINT).ok_or_else(|| {
275 error!("Missing system mint entity hash");
276 ProtocolUpgradeError::MissingSystemEntityHash(MINT.to_string())
277 })?;
278 let auction = *registry.get(AUCTION).ok_or_else(|| {
279 error!("Missing system auction entity hash");
280 ProtocolUpgradeError::MissingSystemEntityHash(AUCTION.to_string())
281 })?;
282 let handle_payment = *registry.get(HANDLE_PAYMENT).ok_or_else(|| {
283 error!("Missing system handle payment entity hash");
284 ProtocolUpgradeError::MissingSystemEntityHash(HANDLE_PAYMENT.to_string())
285 })?;
286 if let Some(standard_payment_hash) = registry.remove_standard_payment() {
287 let cl_value_chainspec_registry = CLValue::from_t(registry)
289 .map_err(|error| ProtocolUpgradeError::Bytesrepr(error.to_string()))?;
290
291 self.tracking_copy.write(
292 Key::SystemEntityRegistry,
293 StoredValue::CLValue(cl_value_chainspec_registry),
294 );
295
296 self.tracking_copy.prune(Key::Hash(standard_payment_hash));
298 };
299
300 let cl_value_chainspec_registry = CLValue::from_t(self.config.chainspec_registry().clone())
302 .map_err(|error| ProtocolUpgradeError::Bytesrepr(error.to_string()))?;
303
304 self.tracking_copy.write(
305 Key::ChainspecRegistry,
306 StoredValue::CLValue(cl_value_chainspec_registry),
307 );
308
309 let system_hash_addresses = SystemHashAddresses::new(mint, auction, handle_payment);
310
311 Ok(system_hash_addresses)
312 }
313
314 pub fn migrate_or_refresh_system_entities(
316 &mut self,
317 system_entity_addresses: &SystemHashAddresses,
318 ) -> Result<(), ProtocolUpgradeError> {
319 debug!("refresh system contracts");
320 self.migrate_or_refresh_system_entity_entry_points(
321 system_entity_addresses.mint(),
322 SystemEntityType::Mint,
323 )?;
324 self.migrate_or_refresh_system_entity_entry_points(
325 system_entity_addresses.auction(),
326 SystemEntityType::Auction,
327 )?;
328 self.migrate_or_refresh_system_entity_entry_points(
329 system_entity_addresses.handle_payment(),
330 SystemEntityType::HandlePayment,
331 )?;
332
333 Ok(())
334 }
335
336 pub fn refresh_system_contracts(
338 &mut self,
339 system_entity_addresses: &SystemHashAddresses,
340 ) -> Result<(), ProtocolUpgradeError> {
341 self.refresh_system_contract_entry_points(
342 system_entity_addresses.mint(),
343 SystemEntityType::Mint,
344 )?;
345 self.refresh_system_contract_entry_points(
346 system_entity_addresses.auction(),
347 SystemEntityType::Auction,
348 )?;
349 self.refresh_system_contract_entry_points(
350 system_entity_addresses.handle_payment(),
351 SystemEntityType::HandlePayment,
352 )?;
353
354 Ok(())
355 }
356
357 fn migrate_or_refresh_system_entity_entry_points(
360 &mut self,
361 hash_addr: HashAddr,
362 system_entity_type: SystemEntityType,
363 ) -> Result<(), ProtocolUpgradeError> {
364 debug!(%system_entity_type, "refresh system contract entry points");
365 let entity_name = system_entity_type.entity_name();
366
367 let (mut entity, maybe_named_keys, must_carry_forward) =
368 match self.retrieve_system_entity(hash_addr, system_entity_type) {
369 Ok(ret) => ret,
370 Err(err) => {
371 error!("{:?}", err);
372 return Err(err);
373 }
374 };
375
376 let mut package =
377 self.retrieve_system_package(entity.package_hash(), system_entity_type)?;
378
379 let entity_hash = AddressableEntityHash::new(hash_addr);
380 let entity_addr = EntityAddr::new_system(entity_hash.value());
381 package.disable_entity_version(entity_addr).map_err(|_| {
382 ProtocolUpgradeError::FailedToDisablePreviousVersion(entity_name.to_string())
383 })?;
384
385 entity.set_protocol_version(self.config.new_protocol_version());
386
387 let new_entity = AddressableEntity::new(
388 entity.package_hash(),
389 ByteCodeHash::default(),
390 self.config.new_protocol_version(),
391 URef::default(),
392 AssociatedKeys::default(),
393 ActionThresholds::default(),
394 EntityKind::System(system_entity_type),
395 );
396
397 let byte_code_key = Key::byte_code_key(ByteCodeAddr::Empty);
398 let byte_code = ByteCode::new(ByteCodeKind::Empty, vec![]);
399
400 self.tracking_copy
401 .write(byte_code_key, StoredValue::ByteCode(byte_code));
402
403 let entity_key = new_entity.entity_key(entity_hash);
404
405 self.tracking_copy
406 .write(entity_key, StoredValue::AddressableEntity(new_entity));
407
408 if let Some(named_keys) = maybe_named_keys {
409 for (string, key) in named_keys.into_inner().into_iter() {
410 let entry_addr = NamedKeyAddr::new_from_string(entity_addr, string.clone())
411 .map_err(|err| ProtocolUpgradeError::Bytesrepr(err.to_string()))?;
412
413 let entry_key = Key::NamedKey(entry_addr);
414
415 let named_key_value = NamedKeyValue::from_concrete_values(key, string)
416 .map_err(|error| ProtocolUpgradeError::CLValue(error.to_string()))?;
417
418 self.tracking_copy
419 .write(entry_key, StoredValue::NamedKey(named_key_value));
420 }
421 }
422
423 let entry_points = system_entity_type.entry_points();
424
425 for entry_point in entry_points.take_entry_points() {
426 let entry_point_addr =
427 EntryPointAddr::new_v1_entry_point_addr(entity_addr, entry_point.name())
428 .map_err(|error| ProtocolUpgradeError::Bytesrepr(error.to_string()))?;
429 self.tracking_copy.write(
430 Key::EntryPoint(entry_point_addr),
431 StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point)),
432 );
433 }
434
435 package.insert_entity_version(
436 self.config.new_protocol_version().value().major,
437 entity_addr,
438 );
439
440 self.tracking_copy.write(
441 Key::SmartContract(entity.package_hash().value()),
442 StoredValue::SmartContract(package),
443 );
444
445 if must_carry_forward {
446 let package_key = Key::SmartContract(entity.package_hash().value());
448 let uref = URef::default();
449 let indirection = CLValue::from_t((package_key, uref))
450 .map_err(|cl_error| ProtocolUpgradeError::CLValue(cl_error.to_string()))?;
451
452 self.tracking_copy.write(
453 Key::Hash(entity.package_hash().value()),
454 StoredValue::CLValue(indirection),
455 );
456
457 let contract_wasm_key = Key::Hash(entity.byte_code_hash().value());
458 let contract_wasm_indirection = CLValue::from_t(Key::ByteCode(ByteCodeAddr::Empty))
459 .map_err(|cl_error| ProtocolUpgradeError::CLValue(cl_error.to_string()))?;
460 self.tracking_copy.write(
461 contract_wasm_key,
462 StoredValue::CLValue(contract_wasm_indirection),
463 );
464
465 let contract_indirection = CLValue::from_t(Key::AddressableEntity(entity_addr))
466 .map_err(|cl_error| ProtocolUpgradeError::CLValue(cl_error.to_string()))?;
467
468 self.tracking_copy.write(
469 Key::Hash(entity_addr.value()),
470 StoredValue::CLValue(contract_indirection),
471 )
472 }
473
474 Ok(())
475 }
476
477 fn retrieve_system_package(
478 &mut self,
479 package_hash: PackageHash,
480 system_contract_type: SystemEntityType,
481 ) -> Result<Package, ProtocolUpgradeError> {
482 debug!(%system_contract_type, "retrieve system package");
483 if let Some(StoredValue::SmartContract(system_entity)) = self
484 .tracking_copy
485 .read(&Key::SmartContract(package_hash.value()))
486 .map_err(|_| {
487 ProtocolUpgradeError::UnableToRetrieveSystemContractPackage(
488 system_contract_type.to_string(),
489 )
490 })?
491 {
492 return Ok(system_entity);
493 }
494
495 if let Some(StoredValue::ContractPackage(contract_package)) = self
496 .tracking_copy
497 .read(&Key::Hash(package_hash.value()))
498 .map_err(|_| {
499 ProtocolUpgradeError::UnableToRetrieveSystemContractPackage(
500 system_contract_type.to_string(),
501 )
502 })?
503 {
504 let versions: BTreeMap<EntityVersionKey, EntityAddr> = contract_package
505 .versions()
506 .iter()
507 .map(|(version, contract_hash)| {
508 let entity_version = EntityVersionKey::new(2, version.contract_version());
509 let entity_hash = EntityAddr::System(contract_hash.value());
510 (entity_version, entity_hash)
511 })
512 .collect();
513
514 let disabled_versions = contract_package
515 .disabled_versions()
516 .iter()
517 .map(|contract_versions| {
518 EntityVersionKey::new(
519 contract_versions.protocol_version_major(),
520 contract_versions.contract_version(),
521 )
522 })
523 .collect();
524
525 let lock_status = if contract_package.lock_status() == ContractPackageStatus::Locked {
526 PackageStatus::Locked
527 } else {
528 PackageStatus::Unlocked
529 };
530
531 let groups = contract_package.take_groups();
532 return Ok(Package::new(
533 versions.into(),
534 disabled_versions,
535 groups,
536 lock_status,
537 ));
538 }
539
540 Err(ProtocolUpgradeError::UnableToRetrieveSystemContractPackage(
541 system_contract_type.to_string(),
542 ))
543 }
544
545 fn retrieve_system_entity(
546 &mut self,
547 hash_addr: HashAddr,
548 system_contract_type: SystemEntityType,
549 ) -> Result<(AddressableEntity, Option<NamedKeys>, bool), ProtocolUpgradeError> {
550 debug!(%system_contract_type, "retrieve system entity");
551 if let Some(StoredValue::Contract(system_contract)) = self
552 .tracking_copy
553 .read(&Key::Hash(hash_addr))
554 .map_err(|_| {
555 ProtocolUpgradeError::UnableToRetrieveSystemContract(
556 system_contract_type.to_string(),
557 )
558 })?
559 {
560 let named_keys = system_contract.named_keys().clone();
561 return Ok((system_contract.into(), Some(named_keys), CARRY_FORWARD));
562 }
563
564 if let Some(StoredValue::AddressableEntity(system_entity)) = self
565 .tracking_copy
566 .read(&Key::AddressableEntity(EntityAddr::new_system(hash_addr)))
567 .map_err(|_| {
568 ProtocolUpgradeError::UnableToRetrieveSystemContract(
569 system_contract_type.to_string(),
570 )
571 })?
572 {
573 return Ok((system_entity, None, NO_CARRY_FORWARD));
574 }
575
576 Err(ProtocolUpgradeError::UnableToRetrieveSystemContract(
577 system_contract_type.to_string(),
578 ))
579 }
580
581 fn refresh_system_contract_entry_points(
584 &mut self,
585 contract_hash: HashAddr,
586 system_entity_type: SystemEntityType,
587 ) -> Result<(), ProtocolUpgradeError> {
588 let contract_name = system_entity_type.entity_name();
589 let entry_points = system_entity_type.entry_points();
590
591 let mut contract = if let StoredValue::Contract(contract) = self
592 .tracking_copy
593 .read(&Key::Hash(contract_hash))
594 .map_err(|_| {
595 ProtocolUpgradeError::UnableToRetrieveSystemContract(contract_name.to_string())
596 })?
597 .ok_or_else(|| {
598 ProtocolUpgradeError::UnableToRetrieveSystemContract(contract_name.to_string())
599 })? {
600 contract
601 } else {
602 return Err(ProtocolUpgradeError::UnableToRetrieveSystemContract(
603 contract_name,
604 ));
605 };
606
607 let is_major_bump = self
608 .config
609 .current_protocol_version()
610 .check_next_version(&self.config.new_protocol_version())
611 .is_major_version();
612
613 let contract_entry_points: EntryPoints = contract.entry_points().clone().into();
614 let entry_points_unchanged = contract_entry_points == entry_points;
615 if entry_points_unchanged && !is_major_bump {
616 return Ok(());
619 }
620
621 let contract_package_key = Key::Hash(contract.contract_package_hash().value());
622
623 let mut contract_package = if let StoredValue::ContractPackage(contract_package) = self
624 .tracking_copy
625 .read(&contract_package_key)
626 .map_err(|_| {
627 ProtocolUpgradeError::UnableToRetrieveSystemContractPackage(
628 contract_name.to_string(),
629 )
630 })?
631 .ok_or_else(|| {
632 ProtocolUpgradeError::UnableToRetrieveSystemContractPackage(
633 contract_name.to_string(),
634 )
635 })? {
636 contract_package
637 } else {
638 return Err(ProtocolUpgradeError::UnableToRetrieveSystemContractPackage(
639 contract_name,
640 ));
641 };
642
643 contract.set_protocol_version(self.config.new_protocol_version());
644
645 let new_contract = Contract::new(
646 contract.contract_package_hash(),
647 contract.contract_wasm_hash(),
648 contract.named_keys().clone(),
649 entry_points.into(),
650 self.config.new_protocol_version(),
651 );
652 self.tracking_copy.write(
653 Key::Hash(contract_hash),
654 StoredValue::Contract(new_contract),
655 );
656
657 contract_package.insert_contract_version(
658 self.config.new_protocol_version().value().major,
659 ContractHash::new(contract_hash),
660 );
661
662 self.tracking_copy.write(
663 contract_package_key,
664 StoredValue::ContractPackage(contract_package),
665 );
666
667 Ok(())
668 }
669
670 pub fn migrate_system_account(
672 &mut self,
673 pre_state_hash: Digest,
674 ) -> Result<(), ProtocolUpgradeError> {
675 debug!("migrate system account");
676 let mut address_generator = AddressGenerator::new(pre_state_hash.as_ref(), Phase::System);
677
678 let account_hash = PublicKey::System.to_account_hash();
679
680 let main_purse = {
681 let purse_addr = address_generator.new_hash_address();
682 let balance_cl_value = CLValue::from_t(U512::zero())
683 .map_err(|error| ProtocolUpgradeError::CLValue(error.to_string()))?;
684
685 self.tracking_copy.write(
686 Key::Balance(purse_addr),
687 StoredValue::CLValue(balance_cl_value),
688 );
689
690 let purse_cl_value = CLValue::unit();
691 let purse_uref = URef::new(purse_addr, AccessRights::READ_ADD_WRITE);
692
693 self.tracking_copy
694 .write(Key::URef(purse_uref), StoredValue::CLValue(purse_cl_value));
695 purse_uref
696 };
697
698 let associated_keys = AssociatedKeys::new(account_hash, Weight::new(1));
699 let byte_code_hash = ByteCodeHash::default();
700 let entity_hash = AddressableEntityHash::new(PublicKey::System.to_account_hash().value());
701 let package_hash = PackageHash::new(address_generator.new_hash_address());
702
703 let byte_code = ByteCode::new(ByteCodeKind::Empty, vec![]);
704
705 let system_account_entity = AddressableEntity::new(
706 package_hash,
707 byte_code_hash,
708 self.config.new_protocol_version(),
709 main_purse,
710 associated_keys,
711 ActionThresholds::default(),
712 EntityKind::Account(account_hash),
713 );
714
715 let package = {
716 let mut package = Package::new(
717 EntityVersions::default(),
718 BTreeSet::default(),
719 Groups::default(),
720 PackageStatus::default(),
721 );
722 package.insert_entity_version(
723 self.config.new_protocol_version().value().major,
724 EntityAddr::Account(entity_hash.value()),
725 );
726 package
727 };
728
729 let byte_code_key = Key::ByteCode(ByteCodeAddr::Empty);
730 self.tracking_copy
731 .write(byte_code_key, StoredValue::ByteCode(byte_code));
732
733 let entity_key = system_account_entity.entity_key(entity_hash);
734
735 self.tracking_copy.write(
736 entity_key,
737 StoredValue::AddressableEntity(system_account_entity),
738 );
739
740 self.tracking_copy
741 .write(package_hash.into(), StoredValue::SmartContract(package));
742
743 let contract_by_account = CLValue::from_t(entity_key)
744 .map_err(|error| ProtocolUpgradeError::CLValue(error.to_string()))?;
745
746 self.tracking_copy.write(
747 Key::Account(account_hash),
748 StoredValue::CLValue(contract_by_account),
749 );
750
751 Ok(())
752 }
753
754 pub fn create_accumulation_purse_if_required(
760 &mut self,
761 handle_payment_hash: &HashAddr,
762 fee_handling: FeeHandling,
763 ) -> Result<(), ProtocolUpgradeError> {
764 debug!(?fee_handling, "create accumulation purse if required");
765 match fee_handling {
766 FeeHandling::PayToProposer | FeeHandling::Burn => return Ok(()),
767 FeeHandling::Accumulate | FeeHandling::NoFee => {}
768 }
769 let mut address_generator = {
770 let seed_bytes = (
771 self.config.current_protocol_version(),
772 self.config.new_protocol_version(),
773 )
774 .to_bytes()?;
775 let phase = Phase::System;
776 AddressGenerator::new(&seed_bytes, phase)
777 };
778 let system_contract = SystemEntityType::HandlePayment;
779
780 let (addressable_entity, maybe_named_keys, _) =
781 self.retrieve_system_entity(*handle_payment_hash, system_contract)?;
782
783 let entity_addr = EntityAddr::new_system(*handle_payment_hash);
784
785 if let Some(named_keys) = maybe_named_keys {
786 for (string, key) in named_keys.into_inner().into_iter() {
787 let entry_addr = NamedKeyAddr::new_from_string(entity_addr, string.clone())
788 .map_err(|err| ProtocolUpgradeError::Bytesrepr(err.to_string()))?;
789
790 let named_key_value = NamedKeyValue::from_concrete_values(key, string)
791 .map_err(|error| ProtocolUpgradeError::CLValue(error.to_string()))?;
792
793 let entry_key = Key::NamedKey(entry_addr);
794
795 self.tracking_copy
796 .write(entry_key, StoredValue::NamedKey(named_key_value));
797 }
798 }
799
800 let named_key_addr =
801 NamedKeyAddr::new_from_string(entity_addr, ACCUMULATION_PURSE_KEY.to_string())
802 .map_err(|err| ProtocolUpgradeError::Bytesrepr(err.to_string()))?;
803
804 let requries_accumulation_purse = self
805 .tracking_copy
806 .read(&Key::NamedKey(named_key_addr))
807 .map_err(|_| ProtocolUpgradeError::UnexpectedStoredValueVariant)?
808 .is_none();
809
810 if requries_accumulation_purse {
811 let purse_uref = address_generator.new_uref(AccessRights::READ_ADD_WRITE);
812 let balance_clvalue = CLValue::from_t(U512::zero())?;
813 self.tracking_copy.write(
814 Key::Balance(purse_uref.addr()),
815 StoredValue::CLValue(balance_clvalue),
816 );
817
818 let purse_key = Key::URef(purse_uref);
819
820 self.tracking_copy
821 .write(purse_key, StoredValue::CLValue(CLValue::unit()));
822
823 let purse =
824 NamedKeyValue::from_concrete_values(purse_key, ACCUMULATION_PURSE_KEY.to_string())
825 .map_err(|cl_error| ProtocolUpgradeError::CLValue(cl_error.to_string()))?;
826
827 self.tracking_copy
828 .write(Key::NamedKey(named_key_addr), StoredValue::NamedKey(purse));
829
830 let entity_key = Key::AddressableEntity(EntityAddr::System(*handle_payment_hash));
831
832 self.tracking_copy.write(
833 entity_key,
834 StoredValue::AddressableEntity(addressable_entity),
835 );
836 }
837
838 Ok(())
839 }
840
841 pub fn create_accumulation_purse_if_required_by_contract(
847 &mut self,
848 handle_payment_hash: &HashAddr,
849 fee_handling: FeeHandling,
850 ) -> Result<(), ProtocolUpgradeError> {
851 match fee_handling {
852 FeeHandling::PayToProposer | FeeHandling::Burn => return Ok(()),
853 FeeHandling::Accumulate | FeeHandling::NoFee => {}
854 }
855
856 let mut address_generator = {
857 let seed_bytes = (
858 self.config.current_protocol_version(),
859 self.config.new_protocol_version(),
860 )
861 .to_bytes()?;
862
863 let phase = Phase::System;
864
865 AddressGenerator::new(&seed_bytes, phase)
866 };
867
868 let system_contract = SystemEntityType::HandlePayment;
869 let contract_name = system_contract.entity_name();
870 let mut contract = if let StoredValue::Contract(contract) = self
871 .tracking_copy
872 .read(&Key::Hash(*handle_payment_hash))
873 .map_err(|_| {
874 ProtocolUpgradeError::UnableToRetrieveSystemContract(contract_name.to_string())
875 })?
876 .ok_or_else(|| {
877 ProtocolUpgradeError::UnableToRetrieveSystemContract(contract_name.to_string())
878 })? {
879 contract
880 } else {
881 return Err(ProtocolUpgradeError::UnableToRetrieveSystemContract(
882 contract_name,
883 ));
884 };
885
886 if !contract.named_keys().contains(ACCUMULATION_PURSE_KEY) {
887 let purse_uref = address_generator.new_uref(AccessRights::READ_ADD_WRITE);
888 let balance_clvalue = CLValue::from_t(U512::zero())?;
889 self.tracking_copy.write(
890 Key::Balance(purse_uref.addr()),
891 StoredValue::CLValue(balance_clvalue),
892 );
893 self.tracking_copy
894 .write(Key::URef(purse_uref), StoredValue::CLValue(CLValue::unit()));
895
896 let mut new_named_keys = NamedKeys::new();
897 new_named_keys.insert(ACCUMULATION_PURSE_KEY.into(), Key::from(purse_uref));
898 contract.named_keys_append(new_named_keys);
899
900 self.tracking_copy.write(
901 Key::Hash(*handle_payment_hash),
902 StoredValue::Contract(contract),
903 );
904 }
905
906 Ok(())
907 }
908
909 fn get_named_keys(
910 &mut self,
911 contract_hash: HashAddr,
912 ) -> Result<NamedKeys, ProtocolUpgradeError> {
913 if self.config.enable_addressable_entity() {
914 let named_keys = self
915 .tracking_copy
916 .get_named_keys(EntityAddr::System(contract_hash))?;
917 Ok(named_keys)
918 } else {
919 let named_keys = self
920 .tracking_copy
921 .read(&Key::Hash(contract_hash))?
922 .ok_or_else(|| {
923 ProtocolUpgradeError::UnableToRetrieveSystemContract(format!(
924 "{:?}",
925 contract_hash
926 ))
927 })?
928 .as_contract()
929 .map(|contract| contract.named_keys().clone())
930 .ok_or(ProtocolUpgradeError::UnexpectedStoredValueVariant)?;
931
932 Ok(named_keys)
933 }
934 }
935
936 pub fn handle_payment_purse_check(
938 &mut self,
939 handle_payment: HashAddr,
940 mint: HashAddr,
941 ) -> Result<(), ProtocolUpgradeError> {
942 let payment_named_keys = self.get_named_keys(handle_payment)?;
943 let payment_purse_key = payment_named_keys
944 .get(PAYMENT_PURSE_KEY)
945 .expect("payment purse key must exist in handle payment contract's named keys");
946 let balance = self
947 .tracking_copy
948 .get_total_balance(*payment_purse_key)
949 .expect("must be able to get payment purse balance");
950 if balance <= Motes::zero() {
951 return Ok(());
952 }
953 warn!("payment purse had remaining balance at upgrade {}", balance);
954 let balance_key = {
955 let uref_addr = payment_purse_key
956 .as_uref()
957 .expect("payment purse key must be uref.")
958 .addr();
959 Key::Balance(uref_addr)
960 };
961
962 let mint_named_keys = self.get_named_keys(mint)?;
963 let total_supply_key = mint_named_keys
964 .get(TOTAL_SUPPLY_KEY)
965 .expect("total supply key must exist in mint contract's named keys");
966
967 let stored_value = self
968 .tracking_copy
969 .read(total_supply_key)
970 .expect("must be able to read total supply")
971 .expect("total supply must have a value");
972
973 if let StoredValue::CLValue(value) = stored_value {
975 let total_supply: U512 =
977 CLValue::into_t(value).expect("total supply must have expected type.");
978
979 let new_total_supply = total_supply.saturating_sub(balance.value());
980 info!(
981 "adjusting total supply from {} to {}",
982 total_supply, new_total_supply
983 );
984 let cl_value = CLValue::from_t(new_total_supply)
985 .expect("new total supply must convert to CLValue.");
986 self.tracking_copy
987 .write(*total_supply_key, StoredValue::CLValue(cl_value));
988 info!(
989 "adjusting payment purse balance from {} to {}",
990 balance.value(),
991 U512::zero()
992 );
993 let cl_value = CLValue::from_t(U512::zero()).expect("zero must convert to CLValue.");
994 self.tracking_copy
995 .write(balance_key, StoredValue::CLValue(cl_value));
996 Ok(())
997 } else {
998 Err(ProtocolUpgradeError::CLValue(
999 "failure to retrieve total supply".to_string(),
1000 ))
1001 }
1002 }
1003
1004 pub fn handle_new_gas_hold_config(
1006 &mut self,
1007 mint: HashAddr,
1008 ) -> Result<(), ProtocolUpgradeError> {
1009 if self.config.new_gas_hold_handling().is_none()
1010 && self.config.new_gas_hold_interval().is_none()
1011 {
1012 return Ok(());
1013 }
1014
1015 let mint_addr = EntityAddr::System(mint);
1016 let named_keys = self.get_named_keys(mint)?;
1017
1018 if let Some(new_gas_hold_handling) = self.config.new_gas_hold_handling() {
1019 debug!(%new_gas_hold_handling, "handle new gas hold handling");
1020 let stored_value =
1021 StoredValue::CLValue(CLValue::from_t(new_gas_hold_handling.tag()).map_err(
1022 |_| ProtocolUpgradeError::Bytesrepr("new_gas_hold_handling".to_string()),
1023 )?);
1024
1025 self.system_uref(
1026 mint_addr,
1027 MINT_GAS_HOLD_HANDLING_KEY,
1028 &named_keys,
1029 stored_value,
1030 )?;
1031 }
1032
1033 if let Some(new_gas_hold_interval) = self.config.new_gas_hold_interval() {
1034 debug!(%new_gas_hold_interval, "handle new gas hold interval");
1035 let stored_value =
1036 StoredValue::CLValue(CLValue::from_t(new_gas_hold_interval).map_err(|_| {
1037 ProtocolUpgradeError::Bytesrepr("new_gas_hold_interval".to_string())
1038 })?);
1039
1040 self.system_uref(
1041 mint_addr,
1042 MINT_GAS_HOLD_INTERVAL_KEY,
1043 &named_keys,
1044 stored_value,
1045 )?;
1046 }
1047 Ok(())
1048 }
1049
1050 fn system_uref(
1051 &mut self,
1052 entity_addr: EntityAddr,
1053 name: &str,
1054 named_keys: &NamedKeys,
1055 stored_value: StoredValue,
1056 ) -> Result<(), ProtocolUpgradeError> {
1057 let uref = {
1058 match named_keys.get(name) {
1059 Some(key) => match key.as_uref() {
1060 Some(uref) => *uref,
1061 None => {
1062 return Err(ProtocolUpgradeError::UnexpectedKeyVariant);
1063 }
1064 },
1065 None => self
1066 .address_generator
1067 .borrow_mut()
1068 .new_uref(AccessRights::READ_ADD_WRITE),
1069 }
1070 };
1071 self.tracking_copy
1072 .upsert_uref_to_named_keys(entity_addr, name, named_keys, uref, stored_value)
1073 .map_err(ProtocolUpgradeError::TrackingCopy)
1074 }
1075
1076 pub fn handle_new_validator_slots(
1078 &mut self,
1079 auction: HashAddr,
1080 ) -> Result<(), ProtocolUpgradeError> {
1081 if let Some(new_validator_slots) = self.config.new_validator_slots() {
1082 debug!(%new_validator_slots, "handle new validator slots");
1083 let auction_named_keys = self.get_named_keys(auction)?;
1085
1086 let validator_slots_key = auction_named_keys
1087 .get(VALIDATOR_SLOTS_KEY)
1088 .expect("validator_slots key must exist in auction contract's named keys");
1089 let value =
1090 StoredValue::CLValue(CLValue::from_t(new_validator_slots).map_err(|_| {
1091 ProtocolUpgradeError::Bytesrepr("new_validator_slots".to_string())
1092 })?);
1093 self.tracking_copy.write(*validator_slots_key, value);
1094 }
1095 Ok(())
1096 }
1097
1098 pub fn handle_new_auction_delay(
1100 &mut self,
1101 auction: HashAddr,
1102 ) -> Result<(), ProtocolUpgradeError> {
1103 if let Some(new_auction_delay) = self.config.new_auction_delay() {
1104 debug!(%new_auction_delay, "handle new auction delay");
1105 let auction_named_keys = self.get_named_keys(auction)?;
1106
1107 let auction_delay_key = auction_named_keys
1108 .get(AUCTION_DELAY_KEY)
1109 .expect("auction_delay key must exist in auction contract's named keys");
1110 let value =
1111 StoredValue::CLValue(CLValue::from_t(new_auction_delay).map_err(|_| {
1112 ProtocolUpgradeError::Bytesrepr("new_auction_delay".to_string())
1113 })?);
1114 self.tracking_copy.write(*auction_delay_key, value);
1115 }
1116 Ok(())
1117 }
1118
1119 pub fn handle_new_locked_funds_period_millis(
1121 &mut self,
1122 auction: HashAddr,
1123 ) -> Result<(), ProtocolUpgradeError> {
1124 if let Some(new_locked_funds_period) = self.config.new_locked_funds_period_millis() {
1125 debug!(%new_locked_funds_period,"handle new locked funds period millis");
1126
1127 let auction_named_keys = self.get_named_keys(auction)?;
1128
1129 let locked_funds_period_key = auction_named_keys
1130 .get(LOCKED_FUNDS_PERIOD_KEY)
1131 .expect("locked_funds_period key must exist in auction contract's named keys");
1132 let value =
1133 StoredValue::CLValue(CLValue::from_t(new_locked_funds_period).map_err(|_| {
1134 ProtocolUpgradeError::Bytesrepr("new_locked_funds_period".to_string())
1135 })?);
1136 self.tracking_copy.write(*locked_funds_period_key, value);
1137 }
1138 Ok(())
1139 }
1140
1141 pub fn handle_new_unbonding_delay(
1143 &mut self,
1144 auction: HashAddr,
1145 ) -> Result<(), ProtocolUpgradeError> {
1146 if let Some(new_unbonding_delay) = self.config.new_unbonding_delay() {
1149 debug!(%new_unbonding_delay,"handle new unbonding delay");
1150
1151 let auction_named_keys = self.get_named_keys(auction)?;
1152
1153 let unbonding_delay_key = auction_named_keys
1154 .get(UNBONDING_DELAY_KEY)
1155 .expect("unbonding_delay key must exist in auction contract's named keys");
1156 let value =
1157 StoredValue::CLValue(CLValue::from_t(new_unbonding_delay).map_err(|_| {
1158 ProtocolUpgradeError::Bytesrepr("new_unbonding_delay".to_string())
1159 })?);
1160 self.tracking_copy.write(*unbonding_delay_key, value);
1161 }
1162 Ok(())
1163 }
1164
1165 pub fn handle_new_round_seigniorage_rate(
1167 &mut self,
1168 mint: HashAddr,
1169 ) -> Result<(), ProtocolUpgradeError> {
1170 if let Some(new_round_seigniorage_rate) = self.config.new_round_seigniorage_rate() {
1171 debug!(%new_round_seigniorage_rate,"handle new round seigniorage rate");
1172 let new_round_seigniorage_rate: Ratio<U512> = {
1173 let (numer, denom) = new_round_seigniorage_rate.into();
1174 Ratio::new(numer.into(), denom.into())
1175 };
1176
1177 let mint_named_keys = self.get_named_keys(mint)?;
1178
1179 let locked_funds_period_key = mint_named_keys
1180 .get(ROUND_SEIGNIORAGE_RATE_KEY)
1181 .expect("round_seigniorage_rate key must exist in mint contract's named keys");
1182 let value = StoredValue::CLValue(CLValue::from_t(new_round_seigniorage_rate).map_err(
1183 |_| ProtocolUpgradeError::Bytesrepr("new_round_seigniorage_rate".to_string()),
1184 )?);
1185 self.tracking_copy.write(*locked_funds_period_key, value);
1186 }
1187 Ok(())
1188 }
1189
1190 pub fn handle_unbonds_migration(&mut self) -> Result<(), ProtocolUpgradeError> {
1192 debug!("handle unbonds migration");
1193 let tc = &mut self.tracking_copy;
1194 let existing_keys = match tc.get_keys(&KeyTag::Unbond) {
1195 Ok(keys) => keys,
1196 Err(err) => return Err(ProtocolUpgradeError::TrackingCopy(err)),
1197 };
1198 for key in existing_keys {
1199 if let Some(StoredValue::Unbonding(unbonding_purses)) =
1200 tc.get(&key).map_err(Into::<ProtocolUpgradeError>::into)?
1201 {
1202 tc.prune(key);
1204
1205 for unbonding_purse in unbonding_purses {
1207 let validator = unbonding_purse.validator_public_key();
1208 let unbonder = unbonding_purse.unbonder_public_key();
1209 let new_key = Key::BidAddr(BidAddr::UnbondAccount {
1210 validator: validator.to_account_hash(),
1211 unbonder: unbonder.to_account_hash(),
1212 });
1213 let unbond = Box::new(Unbond::from(unbonding_purse));
1214 let unbond_bid_kind = BidKind::Unbond(unbond.clone());
1215 if !unbond.eras().is_empty() {
1216 tc.write(new_key, StoredValue::BidKind(unbond_bid_kind));
1217 }
1218 }
1219 }
1220 }
1221
1222 Ok(())
1223 }
1224
1225 pub fn handle_bids_migration(
1227 &mut self,
1228 validator_minimum: u64,
1229 delegation_minimum: u64,
1230 delegation_maximum: u64,
1231 ) -> Result<(), ProtocolUpgradeError> {
1232 if delegation_maximum < delegation_minimum {
1233 return Err(ProtocolUpgradeError::InvalidUpgradeConfig);
1234 }
1235 debug!("handle bids migration");
1236 let tc = &mut self.tracking_copy;
1237 let existing_bid_keys = match tc.get_keys(&KeyTag::Bid) {
1238 Ok(keys) => keys,
1239 Err(err) => return Err(ProtocolUpgradeError::TrackingCopy(err)),
1240 };
1241 for key in existing_bid_keys {
1242 if let Some(StoredValue::Bid(existing_bid)) =
1243 tc.get(&key).map_err(Into::<ProtocolUpgradeError>::into)?
1244 {
1245 tc.prune(key);
1247
1248 if existing_bid.staked_amount().is_zero() {
1249 continue;
1258 }
1259
1260 let validator_public_key = existing_bid.validator_public_key();
1261 let validator_bid_addr = BidAddr::from(validator_public_key.clone());
1262 let validator_bid = {
1263 let validator_bid = ValidatorBid::from(*existing_bid.clone());
1264 let inactive = validator_bid.staked_amount() < U512::from(validator_minimum);
1265 validator_bid
1266 .with_inactive(inactive)
1267 .with_min_max_delegation_amount(delegation_maximum, delegation_minimum)
1268 };
1269 tc.write(
1270 validator_bid_addr.into(),
1271 StoredValue::BidKind(BidKind::Validator(Box::new(validator_bid))),
1272 );
1273
1274 let delegators = existing_bid.delegators().clone();
1275 for (_, delegator) in delegators {
1276 let delegator_bid_addr = BidAddr::new_delegator_kind(
1277 validator_public_key,
1278 &DelegatorKind::PublicKey(delegator.delegator_public_key().clone()),
1279 );
1280 if !delegator.staked_amount().is_zero() {
1285 tc.write(
1286 delegator_bid_addr.into(),
1287 StoredValue::BidKind(BidKind::Delegator(Box::new(DelegatorBid::from(
1288 delegator,
1289 )))),
1290 );
1291 }
1292 }
1293 }
1294 }
1295
1296 let validator_bid_keys = tc
1297 .get_by_byte_prefix(&[KeyTag::BidAddr as u8, BidAddrTag::Validator as u8])
1298 .map_err(|_| ProtocolUpgradeError::UnexpectedKeyVariant)?;
1299 for validator_bid_key in validator_bid_keys {
1300 if let Some(StoredValue::BidKind(BidKind::Validator(validator_bid))) = tc
1301 .get(&validator_bid_key)
1302 .map_err(Into::<ProtocolUpgradeError>::into)?
1303 {
1304 let is_bid_inactive = validator_bid.inactive();
1305 let has_less_than_validator_minimum =
1306 validator_bid.staked_amount() < U512::from(validator_minimum);
1307 if !is_bid_inactive && has_less_than_validator_minimum {
1308 let inactive_bid = validator_bid.with_inactive(true);
1309 info!("marking bid inactive {validator_bid_key}");
1310 tc.write(
1311 validator_bid_key,
1312 StoredValue::BidKind(BidKind::Validator(Box::new(inactive_bid))),
1313 );
1314 }
1315 }
1316 }
1317
1318 Ok(())
1319 }
1320
1321 pub fn handle_era_info_migration(&mut self) -> Result<(), ProtocolUpgradeError> {
1323 if let Some(activation_point) = self.config.activation_point() {
1325 let highest_era_info_id = activation_point.saturating_sub(1);
1327 let highest_era_info_key = Key::EraInfo(highest_era_info_id);
1328
1329 let get_result = self
1330 .tracking_copy
1331 .get(&highest_era_info_key)
1332 .map_err(ProtocolUpgradeError::TrackingCopy)?;
1333
1334 match get_result {
1335 Some(stored_value @ StoredValue::EraInfo(_)) => {
1336 self.tracking_copy.write(Key::EraSummary, stored_value);
1337 }
1338 Some(other_stored_value) => {
1339 error!(stored_value_type_name=%other_stored_value.type_name(),
1341 "EraInfo key contains unexpected StoredValue variant");
1342 return Err(ProtocolUpgradeError::UnexpectedStoredValueVariant);
1343 }
1344 None => {
1345 }
1349 };
1350 }
1351 Ok(())
1352 }
1353
1354 pub fn handle_seignorage_snapshot_migration(
1356 &mut self,
1357 auction: HashAddr,
1358 ) -> Result<(), ProtocolUpgradeError> {
1359 let auction_named_keys = self.get_named_keys(auction)?;
1360 let maybe_snapshot_version_key =
1361 auction_named_keys.get(SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION_KEY);
1362 let snapshot_key = auction_named_keys
1363 .get(SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY)
1364 .expect("snapshot key should already exist");
1365
1366 if maybe_snapshot_version_key.is_none() {
1368 let auction_addr = EntityAddr::new_system(auction);
1369
1370 let stored_value = StoredValue::CLValue(CLValue::from_t(
1372 DEFAULT_SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION,
1373 )?);
1374 self.system_uref(
1375 auction_addr,
1376 SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION_KEY,
1377 &auction_named_keys,
1378 stored_value,
1379 )?;
1380
1381 if let Some(snapshot_stored_value) = self.tracking_copy.read(snapshot_key)? {
1383 let snapshot_cl_value = match snapshot_stored_value.into_cl_value() {
1384 Some(cl_value) => cl_value,
1385 None => {
1386 error!("seigniorage recipients snapshot is not a CLValue");
1387 return Err(ProtocolUpgradeError::CLValue(
1388 "seigniorage recipients snapshot is not a CLValue".to_string(),
1389 ));
1390 }
1391 };
1392
1393 let legacy_snapshot: SeigniorageRecipientsSnapshotV1 =
1394 snapshot_cl_value.into_t()?;
1395
1396 let mut new_snapshot = SeigniorageRecipientsSnapshotV2::default();
1397 for (era_id, recipients) in legacy_snapshot.into_iter() {
1398 let mut new_recipients = SeigniorageRecipientsV2::default();
1399 for (pubkey, recipient) in recipients {
1400 new_recipients.insert(pubkey, recipient.into());
1401 }
1402 new_snapshot.insert(era_id, new_recipients);
1403 }
1404
1405 self.tracking_copy.write(
1407 *snapshot_key,
1408 StoredValue::CLValue(CLValue::from_t(new_snapshot)?),
1409 );
1410 };
1411 }
1412
1413 Ok(())
1414 }
1415
1416 pub fn handle_global_state_updates(&mut self) {
1418 debug!("handle global state updates");
1419 for (key, value) in self.config.global_state_update() {
1420 self.tracking_copy.write(*key, value.clone());
1421 }
1422 }
1423}