Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit e04da97

Browse files
committed
contracts: Charge rent for code storage [WIP]
1 parent 63da288 commit e04da97

File tree

5 files changed

+48
-49
lines changed

5 files changed

+48
-49
lines changed

frame/contracts/src/exec.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,17 @@ where
269269
Err(Error::<T>::MaxCallDepthReached)?
270270
}
271271

272+
let contract = <ContractInfoOf<T>>::get(&dest)
273+
.and_then(|contract| contract.get_alive())
274+
.ok_or(Error::<T>::NotCallable)?;
275+
272276
// This charges the rent and denies access to a contract that is in need of
273277
// eviction by returning `None`. We cannot evict eagerly here because those
274278
// changes would be rolled back in case this contract is called by another
275279
// contract.
276280
// See: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324
277-
let contract = if let Ok(Some(ContractInfo::Alive(info))) = Rent::<T>::charge(&dest) {
278-
info
279-
} else {
280-
Err(Error::<T>::NotCallable)?
281-
};
281+
let contract = Rent::<T>::charge(&dest, contract)?
282+
.ok_or(Error::<T>::NotCallable)?;
282283

283284
let transactor_kind = self.transactor_kind();
284285
let caller = self.self_account.clone();
@@ -360,9 +361,12 @@ where
360361
// This also makes sure that it is above the subsistence threshold
361362
// in order to keep up the guarantuee that we always leave a tombstone behind
362363
// with the exception of a contract that called `seal_terminate`.
363-
Rent::<T>::charge(&dest)?
364-
.and_then(|c| c.get_alive())
365-
.ok_or_else(|| Error::<T>::NewContractNotFunded)?;
364+
<ContractInfoOf<T>>::get(&dest)
365+
.and_then(|contract| contract.get_alive())
366+
.map(|contract| Rent::<T>::charge(&dest, contract))
367+
.transpose()?
368+
.flatten()
369+
.ok_or(Error::<T>::NewContractNotFunded)?;
366370

367371
// Deposit an instantiation event.
368372
deposit_event::<T>(vec![], RawEvent::Instantiated(caller.clone(), dest.clone()));

frame/contracts/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ decl_error! {
432432
/// This can either happen when the accumulated storage in bytes is too large or
433433
/// when number of storage items is too large.
434434
StorageExhausted,
435+
/// A contract with the same AccountId already exists.
436+
DuplicateContract,
435437
}
436438
}
437439

