From 6fa4343e5df8fd025179bceeec527ef8874ad78f Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 3 Nov 2023 11:45:41 +0100 Subject: [PATCH 1/4] Merge runtime / runtime-only (#1968) --- crates/e2e/macro/src/codegen.rs | 4 +- crates/e2e/macro/src/config.rs | 40 ++++++++++--------- .../e2e-runtime-only-backend/lib.rs | 6 +-- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 8c5f0fcafb5..d146ee389c2 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -67,8 +67,8 @@ impl InkE2ETest { let client_building = match self.test.config.backend() { Backend::Full => build_full_client(&environment, exec_build_contracts), #[cfg(any(test, feature = "drink"))] - Backend::RuntimeOnly => { - build_runtime_client(exec_build_contracts, self.test.config.runtime()) + Backend::RuntimeOnly { runtime } => { + build_runtime_client(exec_build_contracts, runtime) } }; diff --git a/crates/e2e/macro/src/config.rs b/crates/e2e/macro/src/config.rs index 0cc5d31e0cb..383e9c27b69 100644 --- a/crates/e2e/macro/src/config.rs +++ b/crates/e2e/macro/src/config.rs @@ -13,18 +13,20 @@ // limitations under the License. /// The type of the architecture that should be used to run test. -#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, darling::FromMeta)] +#[derive(Clone, Eq, PartialEq, Debug, Default, darling::FromMeta)] +#[darling(rename_all = "snake_case")] pub enum Backend { /// The standard approach with running dedicated single-node blockchain in a /// background process. #[default] Full, + /// The lightweight approach skipping node layer. /// /// This runs a runtime emulator within `TestExternalities` (using drink! library) in /// the same process as the test. #[cfg(any(test, feature = "drink"))] - RuntimeOnly, + RuntimeOnly { runtime: Option }, } /// The End-to-End test configuration. @@ -44,10 +46,6 @@ pub struct E2EConfig { /// The type of the architecture that should be used to run test. #[darling(default)] backend: Backend, - /// The runtime to use for the runtime only test. - #[cfg(any(test, feature = "drink"))] - #[darling(default)] - runtime: Option, } impl E2EConfig { @@ -73,13 +71,7 @@ impl E2EConfig { /// The type of the architecture that should be used to run test. pub fn backend(&self) -> Backend { - self.backend - } - - /// The runtime to use for the runtime only test. - #[cfg(any(test, feature = "drink"))] - pub fn runtime(&self) -> Option { - self.runtime.clone() + self.backend.clone() } } @@ -97,8 +89,7 @@ mod tests { let input = quote! { additional_contracts = "adder/Cargo.toml flipper/Cargo.toml", environment = crate::CustomEnvironment, - backend = "runtime_only", - runtime = ::drink::MinimalRuntime, + backend(runtime_only()), }; let config = E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap(); @@ -111,10 +102,23 @@ mod tests { config.environment(), Some(syn::parse_quote! { crate::CustomEnvironment }) ); - assert_eq!(config.backend(), Backend::RuntimeOnly); + + assert_eq!(config.backend(), Backend::RuntimeOnly { runtime: None }); + } + + #[test] + fn config_works_with_custom_backend() { + let input = quote! { + backend(runtime_only(runtime = ::ink_e2e::MinimalRuntime)), + }; + let config = + E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap(); + assert_eq!( - config.runtime(), - Some(syn::parse_quote! { ::drink::MinimalRuntime }) + config.backend(), + Backend::RuntimeOnly { + runtime: Some(syn::parse_quote! { ::ink_e2e::MinimalRuntime }) + } ); } } diff --git a/integration-tests/e2e-runtime-only-backend/lib.rs b/integration-tests/e2e-runtime-only-backend/lib.rs index 32f3fdd491f..a0c51c012b7 100644 --- a/integration-tests/e2e-runtime-only-backend/lib.rs +++ b/integration-tests/e2e-runtime-only-backend/lib.rs @@ -55,7 +55,7 @@ pub mod flipper { /// - flip the flipper /// - get the flipper's value /// - assert that the value is `true` - #[ink_e2e::test(backend = "runtime_only")] + #[ink_e2e::test(backend(runtime_only()))] async fn it_works(mut client: Client) -> E2EResult<()> { // given const INITIAL_VALUE: bool = false; @@ -88,7 +88,7 @@ pub mod flipper { /// - transfer some funds to the contract using runtime call /// - get the contract's balance again /// - assert that the contract's balance increased by the transferred amount - #[ink_e2e::test(backend = "runtime_only")] + #[ink_e2e::test(backend(runtime_only()))] async fn runtime_call_works() -> E2EResult<()> { // given let mut constructor = FlipperRef::new(false); @@ -141,7 +141,7 @@ pub mod flipper { } /// Just instantiate a contract using non-default runtime. - #[ink_e2e::test(backend = "runtime_only", runtime = ink_e2e::MinimalRuntime)] + #[ink_e2e::test(backend(runtime_only(runtime = ink_e2e::MinimalRuntime)))] async fn custom_runtime(mut client: Client) -> E2EResult<()> { client .instantiate( From c7794b5debe19e10621692b0675d68c558b5ad5a Mon Sep 17 00:00:00 2001 From: GoodDaisy <90915921+GoodDaisy@users.noreply.github.com> Date: Mon, 6 Nov 2023 17:49:20 +0800 Subject: [PATCH 2/4] chore: fix typos (#1973) --- CONTRIBUTING.md | 2 +- crates/ink/macro/src/lib.rs | 2 +- crates/ink/tests/ui/chain_extension/E-01-simple.rs | 2 +- .../lang-err-integration-tests/integration-flipper/lib.rs | 2 +- linting/src/storage_never_freed.rs | 2 +- linting/src/strict_balance_equality.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3884049276f..516d40e75f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,7 +94,7 @@ older nodes, please do the following: 1. Mark the old `ink_env::function()` (which depends on the imported `[seal0]` function) with the `#[deprecated]` attribute. Please, specify the `since` field with the ink! version which will introduce the new API. We will leave this function in for backwards - compatibility purposes. Specifing some additional helpful info in the `note` field + compatibility purposes. Specifying some additional helpful info in the `note` field could also be a good idea. 2. Name the new function (which depends on the `[seal1] function()`) in a descriptive way, like `ink_env::function_whats_special()`. diff --git a/crates/ink/macro/src/lib.rs b/crates/ink/macro/src/lib.rs index fe00872725b..ba1e2e5cafb 100644 --- a/crates/ink/macro/src/lib.rs +++ b/crates/ink/macro/src/lib.rs @@ -1064,7 +1064,7 @@ pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream { /// #[ink(extension = 4, handle_status = false)] /// fn access(key: &[u8]) -> Option; /// -/// /// Unlocks previously aquired permission to access key. +/// /// Unlocks previously acquired permission to access key. /// /// /// /// # Errors /// /// diff --git a/crates/ink/tests/ui/chain_extension/E-01-simple.rs b/crates/ink/tests/ui/chain_extension/E-01-simple.rs index 6c559673a2b..5e2ae3ab185 100644 --- a/crates/ink/tests/ui/chain_extension/E-01-simple.rs +++ b/crates/ink/tests/ui/chain_extension/E-01-simple.rs @@ -29,7 +29,7 @@ pub trait RuntimeReadWrite { #[ink(extension = 4, handle_status = false)] fn access(key: &[u8]) -> Option; - /// Unlocks previously aquired permission to access key. + /// Unlocks previously acquired permission to access key. /// /// # Errors /// diff --git a/integration-tests/lang-err-integration-tests/integration-flipper/lib.rs b/integration-tests/lang-err-integration-tests/integration-flipper/lib.rs index a4207420a03..213fbca6776 100644 --- a/integration-tests/lang-err-integration-tests/integration-flipper/lib.rs +++ b/integration-tests/lang-err-integration-tests/integration-flipper/lib.rs @@ -30,7 +30,7 @@ pub mod integration_flipper { Self::new(Default::default()) } - /// Attemps to create a new integration_flipper smart contract initialized with + /// Attempts to create a new integration_flipper smart contract initialized with /// the given value. #[ink(constructor)] pub fn try_new(succeed: bool) -> Result { diff --git a/linting/src/storage_never_freed.rs b/linting/src/storage_never_freed.rs index 591edc87870..6f623fd5d19 100644 --- a/linting/src/storage_never_freed.rs +++ b/linting/src/storage_never_freed.rs @@ -212,7 +212,7 @@ fn find_collection_fields(cx: &LateContext, storage_struct_id: ItemId) -> Fields result } -/// Reports the given field defintion +/// Reports the given field definition fn report_field(cx: &LateContext, field_info: &FieldInfo) { if_chain! { if let Node::Field(field) = cx.tcx.hir().get_by_def_id(field_info.did); diff --git a/linting/src/strict_balance_equality.rs b/linting/src/strict_balance_equality.rs index c68409676e3..bdcc7705dbe 100644 --- a/linting/src/strict_balance_equality.rs +++ b/linting/src/strict_balance_equality.rs @@ -432,7 +432,7 @@ impl<'tcx> TransferFunction<'_, 'tcx> { return }; - // Handle `PartialEq` functions that implement comparsion for non-primitive types, + // Handle `PartialEq` functions that implement comparison for non-primitive types, // including references like `&i32`. if_chain! { if init_taints.len() == 2; From 89f0d4acf42b25f3007e984140398c0de3e88546 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:16:41 +0000 Subject: [PATCH 3/4] Update drink requirement from =0.5.3 to =0.5.4 (#1956) Updates the requirements on [drink](https://github.com/Cardinal-Cryptography/drink) to permit the latest version. - [Commits](https://github.com/Cardinal-Cryptography/drink/commits) --- updated-dependencies: - dependency-name: drink dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 83241dbfa7a..a865a188eed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ cfg-if = { version = "1.0" } contract-build = { version = "3.2.0" } darling = { version = "0.20.3" } derive_more = { version = "0.99.17", default-features = false } -drink = { version = "=0.5.3" } +drink = { version = "=0.5.4" } either = { version = "1.5", default-features = false } funty = { version = "2.0.0" } heck = { version = "0.4.0" } From 79d84e3e5d23a2aa4094c1d0b9916292c45e2a2c Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Mon, 6 Nov 2023 19:56:15 +0100 Subject: [PATCH 4/4] `Lazy`: Account for key size in fallible storage ops (#1962) Followup to #1910. The on-chain engine encodes the key and the value into the scoped buffer, so we need to account for both (same as Mapping). --- crates/storage/src/lazy/mod.rs | 39 ++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/crates/storage/src/lazy/mod.rs b/crates/storage/src/lazy/mod.rs index 058c975c0ec..c2ceda7fb85 100644 --- a/crates/storage/src/lazy/mod.rs +++ b/crates/storage/src/lazy/mod.rs @@ -148,16 +148,25 @@ where /// Try to read the `value` from the contract storage. /// + /// To successfully retrieve the `value`, the encoded `key` and `value` + /// must both fit into the static buffer together. + /// /// Returns: /// - `Some(Ok(_))` if `value` was received from storage and could be decoded. - /// - `Some(Err(_))` if the encoded length of `value` exceeds the static buffer size. + /// - `Some(Err(_))` if retrieving the `value` would exceed the static buffer size. /// - `None` if there was no value under this storage key. pub fn try_get(&self) -> Option> { - let encoded_length: usize = ink_env::contains_contract_storage(&KeyType::KEY)? + let key_size = ::encoded_size(&KeyType::KEY); + + if key_size >= ink_env::BUFFER_SIZE { + return Some(Err(ink_env::Error::BufferTooSmall)) + } + + let value_size: usize = ink_env::contains_contract_storage(&KeyType::KEY)? .try_into() .expect("targets of less than 32bit pointer size are not supported; qed"); - if encoded_length > ink_env::BUFFER_SIZE { + if key_size.saturating_add(value_size) > ink_env::BUFFER_SIZE { return Some(Err(ink_env::Error::BufferTooSmall)) } @@ -175,9 +184,13 @@ where /// Try to set the given `value` to the contract storage. /// - /// Fails if `value` exceeds the static buffer size. + /// To successfully store the `value`, the encoded `key` and `value` + /// must fit into the static buffer together. pub fn try_set(&mut self, value: &V) -> ink_env::Result<()> { - if value.encoded_size() > ink_env::BUFFER_SIZE { + let key_size = ::encoded_size(&KeyType::KEY); + let value_size = ::encoded_size(value); + + if key_size.saturating_add(value_size) > ink_env::BUFFER_SIZE { return Err(ink_env::Error::BufferTooSmall) }; @@ -317,9 +330,13 @@ mod tests { #[test] fn fallible_storage_works_for_fitting_data() { ink_env::test::run_test::(|_| { - let mut storage: Lazy<[u8; ink_env::BUFFER_SIZE]> = Lazy::new(); + // The default `Key` is an 4 byte int + const KEY_SIZE: usize = 4; + const VALUE_SIZE: usize = ink_env::BUFFER_SIZE - KEY_SIZE; - let value = [0u8; ink_env::BUFFER_SIZE]; + let mut storage: Lazy<[u8; VALUE_SIZE]> = Lazy::new(); + + let value = [0u8; VALUE_SIZE]; assert_eq!(storage.try_set(&value), Ok(())); assert_eq!(storage.try_get(), Some(Ok(value))); @@ -331,9 +348,13 @@ mod tests { #[test] fn fallible_storage_fails_gracefully_for_overgrown_data() { ink_env::test::run_test::(|_| { - let mut storage: Lazy<[u8; ink_env::BUFFER_SIZE + 1]> = Lazy::new(); + // The default `Key` is an 4 byte int + const KEY_SIZE: usize = 4; + const VALUE_SIZE: usize = ink_env::BUFFER_SIZE - KEY_SIZE + 1; + + let mut storage: Lazy<[u8; VALUE_SIZE]> = Lazy::new(); - let value = [0u8; ink_env::BUFFER_SIZE + 1]; + let value = [0u8; VALUE_SIZE]; assert_eq!(storage.try_get(), None); assert_eq!(storage.try_set(&value), Err(ink_env::Error::BufferTooSmall));