Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions crates/env/src/engine/off_chain/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ where
}

/// Sets the value transferred from the caller to the callee as part of the call.
///
/// Please note that the acting accounts should be set with [`set_caller()`] and [`set_callee()`] beforehand.
pub fn set_value_transferred<T>(value: T::Balance)
where
T: Environment<Balance = u128>, // Just temporary for the MVP!
Expand All @@ -209,6 +211,44 @@ where
})
}

/// Transfers value from the caller account to the contract.
///
/// Please note that the acting accounts should be set with [`set_caller()`] and [`set_callee()`] beforehand.
pub fn transfer_in<T>(value: T::Balance)
where
T: Environment<Balance = u128>, // Just temporary for the MVP!
{
<EnvInstance as OnInstance>::on_instance(|instance| {
let caller = instance
.engine
.exec_context
.caller
.as_ref()
.expect("no caller has been set")
.as_bytes()
.to_vec();

let caller_old_balance = instance
.engine
.get_balance(caller.clone())
.unwrap_or_default();

let callee = instance.engine.get_callee();
let contract_old_balance = instance
.engine
.get_balance(callee.clone())
.unwrap_or_default();

instance
.engine
.set_balance(caller, caller_old_balance - value);
instance
.engine
.set_balance(callee, contract_old_balance + value);
instance.engine.set_value_transferred(value);
});
}

/// Returns the amount of storage cells used by the account `account_id`.
///
/// Returns `None` if the `account_id` is non-existent.
Expand Down Expand Up @@ -355,3 +395,12 @@ pub fn assert_contract_termination<T, F>(
assert_eq!(value_transferred, expected_value_transferred_to_beneficiary);
assert_eq!(beneficiary, expected_beneficiary);
}

