1use std::collections::BTreeSet;
2use tracing::{debug, error};
3
4use casper_types::{
5 account::AccountHash,
6 addressable_entity::{ActionThresholds, AssociatedKeys, NamedKeyAddr, NamedKeyValue, Weight},
7 contracts::{ContractHash, NamedKeys},
8 system::{
9 handle_payment::ACCUMULATION_PURSE_KEY, SystemEntityType, AUCTION, HANDLE_PAYMENT, MINT,
10 },
11 AccessRights, Account, AddressableEntity, AddressableEntityHash, ByteCode, ByteCodeAddr,
12 ByteCodeHash, CLValue, ContextAccessRights, ContractRuntimeTag, EntityAddr, EntityKind,
13 EntityVersions, EntryPointAddr, EntryPointValue, EntryPoints, Groups, HashAddr, Key, Package,
14 PackageHash, PackageStatus, Phase, ProtocolVersion, PublicKey, RuntimeFootprint, StoredValue,
15 StoredValueTypeMismatch, URef, U512,
16};
17
18use crate::{
19 global_state::{error::Error as GlobalStateError, state::StateReader},
20 tracking_copy::{TrackingCopy, TrackingCopyError, TrackingCopyExt},
21 AddressGenerator, KeyPrefix,
22};
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum FeesPurseHandling {
27 ToProposer(AccountHash),
29 Accumulate,
31 Burn(URef),
33 None(URef),
35}
36
37pub trait TrackingCopyEntityExt<R> {
39 type Error;
41
42 fn runtime_footprint_by_entity_addr(
44 &self,
45 entity_addr: EntityAddr,
46 ) -> Result<RuntimeFootprint, Self::Error>;
47
48 fn runtime_footprint_by_hash_addr(
50 &mut self,
51 hash_addr: HashAddr,
52 ) -> Result<RuntimeFootprint, Self::Error>;
53
54 fn runtime_footprint_by_account_hash(
56 &mut self,
57 protocol_version: ProtocolVersion,
58 account_hash: AccountHash,
59 ) -> Result<(EntityAddr, RuntimeFootprint), Self::Error>;
60
61 fn authorized_runtime_footprint_by_account(
63 &mut self,
64 protocol_version: ProtocolVersion,
65 account_hash: AccountHash,
66 authorization_keys: &BTreeSet<AccountHash>,
67 administrative_accounts: &BTreeSet<AccountHash>,
68 ) -> Result<(RuntimeFootprint, EntityAddr), Self::Error>;
69
70 fn authorized_runtime_footprint_with_access_rights(
72 &mut self,
73 protocol_version: ProtocolVersion,
74 initiating_address: AccountHash,
75 authorization_keys: &BTreeSet<AccountHash>,
76 administrative_accounts: &BTreeSet<AccountHash>,
77 ) -> Result<(EntityAddr, RuntimeFootprint, ContextAccessRights), TrackingCopyError>;
78
79 fn system_entity_runtime_footprint(
81 &mut self,
82 protocol_version: ProtocolVersion,
83 ) -> Result<(EntityAddr, RuntimeFootprint, ContextAccessRights), TrackingCopyError>;
84
85 fn migrate_named_keys(
87 &mut self,
88 entity_addr: EntityAddr,
89 named_keys: NamedKeys,
90 ) -> Result<(), Self::Error>;
91
92 fn migrate_entry_points(
94 &mut self,
95 entity_addr: EntityAddr,
96 entry_points: EntryPoints,
97 ) -> Result<(), Self::Error>;
98
99 fn upsert_uref_to_named_keys(
101 &mut self,
102 entity_addr: EntityAddr,
103 name: &str,
104 named_keys: &NamedKeys,
105 uref: URef,
106 stored_value: StoredValue,
107 ) -> Result<(), Self::Error>;
108
109 fn migrate_account(
111 &mut self,
112 account_hash: AccountHash,
113 protocol_version: ProtocolVersion,
114 ) -> Result<(), Self::Error>;
115
116 fn create_new_addressable_entity_on_transfer(
118 &mut self,
119 account_hash: AccountHash,
120 main_purse: URef,
121 protocol_version: ProtocolVersion,
122 ) -> Result<(), Self::Error>;
123
124 fn create_addressable_entity_from_account(
126 &mut self,
127 account: Account,
128 protocol_version: ProtocolVersion,
129 ) -> Result<(), Self::Error>;
130
131 fn migrate_package(
133 &mut self,
134 contract_package_key: Key,
135 protocol_version: ProtocolVersion,
136 ) -> Result<(), Self::Error>;
137
138 fn fees_purse(
140 &mut self,
141 protocol_version: ProtocolVersion,
142 fees_purse_handling: FeesPurseHandling,
143 ) -> Result<URef, TrackingCopyError>;
144
145 fn system_contract_named_key(
147 &mut self,
148 system_contract_name: &str,
149 name: &str,
150 ) -> Result<Option<Key>, Self::Error>;
151}
152
153impl<R> TrackingCopyEntityExt<R> for TrackingCopy<R>
154where
155 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
156{
157 type Error = TrackingCopyError;
158
159 fn runtime_footprint_by_entity_addr(
160 &self,
161 entity_addr: EntityAddr,
162 ) -> Result<RuntimeFootprint, Self::Error> {
163 let entity_key = match entity_addr {
164 EntityAddr::Account(account_addr) => {
165 let account_key = Key::Account(AccountHash::new(account_addr));
166 match self.read(&account_key)? {
167 Some(StoredValue::Account(account)) => {
168 return Ok(RuntimeFootprint::new_account_footprint(account))
169 }
170 Some(StoredValue::CLValue(cl_value)) => cl_value.to_t::<Key>()?,
171 Some(other) => {
172 return Err(TrackingCopyError::TypeMismatch(
173 StoredValueTypeMismatch::new(
174 "Account or Key".to_string(),
175 other.type_name(),
176 ),
177 ))
178 }
179 None => return Err(TrackingCopyError::KeyNotFound(account_key)),
180 }
181 }
182 EntityAddr::SmartContract(addr) | EntityAddr::System(addr) => {
183 let contract_key = Key::Hash(addr);
184 match self.read(&contract_key)? {
185 Some(StoredValue::Contract(contract)) => {
186 let contract_hash = ContractHash::new(entity_addr.value());
187 let maybe_system_entity_type = {
188 let mut ret = None;
189 let registry = self.get_system_entity_registry()?;
190 for (name, hash) in registry.inner().into_iter() {
191 if hash == entity_addr.value() {
192 match name.as_ref() {
193 MINT => ret = Some(SystemEntityType::Mint),
194 AUCTION => ret = Some(SystemEntityType::Auction),
195 HANDLE_PAYMENT => {
196 ret = Some(SystemEntityType::HandlePayment)
197 }
198 _ => continue,
199 }
200 }
201 }
202
203 ret
204 };
205
206 return Ok(RuntimeFootprint::new_contract_footprint(
207 contract_hash,
208 contract,
209 maybe_system_entity_type,
210 ));
211 }
212 Some(StoredValue::CLValue(cl_value)) => cl_value.to_t::<Key>()?,
213 Some(_) | None => Key::AddressableEntity(entity_addr),
214 }
215 }
216 };
217
218 match self.read(&entity_key)? {
219 Some(StoredValue::AddressableEntity(entity)) => {
220 let named_keys = {
221 let keys =
222 self.get_keys_by_prefix(&KeyPrefix::NamedKeysByEntity(entity_addr))?;
223
224 let mut named_keys = NamedKeys::new();
225
226 for entry_key in &keys {
227 match self.read(entry_key)? {
228 Some(StoredValue::NamedKey(named_key)) => {
229 let key =
230 named_key.get_key().map_err(TrackingCopyError::CLValue)?;
231 let name =
232 named_key.get_name().map_err(TrackingCopyError::CLValue)?;
233 named_keys.insert(name, key);
234 }
235 Some(other) => {
236 return Err(TrackingCopyError::TypeMismatch(
237 StoredValueTypeMismatch::new(
238 "CLValue".to_string(),
239 other.type_name(),
240 ),
241 ));
242 }
243 None => match self.cache.reads_cached.get(entry_key) {
244 Some(StoredValue::NamedKey(named_key_value)) => {
245 let key = named_key_value
246 .get_key()
247 .map_err(TrackingCopyError::CLValue)?;
248 let name = named_key_value
249 .get_name()
250 .map_err(TrackingCopyError::CLValue)?;
251 named_keys.insert(name, key);
252 }
253 Some(_) | None => {
254 return Err(TrackingCopyError::KeyNotFound(*entry_key));
255 }
256 },
257 };
258 }
259
260 named_keys
261 };
262 let entry_points = {
263 let keys =
264 self.get_keys_by_prefix(&KeyPrefix::EntryPointsV1ByEntity(entity_addr))?;
265
266 let mut entry_points_v1 = EntryPoints::new();
267
268 for entry_point_key in keys.iter() {
269 match self.read(entry_point_key)? {
270 Some(StoredValue::EntryPoint(EntryPointValue::V1CasperVm(
271 entry_point,
272 ))) => entry_points_v1.add_entry_point(entry_point),
273 Some(other) => {
274 return Err(TrackingCopyError::TypeMismatch(
275 StoredValueTypeMismatch::new(
276 "EntryPointsV1".to_string(),
277 other.type_name(),
278 ),
279 ));
280 }
281 None => match self.cache.reads_cached.get(entry_point_key) {
282 Some(StoredValue::EntryPoint(EntryPointValue::V1CasperVm(
283 entry_point,
284 ))) => entry_points_v1.add_entry_point(entry_point.to_owned()),
285 Some(other) => {
286 return Err(TrackingCopyError::TypeMismatch(
287 StoredValueTypeMismatch::new(
288 "EntryPointsV1".to_string(),
289 other.type_name(),
290 ),
291 ));
292 }
293 None => {
294 return Err(TrackingCopyError::KeyNotFound(*entry_point_key));
295 }
296 },
297 }
298 }
299
300 entry_points_v1
301 };
302 Ok(RuntimeFootprint::new_entity_footprint(
303 entity_addr,
304 entity,
305 named_keys,
306 entry_points,
307 ))
308 }
309 Some(other) => Err(TrackingCopyError::TypeMismatch(
310 StoredValueTypeMismatch::new("AddressableEntity".to_string(), other.type_name()),
311 )),
312 None => Err(TrackingCopyError::KeyNotFound(entity_key)),
313 }
314 }
315
316 fn runtime_footprint_by_hash_addr(
317 &mut self,
318 hash_addr: HashAddr,
319 ) -> Result<RuntimeFootprint, Self::Error> {
320 let entity_addr = if self.get_system_entity_registry()?.exists(&hash_addr) {
321 EntityAddr::new_system(hash_addr)
322 } else {
323 EntityAddr::new_smart_contract(hash_addr)
324 };
325
326 self.runtime_footprint_by_entity_addr(entity_addr)
327 }
328
329 fn runtime_footprint_by_account_hash(
330 &mut self,
331 protocol_version: ProtocolVersion,
332 account_hash: AccountHash,
333 ) -> Result<(EntityAddr, RuntimeFootprint), Self::Error> {
334 let account_key = Key::Account(account_hash);
335
336 let entity_addr = match self.get(&account_key)? {
337 Some(StoredValue::Account(account)) => {
338 if self.enable_addressable_entity {
339 self.create_addressable_entity_from_account(account.clone(), protocol_version)?;
340 }
341
342 let footprint = RuntimeFootprint::new_account_footprint(account);
343 let entity_addr = EntityAddr::new_account(account_hash.value());
344 return Ok((entity_addr, footprint));
345 }
346
347 Some(StoredValue::CLValue(contract_key_as_cl_value)) => {
348 let key = CLValue::into_t::<Key>(contract_key_as_cl_value)?;
349 if let Key::AddressableEntity(addr) = key {
350 addr
351 } else {
352 return Err(Self::Error::UnexpectedKeyVariant(key));
353 }
354 }
355 Some(other) => {
356 return Err(TrackingCopyError::TypeMismatch(
357 StoredValueTypeMismatch::new("Key".to_string(), other.type_name()),
358 ));
359 }
360 None => return Err(TrackingCopyError::KeyNotFound(account_key)),
361 };
362
363 match self.get(&Key::AddressableEntity(entity_addr))? {
364 Some(StoredValue::AddressableEntity(entity)) => {
365 let named_keys = self.get_named_keys(entity_addr)?;
366 let entry_points = self.get_v1_entry_points(entity_addr)?;
367 let runtime_footprint = RuntimeFootprint::new_entity_footprint(
368 entity_addr,
369 entity,
370 named_keys,
371 entry_points,
372 );
373 Ok((entity_addr, runtime_footprint))
374 }
375 Some(other) => Err(TrackingCopyError::TypeMismatch(
376 StoredValueTypeMismatch::new("AddressableEntity".to_string(), other.type_name()),
377 )),
378 None => Err(TrackingCopyError::KeyNotFound(Key::AddressableEntity(
379 entity_addr,
380 ))),
381 }
382 }
383
384 fn authorized_runtime_footprint_by_account(
385 &mut self,
386 protocol_version: ProtocolVersion,
387 account_hash: AccountHash,
388 authorization_keys: &BTreeSet<AccountHash>,
389 administrative_accounts: &BTreeSet<AccountHash>,
390 ) -> Result<(RuntimeFootprint, EntityAddr), Self::Error> {
391 let (entity_addr, footprint) =
392 self.runtime_footprint_by_account_hash(protocol_version, account_hash)?;
393
394 if !administrative_accounts.is_empty()
395 && administrative_accounts
396 .intersection(authorization_keys)
397 .next()
398 .is_some()
399 {
400 return Ok((footprint, entity_addr));
402 }
403
404 if !footprint.can_authorize(authorization_keys) {
406 return Err(Self::Error::Authorization);
407 }
408
409 if !footprint.can_deploy_with(authorization_keys) {
411 return Err(Self::Error::DeploymentAuthorizationFailure);
412 }
413
414 Ok((footprint, entity_addr))
415 }
416
417 fn authorized_runtime_footprint_with_access_rights(
418 &mut self,
419 protocol_version: ProtocolVersion,
420 initiating_address: AccountHash,
421 authorization_keys: &BTreeSet<AccountHash>,
422 administrative_accounts: &BTreeSet<AccountHash>,
423 ) -> Result<(EntityAddr, RuntimeFootprint, ContextAccessRights), TrackingCopyError> {
424 if initiating_address == PublicKey::System.to_account_hash() {
425 return self.system_entity_runtime_footprint(protocol_version);
426 }
427
428 let (footprint, entity_addr) = self.authorized_runtime_footprint_by_account(
429 protocol_version,
430 initiating_address,
431 authorization_keys,
432 administrative_accounts,
433 )?;
434 let access_rights = footprint.extract_access_rights(entity_addr.value());
435 Ok((entity_addr, footprint, access_rights))
436 }
437
438 fn system_entity_runtime_footprint(
439 &mut self,
440 protocol_version: ProtocolVersion,
441 ) -> Result<(EntityAddr, RuntimeFootprint, ContextAccessRights), TrackingCopyError> {
442 let system_account_hash = PublicKey::System.to_account_hash();
443 let (system_entity_addr, mut system_entity) =
444 self.runtime_footprint_by_account_hash(protocol_version, system_account_hash)?;
445
446 let system_entity_registry = self.get_system_entity_registry()?;
447
448 let (auction_named_keys, mut auction_access_rights) = {
449 let auction_hash = match system_entity_registry.get(AUCTION).copied() {
450 Some(auction_hash) => auction_hash,
451 None => {
452 error!("unexpected failure; auction not found");
453 return Err(TrackingCopyError::MissingSystemContractHash(
454 AUCTION.to_string(),
455 ));
456 }
457 };
458 let auction = self.runtime_footprint_by_hash_addr(auction_hash)?;
459 let auction_access_rights = auction.extract_access_rights(auction_hash);
460 (auction.take_named_keys(), auction_access_rights)
461 };
462 let (mint_named_keys, mint_access_rights) = {
463 let mint_hash = match system_entity_registry.get(MINT).copied() {
464 Some(mint_hash) => mint_hash,
465 None => {
466 error!("unexpected failure; mint not found");
467 return Err(TrackingCopyError::MissingSystemContractHash(
468 MINT.to_string(),
469 ));
470 }
471 };
472 let mint = self.runtime_footprint_by_hash_addr(mint_hash)?;
473 let mint_access_rights = mint.extract_access_rights(mint_hash);
474 (mint.take_named_keys(), mint_access_rights)
475 };
476
477 let (payment_named_keys, payment_access_rights) = {
478 let payment_hash = match system_entity_registry.get(HANDLE_PAYMENT).copied() {
479 Some(payment_hash) => payment_hash,
480 None => {
481 error!("unexpected failure; handle payment not found");
482 return Err(TrackingCopyError::MissingSystemContractHash(
483 HANDLE_PAYMENT.to_string(),
484 ));
485 }
486 };
487 let payment = self.runtime_footprint_by_hash_addr(payment_hash)?;
488 let payment_access_rights = payment.extract_access_rights(payment_hash);
489 (payment.take_named_keys(), payment_access_rights)
490 };
491
492 system_entity.named_keys_mut().append(auction_named_keys);
495 system_entity.named_keys_mut().append(mint_named_keys);
496 system_entity.named_keys_mut().append(payment_named_keys);
497
498 auction_access_rights.extend_access_rights(mint_access_rights.take_access_rights());
499 auction_access_rights.extend_access_rights(payment_access_rights.take_access_rights());
500
501 Ok((system_entity_addr, system_entity, auction_access_rights))
502 }
503
504 fn migrate_named_keys(
505 &mut self,
506 entity_addr: EntityAddr,
507 named_keys: NamedKeys,
508 ) -> Result<(), Self::Error> {
509 if !self.enable_addressable_entity {
510 return Err(Self::Error::AddressableEntityDisable);
511 }
512
513 for (string, key) in named_keys.into_inner().into_iter() {
514 let entry_addr = NamedKeyAddr::new_from_string(entity_addr, string.clone())?;
515 let named_key_value =
516 StoredValue::NamedKey(NamedKeyValue::from_concrete_values(key, string.clone())?);
517 let entry_key = Key::NamedKey(entry_addr);
518 self.write(entry_key, named_key_value)
519 }
520
521 Ok(())
522 }
523
524 fn migrate_entry_points(
525 &mut self,
526 entity_addr: EntityAddr,
527 entry_points: EntryPoints,
528 ) -> Result<(), Self::Error> {
529 if !self.enable_addressable_entity {
530 return Err(Self::Error::AddressableEntityDisable);
531 }
532
533 if entry_points.is_empty() {
534 return Ok(());
535 }
536 for entry_point in entry_points.take_entry_points().into_iter() {
537 let entry_point_addr =
538 EntryPointAddr::new_v1_entry_point_addr(entity_addr, entry_point.name())?;
539 let entry_point_value =
540 StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point));
541 self.write(Key::EntryPoint(entry_point_addr), entry_point_value)
542 }
543
544 Ok(())
545 }
546
547 fn upsert_uref_to_named_keys(
548 &mut self,
549 entity_addr: EntityAddr,
550 name: &str,
551 named_keys: &NamedKeys,
552 uref: URef,
553 stored_value: StoredValue,
554 ) -> Result<(), Self::Error> {
555 match named_keys.get(name) {
556 Some(key) => {
557 if let Key::URef(_) = key {
558 self.write(*key, stored_value);
559 } else {
560 return Err(Self::Error::UnexpectedKeyVariant(*key));
561 }
562 }
563 None => {
564 let uref_key = Key::URef(uref).normalize();
565 self.write(uref_key, stored_value);
566
567 if self.enable_addressable_entity {
568 let entry_value = {
569 let named_key_value =
570 NamedKeyValue::from_concrete_values(uref_key, name.to_string())
571 .map_err(Self::Error::CLValue)?;
572 StoredValue::NamedKey(named_key_value)
573 };
574 let entry_key = {
575 let named_key_entry =
576 NamedKeyAddr::new_from_string(entity_addr, name.to_string())
577 .map_err(Self::Error::BytesRepr)?;
578 Key::NamedKey(named_key_entry)
579 };
580
581 self.write(entry_key, entry_value);
582 } else {
583 let named_key_value = StoredValue::CLValue(CLValue::from_t((name, uref_key))?);
584 let base_key = match entity_addr {
585 EntityAddr::System(hash_addr) | EntityAddr::SmartContract(hash_addr) => {
586 Key::Hash(hash_addr)
587 }
588 EntityAddr::Account(addr) => Key::Account(AccountHash::new(addr)),
589 };
590 self.add(base_key, named_key_value)?;
591 }
592 }
593 };
594 Ok(())
595 }
596
597 fn migrate_account(
598 &mut self,
599 account_hash: AccountHash,
600 protocol_version: ProtocolVersion,
601 ) -> Result<(), Self::Error> {
602 if !self.enable_addressable_entity {
603 debug!("ae is not enabled, skipping migration");
604 return Ok(());
605 }
606 let key = Key::Account(account_hash);
607 let maybe_stored_value = self.read(&key)?;
608
609 match maybe_stored_value {
610 Some(StoredValue::Account(account)) => {
611 self.create_addressable_entity_from_account(account, protocol_version)
612 }
613 Some(StoredValue::CLValue(_)) => Ok(()),
614 Some(_) => Err(Self::Error::UnexpectedStoredValueVariant),
619 None => Err(Self::Error::AccountNotFound(key)),
620 }
621 }
622
623 fn create_new_addressable_entity_on_transfer(
624 &mut self,
625 account_hash: AccountHash,
626 main_purse: URef,
627 protocol_version: ProtocolVersion,
628 ) -> Result<(), Self::Error> {
629 let mut generator = AddressGenerator::new(main_purse.addr().as_ref(), Phase::System);
630
631 let byte_code_hash = ByteCodeHash::default();
632 let entity_hash = AddressableEntityHash::new(account_hash.value());
633 let package_hash = PackageHash::new(generator.new_hash_address());
634
635 let associated_keys = AssociatedKeys::new(account_hash, Weight::new(1));
636
637 let action_thresholds: ActionThresholds = Default::default();
638
639 let entity = AddressableEntity::new(
640 package_hash,
641 byte_code_hash,
642 protocol_version,
643 main_purse,
644 associated_keys,
645 action_thresholds,
646 EntityKind::Account(account_hash),
647 );
648
649 let entity_addr = EntityAddr::new_account(entity_hash.value());
650 let package = {
651 let mut package = Package::new(
652 EntityVersions::default(),
653 BTreeSet::default(),
654 Groups::default(),
655 PackageStatus::Locked,
656 );
657 package.insert_entity_version(protocol_version.value().major, entity_addr);
658 package
659 };
660
661 let entity_key = Key::AddressableEntity(entity_addr);
662
663 self.write(entity_key, entity.into());
664 self.write(package_hash.into(), package.into());
665 let contract_by_account = match CLValue::from_t(entity_key) {
666 Ok(cl_value) => cl_value,
667 Err(err) => return Err(Self::Error::CLValue(err)),
668 };
669
670 self.write(
671 Key::Account(account_hash),
672 StoredValue::CLValue(contract_by_account),
673 );
674 Ok(())
675 }
676
677 fn create_addressable_entity_from_account(
678 &mut self,
679 account: Account,
680 protocol_version: ProtocolVersion,
681 ) -> Result<(), Self::Error> {
682 let account_hash = account.account_hash();
683 if !self.enable_addressable_entity {
684 self.write(Key::Account(account_hash), StoredValue::Account(account));
685 return Ok(());
686 }
687
688 let entity_hash = AddressableEntityHash::new(account_hash.value());
690 let entity_addr = EntityAddr::new_account(entity_hash.value());
691
692 let named_keys = account.named_keys().clone();
694 self.migrate_named_keys(entity_addr, named_keys)?;
695
696 let package_hash = {
698 let mut generator =
699 AddressGenerator::new(account.main_purse().addr().as_ref(), Phase::System);
700
701 let package_hash = PackageHash::new(generator.new_hash_address());
702
703 let mut package = Package::new(
704 EntityVersions::default(),
705 BTreeSet::default(),
706 Groups::default(),
707 PackageStatus::Locked,
708 );
709 package.insert_entity_version(protocol_version.value().major, entity_addr);
710 self.write(package_hash.into(), package.into());
711 package_hash
712 };
713
714 {
716 let byte_code_hash = ByteCodeHash::default();
720
721 let action_thresholds = {
722 let account_threshold = account.action_thresholds().clone();
723 ActionThresholds::new(
724 Weight::new(account_threshold.deployment.value()),
725 Weight::new(1u8),
726 Weight::new(account_threshold.key_management.value()),
727 )
728 .map_err(Self::Error::SetThresholdFailure)?
729 };
730
731 let associated_keys = AssociatedKeys::from(account.associated_keys().clone());
732
733 let entity = AddressableEntity::new(
734 package_hash,
735 byte_code_hash,
736 protocol_version,
737 account.main_purse(),
738 associated_keys,
739 action_thresholds,
740 EntityKind::Account(account_hash),
741 );
742 let entity_key = entity.entity_key(entity_hash);
743 let contract_by_account = match CLValue::from_t(entity_key) {
744 Ok(cl_value) => cl_value,
745 Err(err) => return Err(Self::Error::CLValue(err)),
746 };
747
748 self.write(entity_key, entity.into());
749 self.write(
750 Key::Account(account_hash),
751 StoredValue::CLValue(contract_by_account),
752 );
753 }
754
755 Ok(())
756 }
757
758 fn migrate_package(
759 &mut self,
760 legacy_package_key: Key,
761 protocol_version: ProtocolVersion,
762 ) -> Result<(), Self::Error> {
763 if !self.enable_addressable_entity {
764 return Err(Self::Error::AddressableEntityDisable);
765 }
766
767 let legacy_package = match self.read(&legacy_package_key)? {
768 Some(StoredValue::ContractPackage(legacy_package)) => legacy_package,
769 Some(_) | None => {
770 return Err(Self::Error::ValueNotFound(format!(
771 "contract package not found {}",
772 legacy_package_key
773 )));
774 }
775 };
776
777 let legacy_versions = legacy_package.versions().clone();
778 let access_uref = legacy_package.access_key();
779 let mut generator = AddressGenerator::new(access_uref.addr().as_ref(), Phase::System);
780
781 let package: Package = legacy_package.into();
782
783 for (_, contract_hash) in legacy_versions.into_iter() {
784 let contract = match self.read(&Key::Hash(contract_hash.value()))? {
785 Some(StoredValue::Contract(legacy_contract)) => legacy_contract,
786 Some(_) | None => {
787 return Err(Self::Error::ValueNotFound(format!(
788 "contract not found {}",
789 contract_hash
790 )));
791 }
792 };
793
794 let purse = generator.new_uref(AccessRights::all());
795 let cl_value: CLValue = CLValue::from_t(()).map_err(Self::Error::CLValue)?;
796 self.write(Key::URef(purse), StoredValue::CLValue(cl_value));
797
798 let balance_value: CLValue =
799 CLValue::from_t(U512::zero()).map_err(Self::Error::CLValue)?;
800 self.write(
801 Key::Balance(purse.addr()),
802 StoredValue::CLValue(balance_value),
803 );
804
805 let contract_addr = EntityAddr::new_smart_contract(contract_hash.value());
806
807 let contract_wasm_hash = contract.contract_wasm_hash();
808
809 let updated_entity = AddressableEntity::new(
810 PackageHash::new(contract.contract_package_hash().value()),
811 ByteCodeHash::new(contract_wasm_hash.value()),
812 protocol_version,
813 purse,
814 AssociatedKeys::default(),
815 ActionThresholds::default(),
816 EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1),
817 );
818
819 let entry_points = contract.entry_points().clone();
820 let named_keys = contract.take_named_keys();
821
822 self.migrate_named_keys(contract_addr, named_keys)?;
823 self.migrate_entry_points(contract_addr, entry_points.into())?;
824
825 let maybe_previous_wasm = self
826 .read(&Key::Hash(contract_wasm_hash.value()))?
827 .and_then(|stored_value| stored_value.into_contract_wasm());
828
829 match maybe_previous_wasm {
830 None => {
831 return Err(Self::Error::ValueNotFound(format!(
832 "{}",
833 contract_wasm_hash
834 )));
835 }
836 Some(contract_wasm) => {
837 let byte_code_key = Key::byte_code_key(ByteCodeAddr::new_wasm_addr(
838 updated_entity.byte_code_addr(),
839 ));
840 let byte_code_cl_value = match CLValue::from_t(byte_code_key) {
841 Ok(cl_value) => cl_value,
842 Err(err) => return Err(Self::Error::CLValue(err)),
843 };
844 self.write(
845 Key::Hash(updated_entity.byte_code_addr()),
846 StoredValue::CLValue(byte_code_cl_value),
847 );
848
849 let byte_code: ByteCode = contract_wasm.into();
850 self.write(byte_code_key, StoredValue::ByteCode(byte_code));
851 }
852 }
853
854 let entity_hash = AddressableEntityHash::new(contract_hash.value());
855 let entity_key = Key::contract_entity_key(entity_hash);
856 let indirection = match CLValue::from_t(entity_key) {
857 Ok(cl_value) => cl_value,
858 Err(err) => return Err(Self::Error::CLValue(err)),
859 };
860 self.write(
861 Key::Hash(contract_hash.value()),
862 StoredValue::CLValue(indirection),
863 );
864
865 self.write(entity_key, StoredValue::AddressableEntity(updated_entity));
866 }
867
868 let package_key = Key::SmartContract(
869 legacy_package_key
870 .into_hash_addr()
871 .ok_or(Self::Error::UnexpectedKeyVariant(legacy_package_key))?,
872 );
873
874 let access_key_value =
875 CLValue::from_t((package_key, access_uref)).map_err(Self::Error::CLValue)?;
876 self.write(legacy_package_key, StoredValue::CLValue(access_key_value));
877 self.write(package_key, StoredValue::SmartContract(package));
878 Ok(())
879 }
880
881 fn fees_purse(
882 &mut self,
883 protocol_version: ProtocolVersion,
884 fees_purse_handling: FeesPurseHandling,
885 ) -> Result<URef, TrackingCopyError> {
886 let fee_handling = fees_purse_handling;
887 match fee_handling {
888 FeesPurseHandling::None(uref) => Ok(uref),
889 FeesPurseHandling::ToProposer(proposer) => {
890 let (_, entity) =
891 self.runtime_footprint_by_account_hash(protocol_version, proposer)?;
892 Ok(entity
893 .main_purse()
894 .ok_or(TrackingCopyError::AddressableEntityDisable)?)
895 }
896 FeesPurseHandling::Accumulate => {
897 let registry = self.get_system_entity_registry()?;
898 let entity_addr = {
899 let hash = match registry.get(HANDLE_PAYMENT) {
900 Some(hash) => hash,
901 None => {
902 return Err(TrackingCopyError::MissingSystemContractHash(
903 HANDLE_PAYMENT.to_string(),
904 ));
905 }
906 };
907 EntityAddr::new_system(*hash)
908 };
909
910 let named_keys = self.get_named_keys(entity_addr)?;
911
912 let accumulation_purse_uref = match named_keys.get(ACCUMULATION_PURSE_KEY) {
913 Some(Key::URef(accumulation_purse)) => *accumulation_purse,
914 Some(_) | None => {
915 error!(
916 "fee handling is configured to accumulate but handle payment does not \
917 have accumulation purse"
918 );
919 return Err(TrackingCopyError::NamedKeyNotFound(
920 ACCUMULATION_PURSE_KEY.to_string(),
921 ));
922 }
923 };
924
925 Ok(accumulation_purse_uref)
926 }
927 FeesPurseHandling::Burn(uref) => Ok(uref),
928 }
929 }
930
931 fn system_contract_named_key(
932 &mut self,
933 system_contract_name: &str,
934 name: &str,
935 ) -> Result<Option<Key>, Self::Error> {
936 let system_entity_registry = self.get_system_entity_registry()?;
937 let hash = match system_entity_registry.get(system_contract_name).copied() {
938 Some(hash) => hash,
939 None => {
940 error!(
941 "unexpected failure; system contract {} not found",
942 system_contract_name
943 );
944 return Err(TrackingCopyError::MissingSystemContractHash(
945 system_contract_name.to_string(),
946 ));
947 }
948 };
949 let runtime_footprint = self.runtime_footprint_by_hash_addr(hash)?;
950 Ok(runtime_footprint.take_named_keys().get(name).copied())
951 }
952}