Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict wildcard selectors to have exactly one other message #1708

Merged
merged 36 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
641f008
Add some tests/todos
ascjones Mar 8, 2023
d2897f3
Testing
ascjones Mar 9, 2023
f094b0a
Add test for using well known selector without wildcard
ascjones Mar 9, 2023
c6771e4
Require reserved selector
ascjones Mar 10, 2023
8e8f3dd
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Mar 17, 2023
91b3a16
Define reserved selector const
ascjones Mar 17, 2023
91ecf89
WIP defining wildcard selector complement
ascjones Mar 17, 2023
a9b7aaf
Compiles with wildcard selector complement
ascjones Mar 17, 2023
db836eb
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Mar 24, 2023
1109f79
Return combined error on 2 or more messages
ascjones Mar 27, 2023
7f8f3ec
Fix up compile test for wildcard selector complement
ascjones Mar 27, 2023
b491a76
Add error for when wildcard complement used without wildcard
ascjones Mar 27, 2023
1ba18eb
Fix test
ascjones Mar 27, 2023
1450bcf
Fmt
ascjones Mar 27, 2023
3385ef0
Fmt
ascjones Mar 27, 2023
37ce190
Clear up error combine code
ascjones Mar 27, 2023
2af6423
Fix some wildcard complement tests
ascjones Mar 27, 2023
7b3e364
WIP use correct wildcard complement selector
ascjones Mar 28, 2023
ee4e483
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Mar 29, 2023
1aed9d1
Introduce Symbol parsing for MetaValue
ascjones Mar 29, 2023
db324c7
Remove unused imports
ascjones Mar 29, 2023
c02bf84
Add wildcard-selector example
ascjones Mar 29, 2023
856fd08
Calculate correct wildcard complement selector
ascjones Mar 29, 2023
192b325
Use well known wildcard complement constant
ascjones Mar 29, 2023
742df48
Fix UI test
ascjones Mar 29, 2023
c5f991d
WIP wildcard selector integration test
ascjones Mar 29, 2023
a735fc1
WIP wildcard selector integration test
ascjones Mar 30, 2023
cfeae31
Test wildcard
ascjones Mar 30, 2023
f7fa437
Wildcard complement test, define const in prelude and reexport
ascjones Mar 30, 2023
ca1edee
spellcheck
ascjones Mar 30, 2023
74f098e
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Mar 30, 2023
bcc76d8
Clippy
ascjones Mar 30, 2023
5e9b2fc
Use underscores for param bindings
ascjones Mar 30, 2023
763076f
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Apr 12, 2023
3db0181
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Apr 17, 2023
f9a6901
Merge branch 'master' into aj/restrict-wildcard-selectors
ascjones Apr 20, 2023
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
4 changes: 2 additions & 2 deletions crates/e2e/macro/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl TryFrom<ast::AttributeArgs> for E2EConfig {
"E2E test",
))
}
if let ast::PathOrLit::Lit(syn::Lit::Str(lit_str)) = &arg.value {
if let ast::MetaValue::Lit(syn::Lit::Str(lit_str)) = &arg.value {
additional_contracts = Some((lit_str.clone(), arg))
} else {
return Err(format_err_spanned!(
Expand All @@ -69,7 +69,7 @@ impl TryFrom<ast::AttributeArgs> for E2EConfig {
if let Some((_, ast)) = environment {
return Err(duplicate_config_err(ast, arg, "environment", "E2E test"))
}
if let ast::PathOrLit::Path(path) = &arg.value {
if let ast::MetaValue::Path(path) = &arg.value {
environment = Some((path.clone(), arg))
} else {
return Err(format_err_spanned!(
Expand Down
9 changes: 9 additions & 0 deletions crates/e2e/src/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ impl<E, RetType> Message<E, RetType>
where
E: Environment,
{
/// Create a new message from the given account id and encoded message data.
pub fn new(account_id: E::AccountId, exec_input: Vec<u8>) -> Self {
Self {
account_id,
exec_input,
_return_type: Default::default(),
}
}

/// The account id of the contract being called to invoke the message.
pub fn account_id(&self) -> &E::AccountId {
&self.account_id
Expand Down
1 change: 1 addition & 0 deletions crates/e2e/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod xts;

pub use builders::{
build_message,
Message,
MessageBuilder,
};
pub use client::{
Expand Down
1 change: 1 addition & 0 deletions crates/ink/ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ proc-macro2 = "1.0"
itertools = { version = "0.10", default-features = false }
either = { version = "1.5", default-features = false }
blake2 = "0.10"
ink_prelude = { version = "4.1.0", path = "../../prelude/", default-features = false }

[features]
default = ["std"]
Expand Down
24 changes: 12 additions & 12 deletions crates/ink/ir/src/ast/attr_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Parse for AttributeArgs {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::PathOrLit;
use crate::ast::MetaValue;
use quote::quote;

impl AttributeArgs {
Expand Down Expand Up @@ -81,7 +81,7 @@ mod tests {
AttributeArgs::new(vec![MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Lit(syn::parse_quote! { true }),
value: MetaValue::Lit(syn::parse_quote! { true }),
}])
)
}
Expand All @@ -93,7 +93,7 @@ mod tests {
AttributeArgs::new(vec![MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Lit(syn::parse_quote! { "string literal" }),
value: MetaValue::Lit(syn::parse_quote! { "string literal" }),
}])
)
}
Expand All @@ -105,7 +105,7 @@ mod tests {
AttributeArgs::new(vec![MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Path(syn::parse_quote! { MyIdentifier }),
value: MetaValue::Path(syn::parse_quote! { MyIdentifier }),
}])
)
}
Expand All @@ -117,7 +117,7 @@ mod tests {
AttributeArgs::new(vec![MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Path(syn::parse_quote! { ::this::is::my::Path }),
value: MetaValue::Path(syn::parse_quote! { ::this::is::my::Path }),
}])
)
}
Expand All @@ -130,7 +130,7 @@ mod tests {
AttributeArgs::new(vec![MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Path(
value: MetaValue::Path(
syn::parse_quote! { this::is::my::relative::Path }
),
}])
Expand All @@ -143,7 +143,7 @@ mod tests {
expected_args.push_value(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Path(syn::parse_quote! { value }),
value: MetaValue::Path(syn::parse_quote! { value }),
});
expected_args.push_punct(<Token![,]>::default());
assert_eq!(
Expand All @@ -169,27 +169,27 @@ mod tests {
MetaNameValue {
name: syn::parse_quote! { name1 },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Path(syn::parse_quote! { ::root::Path }),
value: MetaValue::Path(syn::parse_quote! { ::root::Path }),
},
MetaNameValue {
name: syn::parse_quote! { name2 },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Lit(syn::parse_quote! { false }),
value: MetaValue::Lit(syn::parse_quote! { false }),
},
MetaNameValue {
name: syn::parse_quote! { name3 },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Lit(syn::parse_quote! { "string literal" }),
value: MetaValue::Lit(syn::parse_quote! { "string literal" }),
},
MetaNameValue {
name: syn::parse_quote! { name4 },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Lit(syn::parse_quote! { 42 }),
value: MetaValue::Lit(syn::parse_quote! { 42 }),
},
MetaNameValue {
name: syn::parse_quote! { name5 },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Lit(syn::parse_quote! { 7.7 }),
value: MetaValue::Lit(syn::parse_quote! { 7.7 }),
},
])
)
Expand Down
57 changes: 46 additions & 11 deletions crates/ink/ir/src/ast/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl ToTokens for Meta {
pub struct MetaNameValue {
pub name: syn::Path,
pub eq_token: syn::token::Eq,
pub value: PathOrLit,
pub value: MetaValue,
}

impl Parse for MetaNameValue {
Expand Down Expand Up @@ -107,35 +107,40 @@ impl MetaNameValue {
}
}

/// Either a path or a literal.
/// Represents a value in a meta name-value pair.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathOrLit {
pub enum MetaValue {
Path(syn::Path),
Lit(syn::Lit),
Symbol(Symbol),
}

impl Parse for PathOrLit {
impl Parse for MetaValue {
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
if input.peek(Token![_]) || input.peek(Token![@]) {
return input.parse::<Symbol>().map(MetaValue::Symbol)
}
if input.fork().peek(syn::Lit) {
return input.parse::<syn::Lit>().map(PathOrLit::Lit)
return input.parse::<syn::Lit>().map(MetaValue::Lit)
}
if input.fork().peek(Ident::peek_any) || input.fork().peek(Token![::]) {
return input.call(parse_meta_path).map(PathOrLit::Path)
return input.call(parse_meta_path).map(MetaValue::Path)
}
Err(input.error("cannot parse into either literal or path"))
Err(input.error("expected a literal, a path or a punct for a meta value"))
}
}

impl ToTokens for PathOrLit {
impl ToTokens for MetaValue {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match self {
Self::Lit(lit) => lit.to_tokens(tokens),
Self::Path(path) => path.to_tokens(tokens),
Self::Symbol(symbol) => symbol.to_tokens(tokens),
}
}
}

impl PathOrLit {
impl MetaValue {
/// Returns the value of the literal if it is a boolean literal.
pub fn as_bool(&self) -> Option<bool> {
match self {
Expand All @@ -161,6 +166,33 @@ impl PathOrLit {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Symbol {
Underscore(Token![_]),
AtSign(Token![@]),
}

impl Parse for Symbol {
fn parse(input: ParseStream) -> syn::Result<Self> {
if input.peek(Token![_]) {
Ok(Symbol::Underscore(input.parse()?))
} else if input.peek(Token![@]) {
Ok(Symbol::AtSign(input.parse()?))
} else {
Err(input.error("expected either a `_` or a `@` symbol"))
}
}
}

impl ToTokens for Symbol {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match self {
Self::Underscore(underscore) => underscore.to_tokens(tokens),
Self::AtSign(at_sign) => at_sign.to_tokens(tokens),
}
}
}

/// Like [`syn::Path::parse_mod_style`] but accepts keywords in the path.
///
/// # Note
Expand Down Expand Up @@ -194,7 +226,10 @@ fn parse_meta_path(input: ParseStream) -> Result<syn::Path, syn::Error> {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::PathOrLit;
use crate::ast::{
MetaValue,
Symbol,
};
use quote::quote;

#[test]
Expand All @@ -204,7 +239,7 @@ mod tests {
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { selector },
eq_token: syn::parse_quote! { = },
value: PathOrLit::Path(syn::Path::from(quote::format_ident!("_"))),
value: MetaValue::Symbol(Symbol::Underscore(syn::parse_quote! { _ })),
})
)
}
Expand Down
3 changes: 2 additions & 1 deletion crates/ink/ir/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use self::{
meta::{
Meta,
MetaNameValue,
PathOrLit,
MetaValue,
Symbol,
},
};
41 changes: 25 additions & 16 deletions crates/ink/ir/src/ir/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use core::result::Result;
use std::collections::HashMap;

use ink_prelude::IIP2_WILDCARD_COMPLEMENT_SELECTOR;
use proc_macro2::{
Span,
TokenStream as TokenStream2,
Expand Down Expand Up @@ -531,22 +532,27 @@ pub enum SelectorOrWildcard {
/// annotated with the wildcard selector will be invoked.
Wildcard,
/// A user provided selector.
UserProvided(ir::Selector),
UserProvided(Selector),
}

impl SelectorOrWildcard {
/// Create a new `SelectorOrWildcard::Selector` from the supplied bytes.
fn selector(bytes: [u8; 4]) -> SelectorOrWildcard {
fn selector(bytes: [u8; 4]) -> Self {
SelectorOrWildcard::UserProvided(Selector::from(bytes))
}

/// The selector of the wildcard complement message.
pub fn wildcard_complement() -> Self {
Self::selector(IIP2_WILDCARD_COMPLEMENT_SELECTOR)
}
}

impl TryFrom<&ast::PathOrLit> for SelectorOrWildcard {
impl TryFrom<&ast::MetaValue> for SelectorOrWildcard {
type Error = syn::Error;

fn try_from(value: &ast::PathOrLit) -> Result<Self, Self::Error> {
fn try_from(value: &ast::MetaValue) -> Result<Self, Self::Error> {
match value {
ast::PathOrLit::Lit(lit) => {
ast::MetaValue::Lit(lit) => {
if let syn::Lit::Str(_) = lit {
return Err(format_err_spanned!(
lit,
Expand All @@ -571,16 +577,19 @@ impl TryFrom<&ast::PathOrLit> for SelectorOrWildcard {
"expected 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]"
))
}
ast::PathOrLit::Path(path) => {
if path.is_ident("_") {
Ok(SelectorOrWildcard::Wildcard)
} else {
Err(format_err_spanned!(
path,
"expected `selector` argument to be either a 4-digit hexcode or `_`"
))
ast::MetaValue::Symbol(symbol) => {
match symbol {
ast::Symbol::Underscore(_) => Ok(SelectorOrWildcard::Wildcard),
ast::Symbol::AtSign(_) => Ok(SelectorOrWildcard::wildcard_complement()),
}
}
ast::MetaValue::Path(path) => {
Err(format_err_spanned!(
path,
"unexpected path for `selector` argument, expected a 4-digit hexcode or one of \
the wildcard symbols: `_` or `@`"
))
}
}
}
}
Expand All @@ -601,11 +610,11 @@ pub struct Namespace {
bytes: Vec<u8>,
}

impl TryFrom<&ast::PathOrLit> for Namespace {
impl TryFrom<&ast::MetaValue> for Namespace {
type Error = syn::Error;

fn try_from(value: &ast::PathOrLit) -> Result<Self, Self::Error> {
if let ast::PathOrLit::Lit(syn::Lit::Str(lit_str)) = value {
fn try_from(value: &ast::MetaValue) -> Result<Self, Self::Error> {
if let ast::MetaValue::Lit(syn::Lit::Str(lit_str)) = value {
let argument = lit_str.value();
syn::parse_str::<syn::Ident>(&argument).map_err(|_error| {
format_err_spanned!(
Expand Down
2 changes: 1 addition & 1 deletion crates/ink/ir/src/ir/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl TryFrom<ast::AttributeArgs> for Config {
if let Some((_, ast)) = env {
return Err(duplicate_config_err(ast, arg, "env", "contract"))
}
if let ast::PathOrLit::Path(path) = &arg.value {
if let ast::MetaValue::Path(path) = &arg.value {
env = Some((Environment { path: path.clone() }, arg))
} else {
return Err(format_err_spanned!(
Expand Down
7 changes: 7 additions & 0 deletions crates/ink/ir/src/ir/item_impl/callable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ where
<C as Callable>::has_wildcard_selector(self.callable)
}

fn has_wildcard_complement_selector(&self) -> bool {
<C as Callable>::has_wildcard_complement_selector(self.callable)
}

fn visibility(&self) -> Visibility {
<C as Callable>::visibility(self.callable)
}
Expand Down Expand Up @@ -180,6 +184,9 @@ pub trait Callable {
/// Returns `true` if the ink! callable is flagged as a wildcard selector.
fn has_wildcard_selector(&self) -> bool;

/// Returns `true` if the ink! callable is flagged as a wildcard complement selector.
fn has_wildcard_complement_selector(&self) -> bool;

/// Returns the visibility of the ink! callable.
fn visibility(&self) -> Visibility;

Expand Down
9 changes: 5 additions & 4 deletions crates/ink/ir/src/ir/item_impl/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,11 @@ impl Callable for Constructor {
}

fn has_wildcard_selector(&self) -> bool {
if let Some(SelectorOrWildcard::Wildcard) = self.selector {
return true
}
false
matches!(self.selector, Some(SelectorOrWildcard::Wildcard))
}

fn has_wildcard_complement_selector(&self) -> bool {
self.selector == Some(SelectorOrWildcard::wildcard_complement())
}

fn is_payable(&self) -> bool {
Expand Down
Loading