frame/contracts/src/rent.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ where
234234
current_block_number: T::BlockNumber,
235235
verdict: Verdict<T>,
236236
allow_eviction: bool,
237-
) -> Result<Option<ContractInfo<T>>, DispatchError> {
237+
) -> Result<Option<AliveContractInfo<T>>, DispatchError> {
238238
match verdict {
239-
Verdict::Exempt => return Ok(Some(ContractInfo::Alive(alive_contract_info))),
239+
Verdict::Exempt => return Ok(Some(alive_contract_info)),
240240
Verdict::Evict { amount: _ } if !allow_eviction => {
241241
Ok(None)
242242
}
@@ -263,18 +263,18 @@ where
263263
<ContractInfoOf<T>>::insert(account, &tombstone_info);
264264
crate::wasm::remove_code_user::<T>(alive_contract_info.code_hash);
265265
<Module<T>>::deposit_event(RawEvent::Evicted(account.clone(), true));
266-
Ok(Some(tombstone_info))
266+
Ok(None)
267267
}
268268
Verdict::Charge { amount } => {
269-
let contract_info = ContractInfo::Alive(AliveContractInfo::<T> {
269+
let contract = ContractInfo::Alive(AliveContractInfo::<T> {
270270
rent_allowance: alive_contract_info.rent_allowance - amount.peek(),
271271
deduct_block: current_block_number,
272272
rent_payed: alive_contract_info.rent_payed.saturating_add(amount.peek()),
273273
..alive_contract_info
274274
});
275-
<ContractInfoOf<T>>::insert(account, &contract_info);
275+
<ContractInfoOf<T>>::insert(account, &contract);
276276
amount.withdraw(account);
277-
Ok(Some(contract_info))
277+
Ok(Some(contract.get_alive().expect("We just constructed it as alive. qed")))
278278
}
279279
}
280280
}
@@ -284,21 +284,15 @@ where
284284
/// This functions does **not** evict the contract. It returns `None` in case the
285285
/// contract is in need of eviction. [`try_eviction`] must
286286
/// be called to perform the eviction.
287-
pub fn charge(account: &T::AccountId) -> Result<Option<ContractInfo<T>>, DispatchError> {
288-
let contract_info = <ContractInfoOf<T>>::get(account);
289-
let alive_contract_info = match contract_info {
290-
None | Some(ContractInfo::Tombstone(_)) => return Ok(contract_info),
291-
Some(ContractInfo::Alive(contract)) => contract,
292-
};
293-
287+
pub fn charge(account: &T::AccountId, contract: AliveContractInfo<T>) -> Result<Option<AliveContractInfo<T>>, DispatchError> {
294288
let current_block_number = <frame_system::Module<T>>::block_number();
295289
let verdict = Self::consider_case(
296290
account,
297291
current_block_number,
298292
Zero::zero(),
299-
&alive_contract_info,
293+
&contract,
300294
);
301-
Self::enact_verdict(account, alive_contract_info, current_block_number, verdict, false)
295+
Self::enact_verdict(account, contract, current_block_number, verdict, false)
302296
}
303297

304298
/// Process a report that a contract under the given address should be evicted.
@@ -380,8 +374,8 @@ where
380374

381375
// Check what happened after enaction of the verdict.
382376
let alive_contract_info = match new_contract_info.map_err(|_| IsTombstone)? {
383-
None | Some(ContractInfo::Tombstone(_)) => return Err(IsTombstone),
384-
Some(ContractInfo::Alive(contract)) => contract,
377+
None => return Err(IsTombstone),
378+
Some(contract) => contract,
385379
};
386380

387381
// Compute how much would the fee per block be with the *updated* balance.

frame/contracts/src/storage.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -164,31 +164,30 @@ where
164164
account: &AccountIdOf<T>,
165165
trie_id: TrieId,
166166
ch: CodeHash<T>,
167-
) -> Result<(), &'static str> {
168-
<ContractInfoOf<T>>::mutate(account, |maybe_contract_info| {
169-
if maybe_contract_info.is_some() {
170-
return Err("Alive contract or tombstone already exists");
167+
) -> Result<AliveContractInfo<T>, &'static str> {
168+
<ContractInfoOf<T>>::try_mutate(account, |existing| {
169+
if existing.is_some() {
170+
return Err(Error::<T>::DuplicateContract.into());
171171
}
172172

173-
*maybe_contract_info = Some(
174-
AliveContractInfo::<T> {
175-
code_hash: ch,
176-
storage_size: 0,
177-
trie_id,
178-
deduct_block:
179-
// We want to charge rent for the first block in advance. Therefore we
180-
// treat the contract as if it was created in the last block and then
181-
// charge rent for it during instantation.
182-
<frame_system::Module<T>>::block_number().saturating_sub(1u32.into()),
183-
rent_allowance: <BalanceOf<T>>::max_value(),
184-
rent_payed: <BalanceOf<T>>::zero(),
185-
pair_count: 0,
186-
last_write: None,
187-
}
188-
.into(),
189-
);
190-
191-
Ok(())
173+
let contract = AliveContractInfo::<T> {
174+
code_hash: ch,
175+
storage_size: 0,
176+
trie_id,
177+
deduct_block:
178+
// We want to charge rent for the first block in advance. Therefore we
179+
// treat the contract as if it was created in the last block and then
180+
// charge rent for it during instantation.
181+
<frame_system::Module<T>>::block_number().saturating_sub(1u32.into()),
182+
rent_allowance: <BalanceOf<T>>::max_value(),
183+
rent_payed: <BalanceOf<T>>::zero(),
184+
pair_count: 0,
185+
last_write: None,
186+
};
187+
188+
*existing = Some(contract.clone().into());
189+
190+
Ok(contract)
192191
})
193192
}
194193

frame/contracts/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ pub mod test_utils {
9393
pub fn place_contract(address: &AccountIdOf<Test>, code_hash: CodeHash<Test>) {
9494
let trie_id = Storage::<Test>::generate_trie_id(address);
9595
set_balance(address, ConfigCache::<Test>::subsistence_threshold_uncached() * 10);
96-
Storage::<Test>::place_contract(&address, trie_id, code_hash).unwrap()
96+
Storage::<Test>::place_contract(&address, trie_id, code_hash).unwrap();
9797
}
9898
pub fn set_balance(who: &AccountIdOf<Test>, amount: u64) {
9999
let imbalance = Balances::deposit_creating(who, amount);

0 commit comments

Comments
 (0)