From 3663fb3536db70e0c5b83f5fae972ab30d88579b Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Mon, 20 Mar 2023 17:41:59 +0100 Subject: [PATCH 1/8] default attribute --- crates/ink/codegen/src/generator/metadata.rs | 4 + crates/ink/ir/src/ir/attrs.rs | 25 ++++ crates/ink/ir/src/ir/item_impl/callable.rs | 11 ++ crates/ink/ir/src/ir/item_impl/constructor.rs | 38 ++++++ crates/ink/ir/src/ir/item_impl/message.rs | 37 ++++++ .../ir/src/ir/trait_def/item/trait_item.rs | 1 + crates/metadata/src/specs.rs | 48 ++++++- crates/metadata/src/tests.rs | 121 +++++++++++++++++- 8 files changed, 278 insertions(+), 7 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata.rs b/crates/ink/codegen/src/generator/metadata.rs index 803372ca93..1c7e80abeb 100644 --- a/crates/ink/codegen/src/generator/metadata.rs +++ b/crates/ink/codegen/src/generator/metadata.rs @@ -140,6 +140,7 @@ impl Metadata<'_> { let selector_bytes = constructor.composed_selector().hex_lits(); let selector_id = constructor.composed_selector().into_be_u32(); let is_payable = constructor.is_payable(); + let is_default = constructor.is_default(); let constructor = constructor.callable(); let ident = constructor.ident(); let args = constructor.inputs().map(Self::generate_dispatch_argument); @@ -156,6 +157,7 @@ impl Metadata<'_> { #( #args ),* ]) .payable(#is_payable) + .default(#is_default) .returns(#ret_ty) .docs([ #( #docs ),* @@ -235,6 +237,7 @@ impl Metadata<'_> { .filter_map(|attr| attr.extract_docs()); let selector_bytes = message.composed_selector().hex_lits(); let is_payable = message.is_payable(); + let is_default = message.is_default(); let message = message.callable(); let mutates = message.receiver().is_ref_mut(); let ident = message.ident(); @@ -253,6 +256,7 @@ impl Metadata<'_> { .returns(#ret_ty) .mutates(#mutates) .payable(#is_payable) + .default(#is_default) .docs([ #( #docs ),* ]) diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 6aab9d2821..4077318d99 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -287,6 +287,12 @@ impl InkAttribute { .any(|arg| matches!(arg.kind(), AttributeArg::Payable)) } + /// Returns `true` if the ink! attribute contains the `default` argument. + pub fn is_default(&self) -> bool { + self.args() + .any(|arg| matches!(arg.kind(), AttributeArg::Default)) + } + /// Returns `true` if the ink! attribute contains the wildcard selector. pub fn has_wildcard_selector(&self) -> bool { self.args().any(|arg| { @@ -351,6 +357,8 @@ pub enum AttributeArgKind { Constructor, /// `#[ink(payable)]` Payable, + /// `#[ink(default)]` + Default, /// `#[ink(selector = _)]` /// `#[ink(selector = 0xDEADBEEF)]` Selector, @@ -403,6 +411,9 @@ pub enum AttributeArg { /// Applied on ink! constructors or messages in order to specify that they /// can receive funds from callers. Payable, + /// Applied on ink! constructors or messages in order to indicate + /// they are default. + Default, /// Can be either one of: /// /// - `#[ink(selector = 0xDEADBEEF)]` Applied on ink! constructors or messages to @@ -463,6 +474,7 @@ impl core::fmt::Display for AttributeArgKind { } Self::Implementation => write!(f, "impl"), Self::HandleStatus => write!(f, "handle_status"), + Self::Default => write!(f, "default"), } } } @@ -483,6 +495,7 @@ impl AttributeArg { Self::Namespace(_) => AttributeArgKind::Namespace, Self::Implementation => AttributeArgKind::Implementation, Self::HandleStatus(_) => AttributeArgKind::HandleStatus, + Self::Default => AttributeArgKind::Default, } } } @@ -506,6 +519,7 @@ impl core::fmt::Display for AttributeArg { } Self::Implementation => write!(f, "impl"), Self::HandleStatus(value) => write!(f, "handle_status = {value:?}"), + Self::Default => write!(f, "default") } } } @@ -959,6 +973,7 @@ impl Parse for AttributeFrag { "anonymous" => Ok(AttributeArg::Anonymous), "topic" => Ok(AttributeArg::Topic), "payable" => Ok(AttributeArg::Payable), + "default" => Ok(AttributeArg::Default), "impl" => Ok(AttributeArg::Implementation), _ => match ident.to_string().as_str() { "extension" => Err(format_err_spanned!( @@ -1217,6 +1232,16 @@ mod tests { ); } + #[test] + fn default_works() { + assert_attribute_try_from( + syn::parse_quote! { + #[ink(default)] + }, + Ok(test::Attribute::Ink(vec![AttributeArg::Default])) + ) + } + #[test] fn namespace_works() { assert_attribute_try_from( diff --git a/crates/ink/ir/src/ir/item_impl/callable.rs b/crates/ink/ir/src/ir/item_impl/callable.rs index e9ce912926..1005cae58a 100644 --- a/crates/ink/ir/src/ir/item_impl/callable.rs +++ b/crates/ink/ir/src/ir/item_impl/callable.rs @@ -116,6 +116,10 @@ where ::is_payable(self.callable) } + fn is_default(&self) -> bool { + ::is_default(self.callable) + } + fn has_wildcard_selector(&self) -> bool { ::has_wildcard_selector(self.callable) } @@ -166,6 +170,13 @@ pub trait Callable { /// Flagging as payable is done using the `#[ink(payable)]` attribute. fn is_payable(&self) -> bool; + /// Returns `true` if the ink! callable is flagged as default. + /// + /// # Note + /// + /// Flagging as default is done using the `#[ink(default)]` attribute. + fn is_default(&self) -> bool; + /// Returns `true` if the ink! callable is flagged as a wildcard selector. fn has_wildcard_selector(&self) -> bool; diff --git a/crates/ink/ir/src/ir/item_impl/constructor.rs b/crates/ink/ir/src/ir/item_impl/constructor.rs index bce50923a6..a8c234cf04 100644 --- a/crates/ink/ir/src/ir/item_impl/constructor.rs +++ b/crates/ink/ir/src/ir/item_impl/constructor.rs @@ -70,6 +70,8 @@ pub struct Constructor { pub(super) item: syn::ImplItemFn, /// If the ink! constructor can receive funds. is_payable: bool, + /// If the ink! constructor is default. + is_default: bool, /// An optional user provided selector. /// /// # Note @@ -139,6 +141,7 @@ impl Constructor { match arg.kind() { ir::AttributeArg::Constructor | ir::AttributeArg::Payable + | ir::AttributeArg::Default | ir::AttributeArg::Selector(_) => Ok(()), _ => Err(None), } @@ -156,10 +159,12 @@ impl TryFrom for Constructor { Self::ensure_no_self_receiver(&method_item)?; let (ink_attrs, other_attrs) = Self::sanitize_attributes(&method_item)?; let is_payable = ink_attrs.is_payable(); + let is_default = ink_attrs.is_default(); let selector = ink_attrs.selector(); Ok(Constructor { selector, is_payable, + is_default, item: syn::ImplItemFn { attrs: other_attrs, ..method_item @@ -195,6 +200,10 @@ impl Callable for Constructor { self.is_payable } + fn is_default(&self) -> bool { + self.is_default + } + fn visibility(&self) -> Visibility { match &self.item.vis { syn::Visibility::Public(vis_public) => Visibility::Public(*vis_public), @@ -214,6 +223,7 @@ impl Callable for Constructor { fn statements(&self) -> &[syn::Stmt] { &self.item.block.stmts } + } impl Constructor { @@ -336,6 +346,34 @@ mod tests { } } + #[test] + fn is_default_works() { + let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![ + // Not default. + ( + false, + syn::parse_quote! { + #[ink(constructor)] + fn my_constructor() -> Self {} + }, + ), + // Default constructor. + ( + true, + syn::parse_quote! { + #[ink(constructor, default)] + pub fn my_constructor() -> Self {} + }, + ), + ]; + for (expect_default, item_method) in test_inputs { + let is_default = >::try_from(item_method) + .unwrap() + .is_default(); + assert_eq!(is_default, expect_default); + } + } + #[test] fn visibility_works() { let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![ diff --git a/crates/ink/ir/src/ir/item_impl/message.rs b/crates/ink/ir/src/ir/item_impl/message.rs index 3ee6c3efc7..0a594adfff 100644 --- a/crates/ink/ir/src/ir/item_impl/message.rs +++ b/crates/ink/ir/src/ir/item_impl/message.rs @@ -100,6 +100,8 @@ pub struct Message { pub(super) item: syn::ImplItemFn, /// If the ink! message can receive funds. is_payable: bool, + /// If the ink! message is default. + is_default: bool, /// An optional user provided selector. /// /// # Note @@ -185,6 +187,7 @@ impl Message { match arg.kind() { ir::AttributeArg::Message | ir::AttributeArg::Payable + | ir::AttributeArg::Default | ir::AttributeArg::Selector(_) => Ok(()), _ => Err(None), } @@ -202,9 +205,11 @@ impl TryFrom for Message { Self::ensure_not_return_self(&method_item)?; let (ink_attrs, other_attrs) = Self::sanitize_attributes(&method_item)?; let is_payable = ink_attrs.is_payable(); + let is_default = ink_attrs.is_default(); let selector = ink_attrs.selector(); Ok(Self { is_payable, + is_default, selector, item: syn::ImplItemFn { attrs: other_attrs, @@ -241,6 +246,10 @@ impl Callable for Message { self.is_payable } + fn is_default(&self) -> bool { + self.is_default + } + fn visibility(&self) -> Visibility { match &self.item.vis { syn::Visibility::Public(vis_public) => Visibility::Public(*vis_public), @@ -466,6 +475,34 @@ mod tests { } } + #[test] + fn is_default_works() { + let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![ + // Not default. + ( + false, + syn::parse_quote! { + #[ink(message)] + fn my_message(&self) {} + }, + ), + // Default message. + ( + true, + syn::parse_quote! { + #[ink(message, payable, default)] + pub fn my_message(&self) {} + }, + ), + ]; + for (expect_default, item_method) in test_inputs { + let is_default = >::try_from(item_method) + .unwrap() + .is_default(); + assert_eq!(is_default, expect_default); + } + } + #[test] fn receiver_works() { let test_inputs: Vec<(Receiver, syn::ImplItemFn)> = vec![ diff --git a/crates/ink/ir/src/ir/trait_def/item/trait_item.rs b/crates/ink/ir/src/ir/trait_def/item/trait_item.rs index 3740b8d4fc..9e215717ba 100644 --- a/crates/ink/ir/src/ir/trait_def/item/trait_item.rs +++ b/crates/ink/ir/src/ir/trait_def/item/trait_item.rs @@ -92,6 +92,7 @@ impl<'a> InkTraitMessage<'a> { Err(Some(format_err!(arg.span(), "wildcard selectors are only supported for inherent ink! messages or constructors, not for traits."))), ir::AttributeArg::Message | ir::AttributeArg::Payable + | ir::AttributeArg::Default | ir::AttributeArg::Selector(_) => Ok(()), _ => Err(None), } diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index b8b71b4a8b..879758b48f 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -228,6 +228,10 @@ where !self.spec.messages.is_empty(), "must have at least one message" ); + assert!(self.spec.constructors.iter().filter(|c| c.default).count() < 2, + "only one default constructor is allowed"); + assert!(self.spec.messages.iter().filter(|m| m.default).count() < 2, + "only one default message is allowed"); self.spec } } @@ -275,6 +279,8 @@ pub struct ConstructorSpec { pub return_type: ReturnTypeSpec, /// The deployment handler documentation. pub docs: Vec, + /// If the constructor is default + default: bool } impl IntoPortable for ConstructorSpec { @@ -292,6 +298,7 @@ impl IntoPortable for ConstructorSpec { .collect::>(), return_type: self.return_type.into_portable(registry), docs: self.docs.into_iter().map(|s| s.into()).collect(), + default: self.default, } } } @@ -332,6 +339,8 @@ where pub fn docs(&self) -> &[F::String] { &self.docs } + + pub fn default(&self) -> &bool { &self.default } } /// A builder for constructors. @@ -369,6 +378,7 @@ where args: Vec::new(), return_type: ReturnTypeSpec::new(None), docs: Vec::new(), + default: false, }, marker: PhantomData, } @@ -417,7 +427,7 @@ impl ConstructorSpecBuilder> where F: Form, { - /// Sets the return type of the message. + /// Sets the return type of the constructor. pub fn returns( self, return_type: ReturnTypeSpec, @@ -436,7 +446,7 @@ impl ConstructorSpecBuilder where F: Form, { - /// Sets the input arguments of the message specification. + /// Sets the input arguments of the constructor specification. pub fn args(self, args: A) -> Self where A: IntoIterator>, @@ -447,7 +457,7 @@ where this } - /// Sets the documentation of the message specification. + /// Sets the documentation of the constructor specification. pub fn docs<'a, D>(self, docs: D) -> Self where D: IntoIterator, @@ -461,6 +471,19 @@ where .collect::>(); this } + + /// Sets the default of the constructor specification. + pub fn default(self, default: bool) -> Self + { + ConstructorSpecBuilder { + spec: ConstructorSpec { + default, + ..self.spec + }, + marker: PhantomData, + } + } + } impl ConstructorSpecBuilder @@ -498,6 +521,8 @@ pub struct MessageSpec { return_type: ReturnTypeSpec, /// The message documentation. docs: Vec, + /// If the message is default + default: bool } /// Type state for builders to tell that some mandatory state has not yet been set @@ -541,6 +566,7 @@ where args: Vec::new(), return_type: ReturnTypeSpec::new(None), docs: Vec::new(), + default: false, }, marker: PhantomData, } @@ -588,6 +614,8 @@ where pub fn docs(&self) -> &[F::String] { &self.docs } + + pub fn default(&self) -> &bool { &self.default } } /// A builder for messages. @@ -709,6 +737,19 @@ where this.spec.docs = docs.into_iter().collect::>(); this } + + /// Sets the default of the message specification. + pub fn default(self, default: bool) -> Self + { + MessageSpecBuilder { + spec: MessageSpec { + default, + ..self.spec + }, + marker: PhantomData, + } + } + } impl @@ -737,6 +778,7 @@ impl IntoPortable for MessageSpec { selector: self.selector, mutates: self.mutates, payable: self.payable, + default: self.default, args: self .args .into_iter() diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs index c539ffc377..ab8cbf7b45 100644 --- a/crates/metadata/src/tests.rs +++ b/crates/metadata/src/tests.rs @@ -47,12 +47,114 @@ fn spec_constructor_selector_must_serialize_to_hex() { "selector": "0x075bcd15", "returnType": null, "args": [], - "docs": [] + "docs": [], + "default": false, }) ); assert_eq!(deserialized.selector, portable_spec.selector); } +#[test] +#[should_panic(expected = "only one default message allowed")] +fn spec_contract_only_one_default_message_allowed() { + ContractSpec::new() + .constructors(vec![ + ConstructorSpec::from_label("new") + .selector([94u8, 189u8, 136u8, 214u8]) + .payable(true) + .args(vec![MessageParamSpec::new("init_value") + .of_type(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + )) + .done()]) + .returns(ReturnTypeSpec::new(None)) + .docs(Vec::new()) + .done() + ]) + .messages(vec![ + MessageSpec::from_label("inc") + .selector([231u8, 208u8, 89u8, 15u8]) + .mutates(true) + .payable(true) + .args(vec![MessageParamSpec::new("by") + .of_type(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + )) + .done()]) + .returns(ReturnTypeSpec::new(None)) + .default(true) + .done(), + MessageSpec::from_label("get") + .selector([37u8, 68u8, 74u8, 254u8]) + .mutates(false) + .payable(false) + .args(Vec::new()) + .returns(ReturnTypeSpec::new(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + ))) + .default(true) + .done(), + ]) + .events(Vec::new()) + .lang_error(TypeSpec::with_name_segs::( + ::core::iter::Iterator::map( + ::core::iter::IntoIterator::into_iter(["ink", "LangError"]), + ::core::convert::AsRef::as_ref, + ), + )) + .done(); +} + +#[test] +#[should_panic(expected = "only one default constructor allowed")] +fn spec_contract_only_one_default_constructor_allowed() { + ContractSpec::new() + .constructors(vec![ + ConstructorSpec::from_label("new") + .selector([94u8, 189u8, 136u8, 214u8]) + .payable(true) + .args(vec![MessageParamSpec::new("init_value") + .of_type(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + )) + .done()]) + .returns(ReturnTypeSpec::new(None)) + .docs(Vec::new()) + .default(true) + .done(), + ConstructorSpec::from_label("default") + .selector([2u8, 34u8, 255u8, 24u8]) + .payable(Default::default()) + .args(Vec::new()) + .returns(ReturnTypeSpec::new(None)) + .docs(Vec::new()) + .default(true) + .done() + ]) + .messages(vec![ + MessageSpec::from_label("inc") + .selector([231u8, 208u8, 89u8, 15u8]) + .mutates(true) + .payable(true) + .args(vec![MessageParamSpec::new("by") + .of_type(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + )) + .done()]) + .returns(ReturnTypeSpec::new(None)) + .default(true) + .done() + ]) + .events(Vec::new()) + .lang_error(TypeSpec::with_name_segs::( + ::core::iter::Iterator::map( + ::core::iter::IntoIterator::into_iter(["ink", "LangError"]), + ::core::convert::AsRef::as_ref, + ), + )) + .done(); +} + #[test] fn spec_contract_json() { // given @@ -75,6 +177,7 @@ fn spec_contract_json() { .args(Vec::new()) .returns(ReturnTypeSpec::new(None)) .docs(Vec::new()) + .default(true) .done(), ConstructorSpec::from_label("result_new") .selector([6u8, 3u8, 55u8, 123u8]) @@ -99,6 +202,7 @@ fn spec_contract_json() { )) .done()]) .returns(ReturnTypeSpec::new(None)) + .default(true) .done(), MessageSpec::from_label("get") .selector([37u8, 68u8, 74u8, 254u8]) @@ -142,6 +246,7 @@ fn spec_contract_json() { } ], "docs": [], + "default": false, "label": "new", "payable": true, "returnType": null, @@ -150,6 +255,7 @@ fn spec_contract_json() { { "args": [], "docs": [], + "default": true, "label": "default", "payable": false, "returnType": null, @@ -158,6 +264,7 @@ fn spec_contract_json() { { "args": [], "docs": [], + "default": false, "label": "result_new", "payable": false, "returnType": { @@ -193,6 +300,7 @@ fn spec_contract_json() { } } ], + "default": true, "docs": [], "mutates": true, "payable": true, @@ -202,6 +310,7 @@ fn spec_contract_json() { }, { "args": [], + "default": false, "docs": [], "mutates": false, "payable": false, @@ -247,7 +356,8 @@ fn trim_docs() { "returnType": null, "selector": "0x075bcd15", "args": [], - "docs": ["foobar"] + "docs": ["foobar"], + "default": false }) ); assert_eq!(deserialized.docs, compact_spec.docs); @@ -295,7 +405,8 @@ fn trim_docs_with_code() { " \"Hello, World\"", "}", "```" - ] + ], + "default": false }) ); assert_eq!(deserialized.docs, compact_spec.docs); @@ -382,7 +493,8 @@ fn construct_runtime_contract_spec() { "docs": [ "foo", "bar" - ] + ], + "default": false } ); assert_eq!(constructor_spec, expected_constructor_spec); @@ -411,6 +523,7 @@ fn construct_runtime_contract_spec() { "FooType" ] }, + "default": false, "docs": [ "foo", "bar" From 2e5ddf9847570f829b40ef6b09c2278797c251ae Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Mon, 20 Mar 2023 23:33:23 +0100 Subject: [PATCH 2/8] fmt --- crates/ink/ir/src/ir/attrs.rs | 4 +- crates/ink/ir/src/ir/item_impl/constructor.rs | 1 - crates/metadata/src/specs.rs | 32 ++++++----- crates/metadata/src/tests.rs | 56 +++++++++---------- 4 files changed, 46 insertions(+), 47 deletions(-) diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 4077318d99..7f821e66ee 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -519,7 +519,7 @@ impl core::fmt::Display for AttributeArg { } Self::Implementation => write!(f, "impl"), Self::HandleStatus(value) => write!(f, "handle_status = {value:?}"), - Self::Default => write!(f, "default") + Self::Default => write!(f, "default"), } } } @@ -1238,7 +1238,7 @@ mod tests { syn::parse_quote! { #[ink(default)] }, - Ok(test::Attribute::Ink(vec![AttributeArg::Default])) + Ok(test::Attribute::Ink(vec![AttributeArg::Default])), ) } diff --git a/crates/ink/ir/src/ir/item_impl/constructor.rs b/crates/ink/ir/src/ir/item_impl/constructor.rs index a8c234cf04..30d8a255fa 100644 --- a/crates/ink/ir/src/ir/item_impl/constructor.rs +++ b/crates/ink/ir/src/ir/item_impl/constructor.rs @@ -223,7 +223,6 @@ impl Callable for Constructor { fn statements(&self) -> &[syn::Stmt] { &self.item.block.stmts } - } impl Constructor { diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 879758b48f..cc795ce311 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -228,10 +228,14 @@ where !self.spec.messages.is_empty(), "must have at least one message" ); - assert!(self.spec.constructors.iter().filter(|c| c.default).count() < 2, - "only one default constructor is allowed"); - assert!(self.spec.messages.iter().filter(|m| m.default).count() < 2, - "only one default message is allowed"); + assert!( + self.spec.constructors.iter().filter(|c| c.default).count() < 2, + "only one default constructor is allowed" + ); + assert!( + self.spec.messages.iter().filter(|m| m.default).count() < 2, + "only one default message is allowed" + ); self.spec } } @@ -280,7 +284,7 @@ pub struct ConstructorSpec { /// The deployment handler documentation. pub docs: Vec, /// If the constructor is default - default: bool + default: bool, } impl IntoPortable for ConstructorSpec { @@ -340,7 +344,9 @@ where &self.docs } - pub fn default(&self) -> &bool { &self.default } + pub fn default(&self) -> &bool { + &self.default + } } /// A builder for constructors. @@ -473,8 +479,7 @@ where } /// Sets the default of the constructor specification. - pub fn default(self, default: bool) -> Self - { + pub fn default(self, default: bool) -> Self { ConstructorSpecBuilder { spec: ConstructorSpec { default, @@ -483,7 +488,6 @@ where marker: PhantomData, } } - } impl ConstructorSpecBuilder @@ -522,7 +526,7 @@ pub struct MessageSpec { /// The message documentation. docs: Vec, /// If the message is default - default: bool + default: bool, } /// Type state for builders to tell that some mandatory state has not yet been set @@ -615,7 +619,9 @@ where &self.docs } - pub fn default(&self) -> &bool { &self.default } + pub fn default(&self) -> &bool { + &self.default + } } /// A builder for messages. @@ -739,8 +745,7 @@ where } /// Sets the default of the message specification. - pub fn default(self, default: bool) -> Self - { + pub fn default(self, default: bool) -> Self { MessageSpecBuilder { spec: MessageSpec { default, @@ -749,7 +754,6 @@ where marker: PhantomData, } } - } impl diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs index ab8cbf7b45..b2f71a6982 100644 --- a/crates/metadata/src/tests.rs +++ b/crates/metadata/src/tests.rs @@ -57,20 +57,18 @@ fn spec_constructor_selector_must_serialize_to_hex() { #[test] #[should_panic(expected = "only one default message allowed")] fn spec_contract_only_one_default_message_allowed() { - ContractSpec::new() - .constructors(vec![ - ConstructorSpec::from_label("new") - .selector([94u8, 189u8, 136u8, 214u8]) - .payable(true) - .args(vec![MessageParamSpec::new("init_value") - .of_type(TypeSpec::with_name_segs::( - vec!["i32"].into_iter().map(AsRef::as_ref), - )) - .done()]) - .returns(ReturnTypeSpec::new(None)) - .docs(Vec::new()) - .done() - ]) + ContractSpec::new() + .constructors(vec![ConstructorSpec::from_label("new") + .selector([94u8, 189u8, 136u8, 214u8]) + .payable(true) + .args(vec![MessageParamSpec::new("init_value") + .of_type(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + )) + .done()]) + .returns(ReturnTypeSpec::new(None)) + .docs(Vec::new()) + .done()]) .messages(vec![ MessageSpec::from_label("inc") .selector([231u8, 208u8, 89u8, 15u8]) @@ -108,7 +106,7 @@ fn spec_contract_only_one_default_message_allowed() { #[test] #[should_panic(expected = "only one default constructor allowed")] fn spec_contract_only_one_default_constructor_allowed() { - ContractSpec::new() + ContractSpec::new() .constructors(vec![ ConstructorSpec::from_label("new") .selector([94u8, 189u8, 136u8, 214u8]) @@ -129,22 +127,20 @@ fn spec_contract_only_one_default_constructor_allowed() { .returns(ReturnTypeSpec::new(None)) .docs(Vec::new()) .default(true) - .done() - ]) - .messages(vec![ - MessageSpec::from_label("inc") - .selector([231u8, 208u8, 89u8, 15u8]) - .mutates(true) - .payable(true) - .args(vec![MessageParamSpec::new("by") - .of_type(TypeSpec::with_name_segs::( - vec!["i32"].into_iter().map(AsRef::as_ref), - )) - .done()]) - .returns(ReturnTypeSpec::new(None)) - .default(true) - .done() + .done(), ]) + .messages(vec![MessageSpec::from_label("inc") + .selector([231u8, 208u8, 89u8, 15u8]) + .mutates(true) + .payable(true) + .args(vec![MessageParamSpec::new("by") + .of_type(TypeSpec::with_name_segs::( + vec!["i32"].into_iter().map(AsRef::as_ref), + )) + .done()]) + .returns(ReturnTypeSpec::new(None)) + .default(true) + .done()]) .events(Vec::new()) .lang_error(TypeSpec::with_name_segs::( ::core::iter::Iterator::map( From 05bd2df149f138d4b827e542c861633391afbc50 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Tue, 21 Mar 2023 00:10:45 +0100 Subject: [PATCH 3/8] fix tests --- crates/metadata/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs index b2f71a6982..0d51aafd57 100644 --- a/crates/metadata/src/tests.rs +++ b/crates/metadata/src/tests.rs @@ -55,7 +55,7 @@ fn spec_constructor_selector_must_serialize_to_hex() { } #[test] -#[should_panic(expected = "only one default message allowed")] +#[should_panic(expected = "only one default message is allowed")] fn spec_contract_only_one_default_message_allowed() { ContractSpec::new() .constructors(vec![ConstructorSpec::from_label("new") @@ -104,7 +104,7 @@ fn spec_contract_only_one_default_message_allowed() { } #[test] -#[should_panic(expected = "only one default constructor allowed")] +#[should_panic(expected = "only one default constructor is allowed")] fn spec_contract_only_one_default_constructor_allowed() { ContractSpec::new() .constructors(vec![ From 06dd55b8c5ddd1309644758d907b4f6a19970e16 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Tue, 28 Mar 2023 23:01:07 +0200 Subject: [PATCH 4/8] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aacbef652a..f0bf06014e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Upgraded `syn` to version `2` - [#1731](https://github.com/paritytech/ink/pull/1731) +- Added `default` attribute to constructors and messages - [#1703](https://github.com/paritytech/ink/pull/1724) ## Version 4.1.0 From 4b31df5d31500a6452620f872cbbb0f1ee5b4b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Wed, 12 Apr 2023 15:41:07 +0200 Subject: [PATCH 5/8] Update crates/metadata/src/specs.rs --- crates/metadata/src/specs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index cc795ce311..52456707c7 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -283,7 +283,7 @@ pub struct ConstructorSpec { pub return_type: ReturnTypeSpec, /// The deployment handler documentation. pub docs: Vec, - /// If the constructor is default + /// If the constructor is default. default: bool, } From 5764c79bc9fbb66094c4fb43c5bf6a9101ab9a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Wed, 12 Apr 2023 15:41:16 +0200 Subject: [PATCH 6/8] Update crates/metadata/src/specs.rs --- crates/metadata/src/specs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 52456707c7..d6cdbc3cf8 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -525,7 +525,7 @@ pub struct MessageSpec { return_type: ReturnTypeSpec, /// The message documentation. docs: Vec, - /// If the message is default + /// If the message is default. default: bool, } From f1d8ae43ca993d9f7867eb076743948b38e80cbf Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Wed, 12 Apr 2023 15:43:34 +0200 Subject: [PATCH 7/8] Apply suggestions from code review --- crates/metadata/src/specs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index d6cdbc3cf8..4af5ffb6a6 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -283,7 +283,7 @@ pub struct ConstructorSpec { pub return_type: ReturnTypeSpec, /// The deployment handler documentation. pub docs: Vec, - /// If the constructor is default. + /// If the constructor is the default for off-chain consumers (e.g UIs). default: bool, } @@ -525,7 +525,7 @@ pub struct MessageSpec { return_type: ReturnTypeSpec, /// The message documentation. docs: Vec, - /// If the message is default. + /// If the message is the default for off-chain consumers (e.g UIs). default: bool, } From 8ab22b7528044473468c46f9a01abfbc4990f794 Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Sat, 15 Apr 2023 14:22:07 +0100 Subject: [PATCH 8/8] Add UIs to dictionary --- .config/cargo_spellcheck.dic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/cargo_spellcheck.dic b/.config/cargo_spellcheck.dic index 463c3ac312..284c18234a 100644 --- a/.config/cargo_spellcheck.dic +++ b/.config/cargo_spellcheck.dic @@ -15,7 +15,7 @@ KECCAK Polkadot RPC SHA -UI +UI/S URI Wasm Wasm32