/// Prepend contract message call with value transfer. Used for tests in off-chain environment.
#[macro_export]
macro_rules! pay_with_call {
($contract:ident . $message:ident ( $( $params:expr ),* ) , $amount:expr) => {{
$crate::test::transfer_in::<Environment>($amount);
$contract.$message($ ($params) ,*)
}}
}
51 changes: 35 additions & 16 deletions crates/lang/codegen/src/generator/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use ir::{
};
use proc_macro2::TokenStream as TokenStream2;
use quote::{
format_ident,
quote,
quote_spanned,
};
Expand Down Expand Up @@ -488,19 +489,25 @@ impl Dispatch<'_> {
#constructor_ident(#constructor_input)
)
});
let constructor_match = (0..count_constructors).map(|index| {
let constructor_span = constructor_spans[index];
let constructor_ident = constructor_variant_ident(index);
let constructor_selector = quote_spanned!(span=>
<#storage_ident as ::ink_lang::reflect::DispatchableConstructorInfo<{

let constructor_selector = (0..count_constructors).map(|index| {
let const_ident = format_ident!("CONSTRUCTOR_{}", index);
quote_spanned!(span=>
const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink_lang::reflect::DispatchableConstructorInfo<{
<#storage_ident as ::ink_lang::reflect::ContractDispatchableConstructors<{
<#storage_ident as ::ink_lang::reflect::ContractAmountDispatchables>::CONSTRUCTORS
}>>::IDS[#index]
}>>::SELECTOR
);
}>>::SELECTOR;
)
});

let constructor_match = (0..count_constructors).map(|index| {
let constructor_span = constructor_spans[index];
let constructor_ident = constructor_variant_ident(index);
let const_ident = format_ident!("CONSTRUCTOR_{}", index);
let constructor_input = expand_constructor_input(constructor_span, storage_ident, index);
quote_spanned!(constructor_span=>
#constructor_selector => {
#const_ident => {
::core::result::Result::Ok(Self::#constructor_ident(
<#constructor_input as ::scale::Decode>::decode(input)
.map_err(|_| ::ink_lang::reflect::DispatchError::InvalidParameters)?
Expand Down Expand Up @@ -576,6 +583,9 @@ impl Dispatch<'_> {
where
I: ::scale::Input,
{
#(
#constructor_selector
)*
match <[::core::primitive::u8; 4usize] as ::scale::Decode>::decode(input)
.map_err(|_| ::ink_lang::reflect::DispatchError::InvalidSelector)?
{
Expand Down Expand Up @@ -653,19 +663,25 @@ impl Dispatch<'_> {
#message_ident(#message_input)
)
});
let message_match = (0..count_messages).map(|index| {
let message_span = message_spans[index];
let message_ident = message_variant_ident(index);
let message_selector = quote_spanned!(span=>
<#storage_ident as ::ink_lang::reflect::DispatchableMessageInfo<{

let message_selector = (0..count_messages).map(|index| {
let const_ident = format_ident!("MESSAGE_{}", index);
quote_spanned!(span=>
const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink_lang::reflect::DispatchableMessageInfo<{
<#storage_ident as ::ink_lang::reflect::ContractDispatchableMessages<{
<#storage_ident as ::ink_lang::reflect::ContractAmountDispatchables>::MESSAGES
}>>::IDS[#index]
}>>::SELECTOR
);
}>>::SELECTOR;
)
});

let message_match = (0..count_messages).map(|index| {
let message_span = message_spans[index];
let message_ident = message_variant_ident(index);
let const_ident = format_ident!("MESSAGE_{}", index);
let message_input = expand_message_input(message_span, storage_ident, index);
quote_spanned!(message_span=>
#message_selector => {
#const_ident => {
::core::result::Result::Ok(Self::#message_ident(
<#message_input as ::scale::Decode>::decode(input)
.map_err(|_| ::ink_lang::reflect::DispatchError::InvalidParameters)?
Expand Down Expand Up @@ -772,6 +788,9 @@ impl Dispatch<'_> {
where
I: ::scale::Input,
{
#(
#message_selector
)*
match <[::core::primitive::u8; 4usize] as ::scale::Decode>::decode(input)
.map_err(|_| ::ink_lang::reflect::DispatchError::InvalidSelector)?
{
Expand Down
2 changes: 2 additions & 0 deletions crates/lang/tests/compile_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ fn ui_tests() {
t.compile_fail("tests/ui/trait_def/fail/*.rs");

t.pass("tests/ui/chain_extension/E-01-simple.rs");

t.pass("tests/ui/pay_with_call/pass/multiple_args.rs");
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied
--> tests/ui/contract/fail/constructor-input-non-codec.rs:13:28
|
13 | pub fn constructor(_input: NonCodecType) -> Self {
| ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType`
| ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType`
|
= help: the following other types implement trait `WrapperTypeDecode`:
Arc<T>
Expand All @@ -18,10 +18,8 @@ note: required by a bound in `DispatchInput`
error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied
--> tests/ui/contract/fail/constructor-input-non-codec.rs:13:9
|
13 | / pub fn constructor(_input: NonCodecType) -> Self {
14 | | Self {}
15 | | }
| |_________^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType`
13 | pub fn constructor(_input: NonCodecType) -> Self {
| ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType`
|
= help: the following other types implement trait `WrapperTypeDecode`:
Arc<T>
Expand All @@ -32,10 +30,8 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied
error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied
--> tests/ui/contract/fail/constructor-input-non-codec.rs:13:9
|
13 | / pub fn constructor(_input: NonCodecType) -> Self {
14 | | Self {}
15 | | }
| |_________^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType`
13 | pub fn constructor(_input: NonCodecType) -> Self {
| ^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType`
|
= help: the following other types implement trait `WrapperTypeEncode`:
&T
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
error: encountered ink! constructor with overlapping wildcard selectors
--> tests/ui/contract/fail/constructor-multiple-wildcard-selectors.rs:15:9
|
15 | / pub fn constructor2() -> Self {
16 | | Self {}
17 | | }
| |_________^
15 | pub fn constructor2() -> Self {
| ^^^

error: first ink! constructor with overlapping wildcard selector here
--> tests/ui/contract/fail/constructor-multiple-wildcard-selectors.rs:10:9
|
10 | / pub fn constructor1() -> Self {
11 | | Self {}
12 | | }
| |_________^
10 | pub fn constructor1() -> Self {
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ error: encountered ink! attribute arguments with equal kinds
--> tests/ui/contract/fail/constructor-selector-and-wildcard-selector.rs:9:51
|
9 | #[ink(constructor, selector = 0xCAFEBABA, selector = _)]
| ^^^^^^^^^^^^
| ^^^^^^^^

error: first equal ink! attribute argument with equal kind here
--> tests/ui/contract/fail/constructor-selector-and-wildcard-selector.rs:9:28
|
9 | #[ink(constructor, selector = 0xCAFEBABA, selector = _)]
| ^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> tests/ui/contract/fail/constructor-self-receiver-03.rs:10:34
|
10 | pub fn constructor(this: &Self) -> Self {
| ^ explicit lifetime name needed here

error[E0411]: cannot find type `Self` in this scope
--> tests/ui/contract/fail/constructor-self-receiver-03.rs:10:35
|
6 | pub struct Contract {}
| --- `Self` not allowed in a constant item
...
10 | pub fn constructor(this: &Self) -> Self {
| ^^^^ `Self` is only available in impls, traits, and type definitions

error[E0106]: missing lifetime specifier
--> tests/ui/contract/fail/constructor-self-receiver-03.rs:10:34
error[E0411]: cannot find type `Self` in this scope
--> tests/ui/contract/fail/constructor-self-receiver-03.rs:10:35
|
3 | #[ink::contract]
| ---------------- `Self` not allowed in a function
...
10 | pub fn constructor(this: &Self) -> Self {
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
| ^^^^ `Self` is only available in impls, traits, and type definitions

error[E0277]: the trait bound `&'static Contract: WrapperTypeDecode` is not satisfied
--> tests/ui/contract/fail/constructor-self-receiver-03.rs:10:9
|
10 ~ pub fn constructor(this: &'a Self) -> Self {
11 | Self {}
12 ~ }<'a>
10 | pub fn constructor(this: &Self) -> Self {
| ^^^ the trait `WrapperTypeDecode` is not implemented for `&'static Contract`
|
= help: the following other types implement trait `WrapperTypeDecode`:
Arc<T>
Box<T>
Rc<T>
= note: required because of the requirements on the impl of `parity_scale_codec::Decode` for `&'static Contract`
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
error[E0277]: the trait bound `EventTopics<4_usize>: RespectTopicLimit<2_usize>` is not satisfied
error[E0277]: the trait bound `EventTopics<4>: RespectTopicLimit<2>` is not satisfied
--> tests/ui/contract/fail/event-too-many-topics-anonymous.rs:26:5
|
26 | / pub struct Event {
27 | | #[ink(topic)]
28 | | arg_1: i8,
29 | | #[ink(topic)]
... |
34 | | arg_4: i32,
35 | | }
| |_____^ the trait `RespectTopicLimit<2_usize>` is not implemented for `EventTopics<4_usize>`
26 | pub struct Event {
| ^^^ the trait `RespectTopicLimit<2>` is not implemented for `EventTopics<4>`
|
= help: the following other types implement trait `RespectTopicLimit<N>`:
<EventTopics<0_usize> as RespectTopicLimit<0_usize>>
<EventTopics<0_usize> as RespectTopicLimit<10_usize>>
<EventTopics<0_usize> as RespectTopicLimit<11_usize>>
<EventTopics<0_usize> as RespectTopicLimit<12_usize>>
<EventTopics<0_usize> as RespectTopicLimit<1_usize>>
<EventTopics<0_usize> as RespectTopicLimit<2_usize>>
<EventTopics<0_usize> as RespectTopicLimit<3_usize>>
<EventTopics<0_usize> as RespectTopicLimit<4_usize>>
<EventTopics<0> as RespectTopicLimit<0>>
<EventTopics<0> as RespectTopicLimit<10>>
<EventTopics<0> as RespectTopicLimit<11>>
<EventTopics<0> as RespectTopicLimit<12>>
<EventTopics<0> as RespectTopicLimit<1>>
<EventTopics<0> as RespectTopicLimit<2>>
<EventTopics<0> as RespectTopicLimit<3>>
<EventTopics<0> as RespectTopicLimit<4>>
and 83 others
note: required by a bound in `EventRespectsTopicLimit`
--> src/codegen/event/topics.rs
Expand Down
28 changes: 11 additions & 17 deletions crates/lang/tests/ui/contract/fail/event-too-many-topics.stderr
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
error[E0277]: the trait bound `EventTopics<3_usize>: RespectTopicLimit<2_usize>` is not satisfied
error[E0277]: the trait bound `EventTopics<3>: RespectTopicLimit<2>` is not satisfied
--> tests/ui/contract/fail/event-too-many-topics.rs:26:5
|
26 | / pub struct Event {
27 | | #[ink(topic)]
28 | | arg_1: i8,
29 | | #[ink(topic)]
... |
32 | | arg_3: i32,
33 | | }
| |_____^ the trait `RespectTopicLimit<2_usize>` is not implemented for `EventTopics<3_usize>`
26 | pub struct Event {
| ^^^ the trait `RespectTopicLimit<2>` is not implemented for `EventTopics<3>`
|
= help: the following other types implement trait `RespectTopicLimit<N>`:
<EventTopics<0_usize> as RespectTopicLimit<0_usize>>
<EventTopics<0_usize> as RespectTopicLimit<10_usize>>
<EventTopics<0_usize> as RespectTopicLimit<11_usize>>
<EventTopics<0_usize> as RespectTopicLimit<12_usize>>
<EventTopics<0_usize> as RespectTopicLimit<1_usize>>
<EventTopics<0_usize> as RespectTopicLimit<2_usize>>
<EventTopics<0_usize> as RespectTopicLimit<3_usize>>
<EventTopics<0_usize> as RespectTopicLimit<4_usize>>
<EventTopics<0> as RespectTopicLimit<0>>
<EventTopics<0> as RespectTopicLimit<10>>
<EventTopics<0> as RespectTopicLimit<11>>
<EventTopics<0> as RespectTopicLimit<12>>
<EventTopics<0> as RespectTopicLimit<1>>
<EventTopics<0> as RespectTopicLimit<2>>
<EventTopics<0> as RespectTopicLimit<3>>
<EventTopics<0> as RespectTopicLimit<4>>
and 83 others
note: required by a bound in `EventRespectsTopicLimit`
--> src/codegen/event/topics.rs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ error[E0599]: no function or associated item named `constructor_2` found for str
--> tests/ui/contract/fail/impl-block-for-non-storage-01.rs:22:16
|
6 | pub struct Contract {}
| ------------------- function or associated item `constructor_2` not found for this
| --- function or associated item `constructor_2` not found for this struct
...
22 | pub fn constructor_2() -> Self {
| ^^^^^^^^^^^^^
Expand All @@ -23,7 +23,7 @@ error[E0599]: no function or associated item named `message_2` found for struct
--> tests/ui/contract/fail/impl-block-for-non-storage-01.rs:27:16
|
6 | pub struct Contract {}
| ------------------- function or associated item `message_2` not found for this
| --- function or associated item `message_2` not found for this struct
...
27 | pub fn message_2(&self) {}
| ^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: expected string type for `namespace` argument, e.g. #[ink(namespace = "he
--> tests/ui/contract/fail/impl-block-namespace-invalid-type.rs:8:11
|
8 | #[ink(namespace = true)]
| ^^^^^^^^^^^^^^^^
| ^^^^^^^^^
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `env` found for struct `Contr
--> tests/ui/contract/fail/impl-block-using-static-env-no-marker.rs:22:27
|
6 | pub struct Contract {}
| ------------------- function or associated item `env` not found for this
| --- function or associated item `env` not found for this struct
...
22 | let _ = Self::env().caller();
| ^^^ function or associated item not found in `Contract`
Expand Down
Loading