contracts: is_contract(address) and caller_is_origin() are added to API (#10789)

* is_contract() and caller_is_origin() added to Ext API

* is_contract() exposed in wasm runtime.rs

* + test for is_contract()

* + seal_is_contract benchmark

* caller_is_origin() exposed to wasm/runtime.rs and covered by a test

* + seal_caller_is_origin benchmark

* Update frame/contracts/src/exec.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Update frame/contracts/src/exec.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Update frame/contracts/src/exec.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Update frame/contracts/src/wasm/runtime.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Update frame/contracts/src/wasm/runtime.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Update frame/contracts/src/wasm/runtime.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Update frame/contracts/src/exec.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* identation fix for benchmark macroses; test cosmetic improvement

* benchmark fix

* + is_contract() wasm test

* + caller_is_origin() wasm test

* Apply suggestions from code review

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* is_contract() to borrow param instead of taking ownership

* phrasing improved

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* fixed wasm tests according to @athei feedback

* dead code warnings suppressed by unstable-interface attributes

* cargo run --quiet --profile=production  --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Parity Bot <admin@parity.io>
This commit is contained in:
Alexander Gryaznov
2022-02-04 20:13:00 +01:00
committed by GitHub
parent 89fa61125e
commit d5c8593566
6 changed files with 965 additions and 652 deletions
+82 -1
View File
@@ -158,6 +158,15 @@ pub trait Ext: sealing::Sealed {
/// Returns a reference to the account id of the caller.
fn caller(&self) -> &AccountIdOf<Self::T>;
/// Check if a contract lives at the specified `address`.
fn is_contract(&self, address: &AccountIdOf<Self::T>) -> bool;
/// Check if the caller of the current contract is the origin of the whole call stack.
///
/// This can be checked with `is_contract(self.caller())` as well.
/// However, this function does not require any storage lookup and therefore uses less weight.
fn caller_is_origin(&self) -> bool;
/// Returns a reference to the account id of the current contract.
fn address(&self) -> &AccountIdOf<Self::T>;
@@ -483,7 +492,7 @@ where
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
E: Executable<T>,
{
/// Create an run a new call stack by calling into `dest`.
/// Create and run a new call stack by calling into `dest`.
///
/// # Note
///
@@ -1024,6 +1033,14 @@ where
self.frames().nth(1).map(|f| &f.account_id).unwrap_or(&self.origin)
}
fn is_contract(&self, address: &T::AccountId) -> bool {
ContractInfoOf::<T>::contains_key(&address)
}
fn caller_is_origin(&self) -> bool {
self.caller() == &self.origin
}
fn balance(&self) -> BalanceOf<T> {
T::Currency::free_balance(&self.top_frame().account_id)
}
@@ -1620,6 +1637,70 @@ mod tests {
WITNESSED_CALLER_CHARLIE.with(|caller| assert_eq!(*caller.borrow(), Some(dest)));
}
#[test]
fn is_contract_returns_proper_values() {
let bob_ch = MockLoader::insert(Call, |ctx, _| {
// Verify that BOB is a contract
assert!(ctx.ext.is_contract(&BOB));
// Verify that ALICE is not a contract
assert!(!ctx.ext.is_contract(&ALICE));
exec_success()
});
ExtBuilder::default().build().execute_with(|| {
let schedule = <Test as Config>::Schedule::get();
place_contract(&BOB, bob_ch);
let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap();
let result = MockStack::run_call(
ALICE,
BOB,
&mut GasMeter::<Test>::new(GAS_LIMIT),
&mut storage_meter,
&schedule,
0,
vec![],
None,
);
assert_matches!(result, Ok(_));
});
}
#[test]
fn caller_is_origin_returns_proper_values() {
let code_charlie = MockLoader::insert(Call, |ctx, _| {
// BOB is not the origin of the stack call
assert!(!ctx.ext.caller_is_origin());
exec_success()
});
let code_bob = MockLoader::insert(Call, |ctx, _| {
// ALICE is the origin of the call stack
assert!(ctx.ext.caller_is_origin());
// BOB calls CHARLIE
ctx.ext.call(0, CHARLIE, 0, vec![], true)
});
ExtBuilder::default().build().execute_with(|| {
let schedule = <Test as Config>::Schedule::get();
place_contract(&BOB, code_bob);
place_contract(&CHARLIE, code_charlie);
let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap();
// ALICE -> BOB (caller is origin) -> CHARLIE (caller is not origin)
let result = MockStack::run_call(
ALICE,
BOB,
&mut GasMeter::<Test>::new(GAS_LIMIT),
&mut storage_meter,
&schedule,
0,
vec![0],
None,
);
assert_matches!(result, Ok(_));
});
}
#[test]
fn address_returns_proper_values() {
let bob_ch = MockLoader::insert(Call, |ctx, _| {