From 0e2f8bbb72d86dd3f7b27e54a1cc429cbd1319ad Mon Sep 17 00:00:00 2001 From: Petar Ivanov <29689712+dartdart26@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:05:42 +0300 Subject: [PATCH] Add ability to configure static buffer capacity Currently, `StaticBuffer` in env/src/engine/on_chain/buffer.sh has a static (constant) size of 16 kB. However, there are cases which might require more space. One such case is passing in and getting out bigger buffers to/from a chain extension. As chain extensions can be arbitrary, it makes sense to have the ability to change the size of the buffer. This commit adds the ability to configure the static buffer capacity at compile time through the `ENV_ENGINE_STATIC_BUFFER_CAPACITY` environment variable. For example, to double it to 32 kB, one might do the following when compiling a smart contract: ``` ENV_ENGINE_STATIC_BUFFER_CAPACITY=32768 cargo +nightly contract build ``` In order to implement, we introduce the `ink_build_script_utils` crate that has functions to read the value from the environment variable and convert it to a Rust constant in a generated file at build-time. Then, we utilize a build.rs script at the `env` crate level. Documentation about the `ENV_ENGINE_STATIC_BUFFER_CAPACITY` environment variable can be added in a separate commit to the `ink-docs` repo. --- Cargo.toml | 1 + crates/build-script-utils/Cargo.toml | 14 ++++ crates/build-script-utils/README.md | 3 + crates/build-script-utils/src/lib.rs | 88 ++++++++++++++++++++++++ crates/env/Cargo.toml | 3 + crates/env/build.rs | 34 +++++++++ crates/env/src/engine/on_chain/buffer.rs | 14 +++- crates/env/src/engine/on_chain/mod.rs | 7 +- 8 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 crates/build-script-utils/Cargo.toml create mode 100644 crates/build-script-utils/README.md create mode 100644 crates/build-script-utils/src/lib.rs create mode 100644 crates/env/build.rs diff --git a/Cargo.toml b/Cargo.toml index 154fbd1a1ae..02a2e104918 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "crates/env", "crates/storage", "crates/storage/derive", + "crates/build-script-utils", ] exclude = [ "examples/", diff --git a/crates/build-script-utils/Cargo.toml b/crates/build-script-utils/Cargo.toml new file mode 100644 index 00000000000..f02652aa752 --- /dev/null +++ b/crates/build-script-utils/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ink_build_script_utils" +version = "3.2.0" +authors = ["Petar Ivanov "] +edition = "2021" + +license = "Apache-2.0" +readme = "README.md" +repository = "https://github.com/paritytech/ink" +documentation = "https://docs.rs/ink_build_script_utils/" +homepage = "https://www.parity.io/" +description = "[ink!] Utilities for `build.rs` scripts." +keywords = ["wasm", "parity", "webassembly", "blockchain", "edsl"] +include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] diff --git a/crates/build-script-utils/README.md b/crates/build-script-utils/README.md new file mode 100644 index 00000000000..1c184f67326 --- /dev/null +++ b/crates/build-script-utils/README.md @@ -0,0 +1,3 @@ +Crate with utility functions for `build.rs` scripts. + +License: Apache-2.0 \ No newline at end of file diff --git a/crates/build-script-utils/src/lib.rs b/crates/build-script-utils/src/lib.rs new file mode 100644 index 00000000000..fb00e2a6f9d --- /dev/null +++ b/crates/build-script-utils/src/lib.rs @@ -0,0 +1,88 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{ + env, + fs, + path::Path, +}; + +// Environment variables. +const ENV_ENGINE_STATIC_BUFFER_CAPACITY: &str = "ENV_ENGINE_STATIC_BUFFER_CAPACITY"; + +/// Configure the `StaticBuffer` capacity used in the `env` crate at build time +/// through the `ENV_ENGINE_STATIC_BUFFER_CAPACITY` environment variable. +/// If not explicitly configured, a default value of 16384 is used. +/// +/// `StaticBuffer`: engine/on_chain/buffer.rs +pub fn env_engine_static_buffer_capacity() -> String { + // Make sure that `build.rs` is called if the capacity configuration (env var) changes. + println!( + "cargo:rerun-if-env-changed={}", + ENV_ENGINE_STATIC_BUFFER_CAPACITY + ); + + let capacity = + env::var(ENV_ENGINE_STATIC_BUFFER_CAPACITY).unwrap_or_else(|_| "16384".into()); + let capacity: usize = capacity.parse().unwrap_or_else(|_| { + panic!( + "`{}` must be of type `usize`", + ENV_ENGINE_STATIC_BUFFER_CAPACITY + ) + }); + + format!("const CONFIGURED_CAPACITY: usize = {};", capacity) +} + +/// Write to the given `file` only if the `content` is different. +/// +/// Taken from: +/// https://github.dev/paritytech/substrate/blob/4b48e8ec7dffcb599248040f4da5be3de3c09318/utils/wasm-builder/src/lib.rs#L151 +pub fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { + if fs::read_to_string(file.as_ref()).ok().as_deref() != Some(content.as_ref()) { + fs::write(file.as_ref(), content.as_ref()).unwrap_or_else(|_| { + panic!("Writing `{}` can not fail!", file.as_ref().display()) + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn env_engine_static_buffer_capacity_no_env() { + env::remove_var(ENV_ENGINE_STATIC_BUFFER_CAPACITY); + assert_eq!( + env_engine_static_buffer_capacity(), + "const CONFIGURED_CAPACITY: usize = 16384;" + ) + } + + #[test] + fn env_engine_static_buffer_capacity_valid_env() { + env::set_var(ENV_ENGINE_STATIC_BUFFER_CAPACITY, "32768"); + assert_eq!( + env_engine_static_buffer_capacity(), + "const CONFIGURED_CAPACITY: usize = 32768;" + ) + } + + #[test] + #[should_panic] + fn env_engine_static_buffer_capacity_invalid_env() { + env::set_var(ENV_ENGINE_STATIC_BUFFER_CAPACITY, "abc"); + env_engine_static_buffer_capacity(); + } +} diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index 82ab3cc2eaf..30b3436bcf4 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -14,6 +14,9 @@ keywords = ["wasm", "parity", "webassembly", "blockchain", "edsl"] categories = ["no-std", "embedded"] include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] +[build-dependencies] +ink_build_script_utils = { version = "3.2.0", path = "../build-script-utils/", default-features = false } + [dependencies] ink_metadata = { version = "3.2.0", path = "../metadata/", default-features = false, features = ["derive"], optional = true } ink_allocator = { version = "3.2.0", path = "../allocator/", default-features = false } diff --git a/crates/env/build.rs b/crates/env/build.rs new file mode 100644 index 00000000000..3735bdd2f63 --- /dev/null +++ b/crates/env/build.rs @@ -0,0 +1,34 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{ + env, + path::PathBuf, +}; + +use ink_build_script_utils::*; + +/// Write the engine static buffer capacity constant to a file that is then +/// included in the env/src/engine/on_chain/buffer.rs file. +fn write_env_engine_static_buffer_capacity() { + let capacity = env_engine_static_buffer_capacity(); + let out_dir = + PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` must be set by cargo!")); + let out_file = out_dir.join("env_engine_static_buffer_capacity.rs"); + write_file_if_changed(out_file, capacity); +} + +fn main() { + write_env_engine_static_buffer_capacity(); +} diff --git a/crates/env/src/engine/on_chain/buffer.rs b/crates/env/src/engine/on_chain/buffer.rs index 469238f2524..6df0751d5ce 100644 --- a/crates/env/src/engine/on_chain/buffer.rs +++ b/crates/env/src/engine/on_chain/buffer.rs @@ -12,15 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// A static buffer with 16 kB of capacity. +// Inlcude the generated configuration file that contains the `CONFIGURED_CAPACITY` +// constant. +include!(concat!( + env!("OUT_DIR"), + "/env_engine_static_buffer_capacity.rs" +)); + +/// A static buffer with a configurable capacity at build-time. +/// If not explicitly configured, a default value of 16384 (16 kB) is used. pub struct StaticBuffer { - /// The static buffer with a total capacity of 16 kB. + /// The static buffer. buffer: [u8; Self::CAPACITY], } impl StaticBuffer { /// The capacity of the static buffer. - const CAPACITY: usize = 1 << 14; // 16 kB + const CAPACITY: usize = CONFIGURED_CAPACITY; /// Creates a new static buffer. pub const fn new() -> Self { diff --git a/crates/env/src/engine/on_chain/mod.rs b/crates/env/src/engine/on_chain/mod.rs index 2bee4c0785b..16d6b9ebd49 100644 --- a/crates/env/src/engine/on_chain/mod.rs +++ b/crates/env/src/engine/on_chain/mod.rs @@ -27,7 +27,7 @@ use super::OnInstance; /// The on-chain environment. pub struct EnvInstance { - /// Encode & decode buffer with static size of 16 kB. + /// Encode & decode buffer with a default static capacity of 16 kB. /// /// If operations require more than that they will fail. /// This limit was found to be a sweet spot after running benchmarks @@ -36,6 +36,11 @@ pub struct EnvInstance { /// Please note that this is still an implementation detail and /// might change. Users should generally avoid storing too big values /// into single storage entries. + /// + /// Note: The static capacity of the buffer can be configured at + /// build-time via the `ENV_ENGINE_STATIC_BUFFER_CAPACITY` environment + /// variable. + /// See crates/env/build.rs for more information. buffer: StaticBuffer, }