casper_storage/tracking_copy/
ext_entity.rs

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/// Fees purse handling.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum FeesPurseHandling {
27    /// Transfer fees to proposer.
28    ToProposer(AccountHash),
29    /// Transfer all fees to a system-wide accumulation purse, for future disbursement.
30    Accumulate,
31    /// Burn all fees from specified purse.
32    Burn(URef),
33    /// No fees are charged.
34    None(URef),
35}
36
37/// Higher-level operations on the state via a `TrackingCopy`.
38pub trait TrackingCopyEntityExt<R> {
39    /// The type for the returned errors.
40    type Error;
41
42    /// Gets a runtime information by entity_addr.
43    fn runtime_footprint_by_entity_addr(
44        &self,
45        entity_addr: EntityAddr,
46    ) -> Result<RuntimeFootprint, Self::Error>;
47
48    /// Gets a runtime information by hash_addr.
49    fn runtime_footprint_by_hash_addr(
50        &mut self,
51        hash_addr: HashAddr,
52    ) -> Result<RuntimeFootprint, Self::Error>;
53
54    /// Gets a runtime information by account hash.
55    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    /// Get runtime information for an account if authorized, else error.
62    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    /// Returns runtime information and access rights if authorized, else error.
71    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    /// Returns runtime information for systemic functionality.
80    fn system_entity_runtime_footprint(
81        &mut self,
82        protocol_version: ProtocolVersion,
83    ) -> Result<(EntityAddr, RuntimeFootprint, ContextAccessRights), TrackingCopyError>;
84
85    /// Migrate the NamedKeys for a entity.
86    fn migrate_named_keys(
87        &mut self,
88        entity_addr: EntityAddr,
89        named_keys: NamedKeys,
90    ) -> Result<(), Self::Error>;
91
92    /// Migrate entry points from and older structure to top level entries.
93    fn migrate_entry_points(
94        &mut self,
95        entity_addr: EntityAddr,
96        entry_points: EntryPoints,
97    ) -> Result<(), Self::Error>;
98
99    /// Upsert uref value to global state and imputed entity's named keys.
100    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    /// Migrate Account to AddressableEntity.
110    fn migrate_account(
111        &mut self,
112        account_hash: AccountHash,
113        protocol_version: ProtocolVersion,
114    ) -> Result<(), Self::Error>;
115
116    /// Create an addressable entity to receive transfer.
117    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    /// Create an addressable entity instance using the field data of an account instance.
125    fn create_addressable_entity_from_account(
126        &mut self,
127        account: Account,
128        protocol_version: ProtocolVersion,
129    ) -> Result<(), Self::Error>;
130
131    /// Migrate ContractPackage to Package.
132    fn migrate_package(
133        &mut self,
134        contract_package_key: Key,
135        protocol_version: ProtocolVersion,
136    ) -> Result<(), Self::Error>;
137
138    /// Returns fee purse.
139    fn fees_purse(
140        &mut self,
141        protocol_version: ProtocolVersion,
142        fees_purse_handling: FeesPurseHandling,
143    ) -> Result<URef, TrackingCopyError>;
144
145    /// Returns named key from selected system contract.
146    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            // Exit early if there's at least a single signature coming from an admin.
401            return Ok((footprint, entity_addr));
402        }
403
404        // Authorize using provided authorization keys
405        if !footprint.can_authorize(authorization_keys) {
406            return Err(Self::Error::Authorization);
407        }
408
409        // Check total key weight against deploy threshold
410        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        // the auction calls the mint for total supply behavior, so extending the context to include
493        // mint named keys & access rights
494        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            // This means the Account does not exist, which we consider to be
615            // an authorization error. As used by the node, this type of deploy
616            // will have already been filtered out, but for other EE use cases
617            // and testing it is reachable.
618            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        // carry forward the account hash to allow reverse lookup
689        let entity_hash = AddressableEntityHash::new(account_hash.value());
690        let entity_addr = EntityAddr::new_account(entity_hash.value());
691
692        // migrate named keys -- if this fails there is no reason to proceed further.
693        let named_keys = account.named_keys().clone();
694        self.migrate_named_keys(entity_addr, named_keys)?;
695
696        // write package first
697        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        // write entity after package
715        {
716            // currently, addressable entities of account kind are not permitted to have bytecode
717            // however, we intend to revisit this and potentially allow it in a future release
718            // as a replacement for stored session.
719            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}