@@ -35,6 +35,49 @@ use sp_runtime::{
35
35
traits:: { Bounded , CheckedDiv , CheckedMul , SaturatedConversion , Saturating , Zero } ,
36
36
} ;
37
37
38
+ /// Information about the required deposit and resulting rent.
39
+ ///
40
+ /// The easiest way to guarantee that a contract stays alive is to assert that
41
+ /// `max_rent == 0` at the **end** of a contract's execution.
42
+ ///
43
+ /// # Note
44
+ ///
45
+ /// The `current_*` fields do **not** consider changes to the code's refcount made during
46
+ /// the currently running call.
47
+ #[ derive( codec:: Encode ) ]
48
+ #[ cfg_attr( test, derive( Debug , PartialEq ) ) ]
49
+ pub struct RentStatus < T : Config > {
50
+ /// Required deposit assuming that this contract is the only user of its code.
51
+ pub max_deposit : BalanceOf < T > ,
52
+ /// Required deposit assuming the code's current refcount.
53
+ pub current_deposit : BalanceOf < T > ,
54
+ /// Required deposit assuming the specified refcount (None if 0 is supplied).
55
+ pub custom_refcount_deposit : Option < BalanceOf < T > > ,
56
+ /// Rent that is payed assuming that the contract is the only user of its code.
57
+ pub max_rent : BalanceOf < T > ,
58
+ /// Rent that is payed given the code's current refcount.
59
+ pub current_rent : BalanceOf < T > ,
60
+ /// Rent that is payed assuming the specified refcount (None is 0 is supplied).
61
+ pub custom_refcount_rent : Option < BalanceOf < T > > ,
62
+ /// Reserved for backwards compatible changes to this data structure.
63
+ pub _reserved : Option < ( ) > ,
64
+ }
65
+
66
+ /// We cannot derive `Default` because `T` does not necessarily implement `Default`.
67
+ impl < T : Config > Default for RentStatus < T > {
68
+ fn default ( ) -> Self {
69
+ Self {
70
+ max_deposit : Default :: default ( ) ,
71
+ current_deposit : Default :: default ( ) ,
72
+ custom_refcount_deposit : Default :: default ( ) ,
73
+ max_rent : Default :: default ( ) ,
74
+ current_rent : Default :: default ( ) ,
75
+ custom_refcount_rent : Default :: default ( ) ,
76
+ _reserved : Default :: default ( ) ,
77
+ }
78
+ }
79
+ }
80
+
38
81
pub struct Rent < T , E > ( sp_std:: marker:: PhantomData < ( T , E ) > ) ;
39
82
40
83
impl < T , E > Rent < T , E >
@@ -160,7 +203,7 @@ where
160
203
// Compute how much would the fee per block be with the *updated* balance.
161
204
let total_balance = T :: Currency :: total_balance ( account) ;
162
205
let free_balance = T :: Currency :: free_balance ( account) ;
163
- let fee_per_block = Self :: compute_fee_per_block (
206
+ let fee_per_block = Self :: fee_per_block (
164
207
& free_balance, & alive_contract_info, code_size,
165
208
) ;
166
209
if fee_per_block. is_zero ( ) {
@@ -281,24 +324,67 @@ where
281
324
Ok ( ( caller_code_len, tombstone_code_len) )
282
325
}
283
326
284
- /// Returns a fee charged per block from the contract.
285
- ///
286
- /// This function accounts for the storage rent deposit. I.e. if the contract possesses enough funds
287
- /// then the fee can drop to zero.
288
- fn compute_fee_per_block (
327
+ /// Create a new `RentStatus` struct for pass through to a requesting contract.
328
+ pub fn rent_status (
289
329
free_balance : & BalanceOf < T > ,
330
+ contract : & AliveContractInfo < T > ,
331
+ aggregated_code_size : u32 ,
332
+ current_refcount : u32 ,
333
+ at_refcount : u32 ,
334
+ ) -> RentStatus < T > {
335
+ let calc_share = |refcount : u32 | {
336
+ aggregated_code_size. checked_div ( refcount) . unwrap_or ( 0 )
337
+ } ;
338
+ let max_share = calc_share ( 1 ) ;
339
+ let current_share = calc_share ( current_refcount) ;
340
+ let custom_share = calc_share ( at_refcount) ;
341
+ RentStatus {
342
+ max_deposit : Self :: required_deposit ( contract, max_share) ,
343
+ current_deposit : Self :: required_deposit ( contract, current_share) ,
344
+ custom_refcount_deposit :
345
+ if at_refcount > 0 {
346
+ Some ( Self :: required_deposit ( contract, custom_share) )
347
+ } else {
348
+ None
349
+ } ,
350
+ max_rent : Self :: fee_per_block ( free_balance, contract, max_share) ,
351
+ current_rent : Self :: fee_per_block ( free_balance, contract, current_share) ,
352
+ custom_refcount_rent :
353
+ if at_refcount > 0 {
354
+ Some ( Self :: fee_per_block ( free_balance, contract, custom_share) )
355
+ } else {
356
+ None
357
+ } ,
358
+ _reserved : None ,
359
+ }
360
+ }
361
+
362
+ /// Returns how much deposit is required to not pay rent.
363
+ fn required_deposit (
290
364
contract : & AliveContractInfo < T > ,
291
365
code_size_share : u32 ,
292
366
) -> BalanceOf < T > {
293
- let uncovered_by_balance = T :: DepositPerStorageByte :: get ( )
367
+ T :: DepositPerStorageByte :: get ( )
294
368
. saturating_mul ( contract. storage_size . saturating_add ( code_size_share) . into ( ) )
295
369
. saturating_add (
296
370
T :: DepositPerStorageItem :: get ( )
297
371
. saturating_mul ( contract. pair_count . into ( ) )
298
372
)
299
373
. saturating_add ( T :: DepositPerContract :: get ( ) )
374
+ }
375
+
376
+ /// Returns a fee charged per block from the contract.
377
+ ///
378
+ /// This function accounts for the storage rent deposit. I.e. if the contract
379
+ /// possesses enough funds then the fee can drop to zero.
380
+ fn fee_per_block (
381
+ free_balance : & BalanceOf < T > ,
382
+ contract : & AliveContractInfo < T > ,
383
+ code_size_share : u32 ,
384
+ ) -> BalanceOf < T > {
385
+ let missing_deposit = Self :: required_deposit ( contract, code_size_share)
300
386
. saturating_sub ( * free_balance) ;
301
- T :: RentFraction :: get ( ) . mul_ceil ( uncovered_by_balance )
387
+ T :: RentFraction :: get ( ) . mul_ceil ( missing_deposit )
302
388
}
303
389
304
390
/// Returns amount of funds available to consume by rent mechanism.
@@ -354,7 +440,7 @@ where
354
440
let free_balance = T :: Currency :: free_balance ( account) ;
355
441
356
442
// An amount of funds to charge per block for storage taken up by the contract.
357
- let fee_per_block = Self :: compute_fee_per_block ( & free_balance, contract, code_size) ;
443
+ let fee_per_block = Self :: fee_per_block ( & free_balance, contract, code_size) ;
358
444
if fee_per_block. is_zero ( ) {
359
445
// The rent deposit offset reduced the fee to 0. This means that the contract
360
446
// gets the rent for free.
0 commit comments