casper_storage/system/handle_payment/
handle_payment_native.rs

1use crate::{
2    global_state::{error::Error as GlobalStateError, state::StateReader},
3    system::{
4        handle_payment::{
5            mint_provider::MintProvider, runtime_provider::RuntimeProvider,
6            storage_provider::StorageProvider, HandlePayment,
7        },
8        mint::Mint,
9        runtime_native::RuntimeNative,
10    },
11    tracking_copy::TrackingCopyEntityExt,
12};
13use casper_types::{
14    account::AccountHash,
15    addressable_entity::{NamedKeyAddr, NamedKeyValue},
16    system::handle_payment::Error,
17    AccessRights, CLValue, FeeHandling, GrantedAccess, Key, Phase, RefundHandling, StoredValue,
18    TransferredTo, URef, U512,
19};
20use std::collections::BTreeSet;
21use tracing::error;
22
23impl<S> MintProvider for RuntimeNative<S>
24where
25    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
26{
27    fn transfer_purse_to_account(
28        &mut self,
29        source: URef,
30        target: AccountHash,
31        amount: U512,
32    ) -> Result<TransferredTo, Error> {
33        let target_key = Key::Account(target);
34        let target_uref = match self.tracking_copy().borrow_mut().read(&target_key) {
35            Ok(Some(StoredValue::CLValue(cl_value))) => {
36                let entity_key = CLValue::into_t::<Key>(cl_value)
37                    .map_err(|_| Error::FailedTransferToAccountPurse)?;
38                // get entity
39                let target_uref = {
40                    if let Ok(Some(StoredValue::AddressableEntity(entity))) =
41                        self.tracking_copy().borrow_mut().read(&entity_key)
42                    {
43                        entity.main_purse_add_only()
44                    } else {
45                        return Err(Error::Transfer);
46                    }
47                };
48                target_uref
49            } // entity exists
50            Ok(Some(StoredValue::Account(account))) => {
51                if self.config().enable_addressable_entity() {
52                    self.tracking_copy()
53                        .borrow_mut()
54                        .migrate_account(target, self.protocol_version())
55                        .map_err(|_| Error::Transfer)?;
56                }
57
58                account.main_purse_add_only()
59            }
60            Ok(_) | Err(_) => return Err(Error::Transfer),
61        };
62
63        // source and target are the same, noop
64        if source.with_access_rights(AccessRights::ADD) == target_uref {
65            return Ok(TransferredTo::ExistingAccount);
66        }
67
68        // Temporarily grant ADD access to target if it is not already present.
69        let granted_access = self.access_rights_mut().grant_access(target_uref);
70
71        let transfered = self
72            .transfer_purse_to_purse(source, target_uref, amount)
73            .is_ok();
74
75        // if ADD access was temporarily granted, remove it.
76        if let GrantedAccess::Granted {
77            uref_addr,
78            newly_granted_access_rights,
79        } = granted_access
80        {
81            self.access_rights_mut()
82                .remove_access(uref_addr, newly_granted_access_rights)
83        }
84
85        if transfered {
86            Ok(TransferredTo::ExistingAccount)
87        } else {
88            Err(Error::Transfer)
89        }
90    }
91
92    fn transfer_purse_to_purse(
93        &mut self,
94        source: URef,
95        target: URef,
96        amount: U512,
97    ) -> Result<(), Error> {
98        // system purses do not have holds on them
99        match self.transfer(None, source, target, amount, None) {
100            Ok(ret) => Ok(ret),
101            Err(err) => {
102                error!("{}", err);
103                Err(Error::Transfer)
104            }
105        }
106    }
107
108    fn available_balance(&mut self, purse: URef) -> Result<Option<U512>, Error> {
109        match <Self as Mint>::balance(self, purse) {
110            Ok(ret) => Ok(ret),
111            Err(err) => {
112                error!("{}", err);
113                Err(Error::GetBalance)
114            }
115        }
116    }
117
118    fn reduce_total_supply(&mut self, amount: U512) -> Result<(), Error> {
119        match <Self as Mint>::reduce_total_supply(self, amount) {
120            Ok(ret) => Ok(ret),
121            Err(err) => {
122                error!("{}", err);
123                Err(Error::ReduceTotalSupply)
124            }
125        }
126    }
127}
128
129impl<S> RuntimeProvider for RuntimeNative<S>
130where
131    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
132{
133    fn get_key(&mut self, name: &str) -> Option<Key> {
134        self.named_keys().get(name).cloned()
135    }
136
137    fn put_key(&mut self, name: &str, key: Key) -> Result<(), Error> {
138        let name = name.to_string();
139        match self.context_key() {
140            Key::Account(_) | Key::Hash(_) => {
141                let name: String = name.clone();
142                let value = CLValue::from_t((name.clone(), key)).map_err(|_| Error::PutKey)?;
143                let named_key_value = StoredValue::CLValue(value);
144                self.tracking_copy()
145                    .borrow_mut()
146                    .add(*self.context_key(), named_key_value)
147                    .map_err(|_| Error::PutKey)?;
148                self.named_keys_mut().insert(name, key);
149                Ok(())
150            }
151            Key::AddressableEntity(entity_addr) => {
152                let named_key_value = StoredValue::NamedKey(
153                    NamedKeyValue::from_concrete_values(key, name.clone())
154                        .map_err(|_| Error::PutKey)?,
155                );
156                let named_key_addr = NamedKeyAddr::new_from_string(*entity_addr, name.clone())
157                    .map_err(|_| Error::PutKey)?;
158                let named_key = Key::NamedKey(named_key_addr);
159                // write to both tracking copy and in-mem named keys cache
160                self.tracking_copy()
161                    .borrow_mut()
162                    .write(named_key, named_key_value);
163                self.named_keys_mut().insert(name, key);
164                Ok(())
165            }
166            _ => Err(Error::UnexpectedKeyVariant),
167        }
168    }
169
170    fn remove_key(&mut self, name: &str) -> Result<(), Error> {
171        self.named_keys_mut().remove(name);
172        match self.context_key() {
173            Key::AddressableEntity(entity_addr) => {
174                let named_key_addr = NamedKeyAddr::new_from_string(*entity_addr, name.to_string())
175                    .map_err(|_| Error::RemoveKey)?;
176                let key = Key::NamedKey(named_key_addr);
177                let value = self
178                    .tracking_copy()
179                    .borrow_mut()
180                    .read(&key)
181                    .map_err(|_| Error::RemoveKey)?;
182                if let Some(StoredValue::NamedKey(_)) = value {
183                    self.tracking_copy().borrow_mut().prune(key);
184                }
185            }
186            Key::Hash(_) => {
187                let mut contract = self
188                    .tracking_copy()
189                    .borrow_mut()
190                    .read(self.context_key())
191                    .map_err(|_| Error::RemoveKey)?
192                    .ok_or(Error::RemoveKey)?
193                    .as_contract()
194                    .ok_or(Error::RemoveKey)?
195                    .clone();
196
197                if contract.remove_named_key(name).is_none() {
198                    return Ok(());
199                }
200
201                self.tracking_copy()
202                    .borrow_mut()
203                    .write(*self.context_key(), StoredValue::Contract(contract))
204            }
205            Key::Account(_) => {
206                let account = {
207                    let mut account = match self
208                        .tracking_copy()
209                        .borrow_mut()
210                        .read(self.context_key())
211                        .map_err(|_| Error::RemoveKey)?
212                    {
213                        Some(StoredValue::Account(account)) => account,
214                        Some(_) | None => return Err(Error::UnexpectedKeyVariant),
215                    };
216                    account.named_keys_mut().remove(name);
217                    account
218                };
219                self.tracking_copy()
220                    .borrow_mut()
221                    .write(*self.context_key(), StoredValue::Account(account));
222            }
223            _ => return Err(Error::UnexpectedKeyVariant),
224        }
225
226        Ok(())
227    }
228
229    fn get_phase(&self) -> Phase {
230        self.phase()
231    }
232
233    fn get_caller(&self) -> AccountHash {
234        self.address()
235    }
236
237    fn refund_handling(&self) -> RefundHandling {
238        *self.config().refund_handling()
239    }
240
241    fn fee_handling(&self) -> FeeHandling {
242        *self.config().fee_handling()
243    }
244
245    fn administrative_accounts(&self) -> BTreeSet<AccountHash> {
246        self.transfer_config().administrative_accounts()
247    }
248}
249
250impl<S> StorageProvider for RuntimeNative<S>
251where
252    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
253{
254    fn write_balance(&mut self, purse_uref: URef, amount: U512) -> Result<(), Error> {
255        let cl_value = CLValue::from_t(amount).map_err(|_| Error::Storage)?;
256        self.tracking_copy().borrow_mut().write(
257            Key::Balance(purse_uref.addr()),
258            StoredValue::CLValue(cl_value),
259        );
260        Ok(())
261    }
262}
263
264impl<S> HandlePayment for RuntimeNative<S> where
265    S: StateReader<Key, StoredValue, Error = GlobalStateError>
266{
267}