This repository was archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Contracts: runtime_call and storage_deposit #13990
Merged
Merged
Changes from 15 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
909cbae
wip
pgherveou fb0cc68
add comments
pgherveou 81859b6
fix comment
pgherveou 0ccd804
comments
pgherveou a5a63da
comments
pgherveou 21e2fc1
PR comment
pgherveou c81bde4
field orders
pgherveou 60c2bf4
Update frame/contracts/src/tests.rs
pgherveou cd177fc
Update frame/contracts/fixtures/call_runtime_and_call.wat
pgherveou 672070b
Apply suggestions from code review
pgherveou ead8ba3
Apply suggestions from code review
pgherveou 826bfa7
Update frame/contracts/src/tests.rs
pgherveou faf1b12
Validate fees of failed call
pgherveou ec43399
Merge branch 'master' into pg/storage_deposit_runtime
pgherveou fe79901
Update frame/contracts/src/tests.rs
pgherveou 2bed075
Update frame/contracts/src/tests.rs
pgherveou e68423d
Merge remote-tracking branch 'origin/master' into pg/storage_deposit_…
badc93c
Update frame/contracts/src/tests.rs
pgherveou 22cea6e
bubble up refund error
pgherveou 05c9f8c
Merge branch 'master' into pg/storage_deposit_runtime
pgherveou 45aae4d
rename fixture file
pgherveou File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| (module | ||
| (import "seal0" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) | ||
| (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) | ||
| (import "seal0" "seal_input" (func $seal_input (param i32 i32))) | ||
| (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) | ||
| (import "env" "memory" (memory 1 1)) | ||
|
|
||
| (func $assert (param i32) | ||
| (block $ok | ||
| (br_if $ok (get_local 0)) | ||
| (unreachable) | ||
| ) | ||
| ) | ||
|
|
||
| (func (export "call") | ||
| ;; Store available input size at offset 0. | ||
| (i32.store (i32.const 0) (i32.const 512)) | ||
|
|
||
| ;; read input data | ||
| (call $seal_input (i32.const 4) (i32.const 0)) | ||
|
|
||
| ;; Input data layout. | ||
| ;; [0..4) - size of the call | ||
| ;; [4..8) - how many bytes to add to storage | ||
| ;; [8..40) - address of the callee | ||
| ;; [40..n) - encoded runtime call | ||
|
|
||
| ;; Invoke call_runtime with the encoded call passed to this contract. | ||
| (call $assert (i32.eqz | ||
| (call $call_runtime | ||
| (i32.const 40) ;; Pointer where the call is stored | ||
| (i32.sub | ||
| (i32.load (i32.const 0)) ;; Size of the call | ||
| (i32.const 36) ;; Subtract size of the subcall-related part: 4 bytes for storage length to add + 32 bytes of the callee address | ||
| ) | ||
| ) | ||
| )) | ||
|
|
||
| ;; call passed contract | ||
| (call $assert (i32.eqz | ||
| (call $seal_call | ||
| (i32.const 0) ;; No flags | ||
| (i32.const 8) ;; Pointer to "callee" address. | ||
| (i64.const 0) ;; How much gas to devote for the execution. 0 = all. | ||
| (i32.const 512) ;; Pointer to the buffer with value to transfer | ||
| (i32.const 4) ;; Pointer to input data buffer address | ||
| (i32.const 4) ;; Length of input data buffer | ||
| (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output | ||
| (i32.const 0) ;; Length is ignored in this case | ||
| ) | ||
| )) | ||
| ) | ||
|
|
||
| (func (export "deploy")) | ||
| ) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,7 +82,7 @@ pub trait Ext<T: Config> { | |
| deposit_account: &DepositAccount<T>, | ||
| amount: &DepositOf<T>, | ||
| terminated: bool, | ||
| ); | ||
| ) -> Result<(), DispatchError>; | ||
| } | ||
|
|
||
| /// This [`Ext`] is used for actual on-chain execution when balance needs to be charged. | ||
|
|
@@ -343,14 +343,14 @@ where | |
| /// | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. docs above this line could be improved a bit to reflect the fact this is now a fallible fn |
||
| /// This drops the root meter in order to make sure it is only called when the whole | ||
| /// execution did finish. | ||
| pub fn into_deposit(self, origin: &T::AccountId) -> DepositOf<T> { | ||
| pub fn try_into_deposit(self, origin: &T::AccountId) -> Result<DepositOf<T>, DispatchError> { | ||
| for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Refund(_))) { | ||
| E::charge(origin, &charge.deposit_account, &charge.amount, charge.terminated); | ||
| E::charge(origin, &charge.deposit_account, &charge.amount, charge.terminated)?; | ||
| } | ||
| for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Charge(_))) { | ||
| E::charge(origin, &charge.deposit_account, &charge.amount, charge.terminated); | ||
| E::charge(origin, &charge.deposit_account, &charge.amount, charge.terminated)?; | ||
| } | ||
| self.total_deposit | ||
| Ok(self.total_deposit) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -405,7 +405,8 @@ where | |
| info.deposit_account(), | ||
| &deposit.saturating_sub(&Deposit::Charge(ed)), | ||
| false, | ||
| ); | ||
| )?; | ||
|
|
||
| System::<T>::inc_consumers(info.deposit_account())?; | ||
|
|
||
| // We also need to make sure that the contract's account itself exists. | ||
|
|
@@ -476,41 +477,14 @@ impl<T: Config> Ext<T> for ReservingExt { | |
| deposit_account: &DepositAccount<T>, | ||
| amount: &DepositOf<T>, | ||
| terminated: bool, | ||
| ) { | ||
| // There is nothing we can do when this fails as this constitutes a bug in the runtime. | ||
| // We need to settle for emitting an error log in this case. | ||
| // | ||
| // # Note | ||
| // | ||
| // This is infallible because it is called in a part of the execution where we cannot | ||
| // simply roll back. It might make sense to do some refactoring to move the deposit | ||
| // collection to the fallible part of execution. | ||
| ) -> Result<(), DispatchError> { | ||
| match amount { | ||
| Deposit::Charge(amount) => { | ||
| // This will never fail because a deposit account is required to exist | ||
| // at all times. The pallet enforces this invariant by holding a consumer reference | ||
| // on the deposit account as long as the contract exists. | ||
| // | ||
| // The sender always has enough balance because we checked that it had enough | ||
| // balance when instantiating the storage meter. There is no way for the sender | ||
| // which is a plain account to send away this balance in the meantime. | ||
| let result = T::Currency::transfer( | ||
| origin, | ||
| deposit_account, | ||
| *amount, | ||
| ExistenceRequirement::KeepAlive, | ||
| ); | ||
| if let Err(err) = result { | ||
| log::error!( | ||
| target: LOG_TARGET, | ||
| "Failed to transfer storage deposit {:?} from origin {:?} to deposit account {:?}: {:?}", | ||
| amount, origin, deposit_account, err, | ||
| ); | ||
| if cfg!(debug_assertions) { | ||
| panic!("Unable to collect storage deposit. This is a bug."); | ||
| } | ||
| } | ||
| }, | ||
| Deposit::Charge(amount) => T::Currency::transfer( | ||
| origin, | ||
| deposit_account, | ||
| *amount, | ||
| ExistenceRequirement::KeepAlive, | ||
| ), | ||
| // The receiver always exists because the initial value transfer from the | ||
| // origin to the contract has a keep alive existence requirement. When taking a deposit | ||
| // we make sure to leave at least the ed in the free balance. | ||
|
|
@@ -539,8 +513,9 @@ impl<T: Config> Ext<T> for ReservingExt { | |
| panic!("Unable to refund storage deposit. This is a bug."); | ||
| } | ||
| } | ||
| Ok(()) | ||
| }, | ||
| }; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -613,7 +588,7 @@ mod tests { | |
| contract: &DepositAccount<Test>, | ||
| amount: &DepositOf<Test>, | ||
| terminated: bool, | ||
| ) { | ||
| ) -> Result<(), DispatchError> { | ||
| TestExtTestValue::mutate(|ext| { | ||
| ext.charges.push(Charge { | ||
| origin: origin.clone(), | ||
|
|
@@ -622,6 +597,7 @@ mod tests { | |
| terminated, | ||
| }) | ||
| }); | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -719,7 +695,7 @@ mod tests { | |
| nested0.enforce_limit(Some(&mut nested0_info)).unwrap(); | ||
| meter.absorb(nested0, DepositAccount(BOB), Some(&mut nested0_info)); | ||
|
|
||
| meter.into_deposit(&ALICE); | ||
| meter.try_into_deposit(&ALICE).unwrap(); | ||
|
|
||
| assert_eq!(nested0_info.extra_deposit(), 112); | ||
| assert_eq!(nested1_info.extra_deposit(), 110); | ||
|
|
@@ -779,7 +755,7 @@ mod tests { | |
| nested0.absorb(nested1, DepositAccount(CHARLIE), None); | ||
|
|
||
| meter.absorb(nested0, DepositAccount(BOB), None); | ||
| meter.into_deposit(&ALICE); | ||
| meter.try_into_deposit(&ALICE).unwrap(); | ||
|
|
||
| assert_eq!( | ||
| TestExtTestValue::get(), | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.