casper_storage/system/mint/
mint_native.rs

1use tracing::error;
2
3use crate::{
4    global_state::{error::Error as GlobalStateError, state::StateReader},
5    system::{
6        error::ProviderError,
7        mint::{
8            runtime_provider::RuntimeProvider, storage_provider::StorageProvider,
9            system_provider::SystemProvider, Mint,
10        },
11        runtime_native::{Id, RuntimeNative},
12    },
13    tracking_copy::{TrackingCopyEntityExt, TrackingCopyExt},
14};
15use casper_types::{
16    account::AccountHash,
17    bytesrepr::{FromBytes, ToBytes},
18    system::{mint::Error, Caller},
19    AccessRights, CLTyped, CLValue, Gas, InitiatorAddr, Key, Phase, PublicKey, RuntimeFootprint,
20    StoredValue, SystemHashRegistry, Transfer, TransferV2, URef, U512,
21};
22
23impl<S> RuntimeProvider for RuntimeNative<S>
24where
25    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
26{
27    fn get_caller(&self) -> AccountHash {
28        self.address()
29    }
30
31    fn get_immediate_caller(&self) -> Option<Caller> {
32        let caller = Caller::Initiator {
33            account_hash: PublicKey::System.to_account_hash(),
34        };
35        Some(caller)
36    }
37
38    fn is_called_from_standard_payment(&self) -> bool {
39        self.phase() == Phase::Payment
40    }
41
42    fn get_system_entity_registry(&self) -> Result<SystemHashRegistry, ProviderError> {
43        self.tracking_copy()
44            .borrow_mut()
45            .get_system_entity_registry()
46            .map_err(|tce| {
47                error!(%tce, "unable to obtain system entity registry during transfer");
48                ProviderError::SystemEntityRegistry
49            })
50    }
51
52    fn runtime_footprint_by_account_hash(
53        &mut self,
54        account_hash: AccountHash,
55    ) -> Result<Option<RuntimeFootprint>, ProviderError> {
56        match self
57            .tracking_copy()
58            .borrow_mut()
59            .runtime_footprint_by_account_hash(self.protocol_version(), account_hash)
60        {
61            Ok((_, footprint)) => Ok(Some(footprint)),
62            Err(tce) => {
63                error!(%tce, "error reading addressable entity by account hash");
64                Err(ProviderError::AccountHash(account_hash))
65            }
66        }
67    }
68
69    fn get_phase(&self) -> Phase {
70        self.phase()
71    }
72
73    fn get_key(&self, name: &str) -> Option<Key> {
74        self.named_keys().get(name).cloned()
75    }
76
77    fn get_approved_spending_limit(&self) -> U512 {
78        self.remaining_spending_limit()
79    }
80
81    fn sub_approved_spending_limit(&mut self, amount: U512) {
82        if let Some(remaining) = self.remaining_spending_limit().checked_sub(amount) {
83            self.set_remaining_spending_limit(remaining);
84        } else {
85            error!(
86                limit = %self.remaining_spending_limit(),
87                spent = %amount,
88                "exceeded main purse spending limit"
89            );
90            self.set_remaining_spending_limit(U512::zero());
91        }
92    }
93
94    fn get_main_purse(&self) -> Option<URef> {
95        self.runtime_footprint().main_purse()
96    }
97
98    fn is_administrator(&self, account_hash: &AccountHash) -> bool {
99        self.transfer_config().is_administrator(account_hash)
100    }
101
102    fn allow_unrestricted_transfers(&self) -> bool {
103        self.transfer_config().allow_unrestricted_transfers()
104    }
105
106    fn is_valid_uref(&self, uref: &URef) -> bool {
107        self.access_rights().has_access_rights_to_uref(uref)
108    }
109}
110
111impl<S> StorageProvider for RuntimeNative<S>
112where
113    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
114{
115    fn new_uref<T: CLTyped + ToBytes>(&mut self, value: T) -> Result<URef, Error> {
116        let cl_value: CLValue = CLValue::from_t(value).map_err(|_| Error::CLValue)?;
117        let uref = self
118            .address_generator()
119            .write()
120            .new_uref(AccessRights::READ_ADD_WRITE);
121        self.extend_access_rights(&[uref]);
122        // we are creating this key now, thus we know it is a Key::URef and we grant the creator
123        // full permissions on it, thus we do not need to do validate key / validate uref access
124        // before storing it.
125        self.tracking_copy()
126            .borrow_mut()
127            .write(Key::URef(uref), StoredValue::CLValue(cl_value));
128        Ok(uref)
129    }
130
131    fn read<T: CLTyped + FromBytes>(&mut self, uref: URef) -> Result<Option<T>, Error> {
132        // check access rights on uref
133        if !self.access_rights().has_access_rights_to_uref(&uref) {
134            return Err(Error::ForgedReference);
135        }
136        let key = &Key::URef(uref);
137        let stored_value = match self.tracking_copy().borrow_mut().read(key) {
138            Ok(Some(stored_value)) => stored_value,
139            Ok(None) => return Ok(None),
140            Err(_) => return Err(Error::Storage),
141        };
142        // by convention, we only store CLValues under Key::URef
143        if let StoredValue::CLValue(value) = stored_value {
144            // Only CLTyped instances should be stored as a CLValue.
145            let value = CLValue::into_t(value).map_err(|_| Error::CLValue)?;
146            Ok(Some(value))
147        } else {
148            Err(Error::CLValue)
149        }
150    }
151
152    fn write_amount(&mut self, uref: URef, amount: U512) -> Result<(), Error> {
153        let cl_value = CLValue::from_t(amount).map_err(|_| Error::CLValue)?;
154        // is the uref writeable?
155        if !uref.is_writeable() {
156            return Err(Error::Storage);
157        }
158        // check access rights on uref
159        if !self.access_rights().has_access_rights_to_uref(&uref) {
160            return Err(Error::ForgedReference);
161        }
162        self.tracking_copy()
163            .borrow_mut()
164            .write(Key::URef(uref), StoredValue::CLValue(cl_value));
165        Ok(())
166    }
167
168    fn add<T: CLTyped + ToBytes>(&mut self, uref: URef, value: T) -> Result<(), Error> {
169        let cl_value = CLValue::from_t(value).map_err(|_| Error::CLValue)?;
170        self.tracking_copy()
171            .borrow_mut()
172            .add(Key::URef(uref), StoredValue::CLValue(cl_value))
173            .map_err(|_| Error::Storage)?;
174        Ok(())
175    }
176
177    fn total_balance(&mut self, purse: URef) -> Result<U512, Error> {
178        match self
179            .tracking_copy()
180            .borrow_mut()
181            .get_total_balance(purse.into())
182        {
183            Ok(total) => Ok(total.value()),
184            Err(err) => {
185                error!(?err, "mint native total_balance");
186                dbg!(&err);
187                Err(Error::Storage)
188            }
189        }
190    }
191
192    fn available_balance(&mut self, purse: URef) -> Result<Option<U512>, Error> {
193        match self
194            .tracking_copy()
195            .borrow_mut()
196            .get_available_balance(Key::Balance(purse.addr()))
197        {
198            Ok(motes) => Ok(Some(motes.value())),
199            Err(err) => {
200                error!(?err, "mint native available_balance");
201                Err(Error::Storage)
202            }
203        }
204    }
205
206    fn write_balance(&mut self, uref: URef, balance: U512) -> Result<(), Error> {
207        let cl_value = CLValue::from_t(balance).map_err(|_| Error::CLValue)?;
208        self.tracking_copy()
209            .borrow_mut()
210            .write(Key::Balance(uref.addr()), StoredValue::CLValue(cl_value));
211        Ok(())
212    }
213
214    fn add_balance(&mut self, uref: URef, value: U512) -> Result<(), Error> {
215        let cl_value = CLValue::from_t(value).map_err(|_| Error::CLValue)?;
216        self.tracking_copy()
217            .borrow_mut()
218            .add(Key::Balance(uref.addr()), StoredValue::CLValue(cl_value))
219            .map_err(|_| Error::Storage)?;
220        Ok(())
221    }
222}
223
224impl<S> SystemProvider for RuntimeNative<S>
225where
226    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
227{
228    fn record_transfer(
229        &mut self,
230        maybe_to: Option<AccountHash>,
231        source: URef,
232        target: URef,
233        amount: U512,
234        id: Option<u64>,
235    ) -> Result<(), Error> {
236        if self.phase() != Phase::Session {
237            return Ok(());
238        }
239        let txn_hash = match self.id() {
240            Id::Transaction(txn_hash) => *txn_hash,
241            // we don't write transfer records for systemic transfers (step, fees, rewards, etc)
242            // so return Ok and move on.
243            Id::Seed(_) => return Ok(()),
244        };
245        let from = InitiatorAddr::AccountHash(self.get_caller());
246        let fee = Gas::from(self.native_transfer_cost());
247        let transfer = Transfer::V2(TransferV2::new(
248            txn_hash, from, maybe_to, source, target, amount, fee, id,
249        ));
250
251        self.push_transfer(transfer);
252
253        Ok(())
254    }
255}
256
257impl<S> Mint for RuntimeNative<S>
258where
259    S: StateReader<Key, StoredValue, Error = GlobalStateError>,
260{
261    fn purse_exists(&mut self, uref: URef) -> Result<bool, Error> {
262        let key = Key::Balance(uref.addr());
263        match self
264            .tracking_copy()
265            .borrow_mut()
266            .read(&key)
267            .map_err(|_| Error::Storage)?
268        {
269            Some(StoredValue::CLValue(value)) => Ok(*value.cl_type() == U512::cl_type()),
270            Some(_non_cl_value) => Err(Error::CLValue),
271            None => Ok(false),
272        }
273    }
274}