casper_execution_engine/runtime/
handle_payment_internal.rs

1use casper_storage::global_state::{error::Error as GlobalStateError, state::StateReader};
2use std::collections::BTreeSet;
3
4use casper_types::{
5    account::AccountHash, addressable_entity::NamedKeyAddr, system::handle_payment::Error, Account,
6    CLValue, Contract, FeeHandling, Key, Phase, RefundHandling, StoredValue, TransferredTo, URef,
7    U512,
8};
9
10use casper_storage::system::handle_payment::{
11    mint_provider::MintProvider, runtime_provider::RuntimeProvider,
12    storage_provider::StorageProvider, HandlePayment,
13};
14
15use crate::{execution::ExecError, runtime::Runtime};
16
17impl From<ExecError> for Option<Error> {
18    fn from(exec_error: ExecError) -> Self {
19        match exec_error {
20            // This is used to propagate [`ExecError::GasLimit`] to make sure
21            // [`HandlePayment`] contract running natively supports propagating gas limit
22            // errors without a panic.
23            ExecError::GasLimit => Some(Error::GasLimit),
24            // There are possibly other exec errors happening but such translation would be lossy.
25            _ => None,
26        }
27    }
28}
29
30impl<R> MintProvider for Runtime<'_, R>
31where
32    R: StateReader<Key, StoredValue, Error = GlobalStateError>,
33{
34    fn transfer_purse_to_account(
35        &mut self,
36        source: URef,
37        target: AccountHash,
38        amount: U512,
39    ) -> Result<TransferredTo, Error> {
40        match self.transfer_from_purse_to_account_hash(source, target, amount, None) {
41            Ok(Ok(transferred_to)) => Ok(transferred_to),
42            Ok(Err(_mint_error)) => Err(Error::Transfer),
43            Err(exec_error) => Err(<Option<Error>>::from(exec_error).unwrap_or(Error::Transfer)),
44        }
45    }
46
47    fn transfer_purse_to_purse(
48        &mut self,
49        source: URef,
50        target: URef,
51        amount: U512,
52    ) -> Result<(), Error> {
53        let contract_hash = match self.get_mint_hash() {
54            Ok(mint_hash) => mint_hash,
55            Err(exec_error) => {
56                return Err(<Option<Error>>::from(exec_error).unwrap_or(Error::Transfer));
57            }
58        };
59        match self.mint_transfer(contract_hash, None, source, target, amount, None) {
60            Ok(Ok(_)) => Ok(()),
61            Ok(Err(_mint_error)) => Err(Error::Transfer),
62            Err(exec_error) => Err(<Option<Error>>::from(exec_error).unwrap_or(Error::Transfer)),
63        }
64    }
65
66    fn available_balance(&mut self, purse: URef) -> Result<Option<U512>, Error> {
67        Runtime::available_balance(self, purse)
68            .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::GetBalance))
69    }
70
71    fn reduce_total_supply(&mut self, amount: U512) -> Result<(), Error> {
72        let contract_hash = match self.get_mint_hash() {
73            Ok(mint_hash) => mint_hash,
74            Err(exec_error) => {
75                return Err(<Option<Error>>::from(exec_error).unwrap_or(Error::Transfer));
76            }
77        };
78        if let Err(exec_error) = self.mint_reduce_total_supply(contract_hash, amount) {
79            Err(<Option<Error>>::from(exec_error).unwrap_or(Error::ReduceTotalSupply))
80        } else {
81            Ok(())
82        }
83    }
84}
85
86impl<R> RuntimeProvider for Runtime<'_, R>
87where
88    R: StateReader<Key, StoredValue, Error = GlobalStateError>,
89{
90    fn get_key(&mut self, name: &str) -> Option<Key> {
91        match self.context.named_keys_get(name).cloned() {
92            None => match self.context.get_context_key() {
93                Key::AddressableEntity(entity_addr) => {
94                    let key = if let Ok(addr) =
95                        NamedKeyAddr::new_from_string(entity_addr, name.to_string())
96                    {
97                        Key::NamedKey(addr)
98                    } else {
99                        return None;
100                    };
101                    if let Ok(Some(StoredValue::NamedKey(value))) = self.context.read_gs(&key) {
102                        value.get_key().ok()
103                    } else {
104                        None
105                    }
106                }
107                Key::Hash(_) => {
108                    match self
109                        .context
110                        .read_gs_typed::<Contract>(&self.context.get_context_key())
111                    {
112                        Ok(contract) => contract.named_keys().get(name).copied(),
113                        Err(_) => None,
114                    }
115                }
116                Key::Account(_) => {
117                    match self
118                        .context
119                        .read_gs_typed::<Account>(&self.context.get_context_key())
120                    {
121                        Ok(account) => account.named_keys().get(name).copied(),
122                        Err(_) => None,
123                    }
124                }
125                _ => None,
126            },
127            Some(key) => Some(key),
128        }
129    }
130
131    fn put_key(&mut self, name: &str, key: Key) -> Result<(), Error> {
132        self.context
133            .put_key(name.to_string(), key)
134            .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::PutKey))
135    }
136
137    fn remove_key(&mut self, name: &str) -> Result<(), Error> {
138        self.context
139            .remove_key(name)
140            .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::RemoveKey))
141    }
142
143    fn get_phase(&self) -> Phase {
144        self.context.phase()
145    }
146
147    fn get_caller(&self) -> AccountHash {
148        self.context.get_initiator()
149    }
150
151    fn refund_handling(&self) -> RefundHandling {
152        self.context.engine_config().refund_handling()
153    }
154
155    fn fee_handling(&self) -> FeeHandling {
156        self.context.engine_config().fee_handling()
157    }
158
159    fn administrative_accounts(&self) -> BTreeSet<AccountHash> {
160        self.context
161            .engine_config()
162            .administrative_accounts()
163            .clone()
164    }
165}
166
167impl<R> StorageProvider for Runtime<'_, R>
168where
169    R: StateReader<Key, StoredValue, Error = GlobalStateError>,
170{
171    fn write_balance(&mut self, purse_uref: URef, amount: U512) -> Result<(), Error> {
172        let cl_amount = CLValue::from_t(amount).map_err(|_| Error::Storage)?;
173        self.context
174            .metered_write_gs_unsafe(Key::Balance(purse_uref.addr()), cl_amount)
175            .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::Storage))?;
176        Ok(())
177    }
178}
179
180impl<R> HandlePayment for Runtime<'_, R> where
181    R: StateReader<Key, StoredValue, Error = GlobalStateError>
182{
183}