casper_storage/system/mint/
mint_native.rs1use 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 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 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 if let StoredValue::CLValue(value) = stored_value {
144 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 if !uref.is_writeable() {
156 return Err(Error::Storage);
157 }
158 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 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}