Repository: paritytech/ink
Pull request #359 (2020-03-20 18:26:04)

making CI faster by ~1 min; 
- `needs:` makes the job not to wait for the previous stage to be over, just a mentioned job
- `cargo test` does not need to run `--release`, it's faster without it, and also it doesn't run `release` profile, it runs `bench`


Patch:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8317e9d175..e0ccb9e7ed 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,7 +14,6 @@ stages:
 variables:
   GIT_STRATEGY:                    fetch
   GIT_DEPTH:                       100
-  CARGO_HOME:                      "/ci-cache/${CI_PROJECT_NAME}/cargo/${CI_JOB_NAME}"
   CARGO_TARGET_DIR:                "/ci-cache/${CI_PROJECT_NAME}/targets/${CI_COMMIT_REF_NAME}/${CI_JOB_NAME}"
   CI_SERVER_NAME:                  "GitLab CI"
   REGISTRY:                        registry.parity.io/parity/infrastructure/scripts
@@ -35,18 +34,7 @@ variables:
     - rustc -vV
     - rustup show
     - bash --version
-    - mkdir -p ${CARGO_HOME}; touch ${CARGO_HOME}/config
-    # global RUSTFLAGS overrides the linker args so this way is better to pass the flags
-    - printf '[build]\nrustflags = ["-C", "link-dead-code"]\n' | tee ${CARGO_HOME}/config
-    # if there is no directory for this $CI_COMMIT_REF_NAME/$CI_JOB_NAME
-    # create such directory and
-    # create hardlinks recursively of all the files from the master/$CI_JOB_NAME if it exists
-    - if [[ ! -d $CARGO_TARGET_DIR ]]; then
-        mkdir -p /ci-cache/${CI_PROJECT_NAME}/targets/${CI_COMMIT_REF_NAME};
-        cp -al /ci-cache/${CI_PROJECT_NAME}/targets/${CI_DEFAULT_BRANCH}/${CI_JOB_NAME}
-          /ci-cache/${CI_PROJECT_NAME}/targets/${CI_COMMIT_REF_NAME} ||
-          echo "_____No such target dir, proceeding from scratch_____";
-      fi
+    - ./scripts/pre_cache.sh
     - sccache -s
   only:
     - master
@@ -113,9 +101,34 @@ test:
   needs:
     - check-std
   script:
-    - for crate in ${ALL_CRATES}; do
-        cargo test --verbose --all-features --release --manifest-path ${crate}/Cargo.toml;
-      done
+    - cargo test --verbose --all-features --no-fail-fast --release --workspace
+
+codecov:
+  stage:                           workspace
+  <<:                              *docker-env
+  needs:
+    - check-std
+  variables:
+    # According to https://github.com/mozilla/grcov/blob/master/README.md
+    # we have to use these variables.
+    CARGO_INCREMENTAL:             0
+    # If `-Zno-landing-pads` is enabled some some tests start to fail.
+    RUSTFLAGS:                     "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off"
+    # The `cargo-taurpalin` coverage reporting tool seems to have better code instrumentation
+    # and thus produces better results for Rust codebases in general. However, unlike `grcov` it
+    # requires running docker with `--security-opt seccomp=unconfined` which is why we use `grcov`
+    # instead.
+  script:
+    # RUSTFLAGS are the cause target cache can't be used here
+    - unset "CARGO_TARGET_DIR"
+    - cargo clean
+    - cargo test --verbose --all-features --no-fail-fast --workspace
+    - cargo build --verbose --all-features --workspace
+    - grcov ./target -s . -t coveralls+ --guess-directory-when-missing --llvm --branch --ignore-not-existing --ignore "/*"
+        --token "$CODECOV_TOKEN" --commit-sha "$CI_COMMIT_SHA" --output-file ccov.json
+    # We'd like to not use a remote bash script for uploading the coverage reports,
+    # however this job seems to be more tricky than we hoped.
+    - bash <(curl -s https://codecov.io/bash) -t "$CODECOV_TOKEN" -X gcov -f ccov.json
 
 clippy-std:
   stage:                           workspace
@@ -148,12 +161,14 @@ fmt:
 
 .update-cargo-contract:            &update-cargo-contract
   # `cargo install` returns an error if there is nothing to update, so have to supress it here temporarily
-  - cargo install --git https://github.com/paritytech/cargo-contract || echo $?
+  - cargo install cargo-contract || echo $?
   - cargo contract -V
 
 examples-test:
   stage:                           examples
   <<:                              *docker-env
+  needs:
+    - clippy-std
   script:
     - for example in examples/*/; do
         cargo test --verbose --manifest-path ${example}/Cargo.toml;
@@ -170,6 +185,8 @@ examples-fmt:
 examples-clippy-std:
   stage:                           examples
   <<:                              *docker-env
+  needs:
+    - clippy-std
   script:
     - for example in examples/*/; do
         cargo clippy --verbose --manifest-path ${example}/Cargo.toml -- -D warnings;
@@ -197,6 +214,8 @@ examples-contract-build:
 examples-generate-metadata:
   stage:                           examples
   <<:                              *docker-env
+  needs:
+    - build-wasm
   script:
     - *update-cargo-contract
     - for example in examples/*/; do
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 2a8c61c9bb..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,63 +0,0 @@
-language: rust
-cache: cargo
-dist: trusty
-sudo: true
-
-branches:
-  only:
-  - master
-
-rust:
-  - nightly-2019-11-17
-
-matrix:
-  allow_failures:
-    - rust: nightly
-
-env:
-  global:
-  - RUSTFLAGS="-C link-dead-code"
-
-addons:
-  apt:
-    packages:
-      - libcurl4-openssl-dev
-      - libelf-dev
-      - libdw-dev
-      - binutils-dev
-      - libiberty-dev
-      - g++
-      - cmake
-      - zlib1g-dev
-
-install:
-  # Print rustc and cargo versions
-  - rustc -vV
-  - cargo -vV
-  - bash --version
-  # Install cargo-kcov Cargo plugin
-  - cargo install --force cargo-kcov
-  - cargo kcov -vV
-  # Install kcov binary
-  - wget https://github.com/SimonKagstrom/kcov/archive/v36.tar.gz
-  - tar xzf v36.tar.gz
-  - pushd kcov-36
-  - mkdir build
-  - pushd build
-  - cmake ..
-  - make
-  - sudo make install # Puts kcov in the default location usually /usr/local/bin/kcov
-  - kcov --version
-  - popd
-  - popd
-  # Export cargo binaries, python and misc settings
-  - export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$HOME/Library/Python/2.7/bin:$PATH
-  # Print current work directory state as directions.
-  - ls -lah
-
-script:
-- |
-  cargo test --all-features --all
-  cargo kcov --verbose --coveralls --all --no-clean-rebuild
-  bash <(curl -s https://codecov.io/bash)
-  exit 0
diff --git a/README.md b/README.md
index c59d25dcc8..9dfb163271 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ Use the scripts provided under `scripts` directory in order to run checks on eit
 For building the example smart contracts found under `examples` you will need to have [`cargo-contract`](https://github.com/paritytech/cargo-contract) installed.
 
 ```
-cargo install --git https://github.com/paritytech/cargo-contract cargo-contract --force
+cargo install cargo-contract --force
 ```
 
 Use the `--force` to ensure you are updated to the most recent `cargo-contract` version.
diff --git a/abi/Cargo.toml b/abi/Cargo.toml
index 19ebc4ea5d..29a63c3266 100644
--- a/abi/Cargo.toml
+++ b/abi/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_abi"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
@@ -15,9 +15,9 @@ categories = ["no-std", "embedded"]
 include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
 
 [dependencies]
-ink_abi_derive = { version = "2.0.0", path = "derive", default-features = false, optional = true }
-ink_prelude = { version = "2.0.0", path = "../prelude/", default-features = false }
-ink_primitives = { version = "2.0.0", path = "../primitives/", default-features = false }
+ink_abi_derive = { version = "2.1.0", path = "derive", default-features = false, optional = true }
+ink_prelude = { version = "2.1.0", path = "../prelude/", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../primitives/", default-features = false }
 
 serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] }
 derive_more = { version = "0.99", default-features = false, features = ["from"] }
diff --git a/abi/derive/Cargo.toml b/abi/derive/Cargo.toml
index bfbb96028a..942b4d2fbf 100644
--- a/abi/derive/Cargo.toml
+++ b/abi/derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_abi_derive"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 license = "APACHE-2.0"
diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml
index c3dbf03676..5b1a952dc1 100644
--- a/alloc/Cargo.toml
+++ b/alloc/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_alloc"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
diff --git a/core/Cargo.toml b/core/Cargo.toml
index ada6b44dae..47d69765fc 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_core"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
@@ -15,17 +15,24 @@ categories = ["no-std", "embedded"]
 include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
 
 [dependencies]
-ink_abi = { version = "2.0.0", path = "../abi/", default-features = false, features = ["derive"], optional = true }
-ink_alloc = { version = "2.0.0", path = "../alloc/", default-features = false }
-ink_primitives = { version = "2.0.0", path = "../primitives/", default-features = false }
-ink_core_derive = { version = "2.0.0", path = "derive", default-features = false }
-ink_prelude = { version = "2.0.0", path = "../prelude/", default-features = false }
+ink_abi = { version = "2.1.0", path = "../abi/", default-features = false, features = ["derive"], optional = true }
+ink_alloc = { version = "2.1.0", path = "../alloc/", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../primitives/", default-features = false }
+ink_core_derive = { version = "2.1.0", path = "derive", default-features = false }
+ink_prelude = { version = "2.1.0", path = "../prelude/", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive", "full"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }
 derive_more = { version = "0.99", default-features = false, features = ["from", "display"] }
 smallvec = { version = "1.2", default-features = false, features = ["union"] }
 cfg-if = "0.1"
 num-traits = { version = "0.2", default-features = false, features = ["i128"] }
+paste = "0.1"
+
+# Hashes for the off-chain environment.
+byteorder = { version = "1.3", optional = true }
+blake2-rfc = { version = "0.2", optional = true }
+sha2 = { version = "0.8", optional = true }
+tiny-keccak = { version = "2.0", optional = true }
 
 # Only used in the off-chain environment.
 #
@@ -55,6 +62,11 @@ std = [
     "rand",
     "rand/std",
     "num-traits/std",
+    # Enables hashing crates for off-chain environment.
+    "byteorder",
+    "blake2-rfc",
+    "sha2",
+    "tiny-keccak",
 ]
 ink-generate-abi = [
     "ink_abi",
diff --git a/core/derive/Cargo.toml b/core/derive/Cargo.toml
index 141d602f23..52f211bc84 100644
--- a/core/derive/Cargo.toml
+++ b/core/derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_core_derive"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
@@ -11,14 +11,14 @@ readme = "../README.md"
 proc-macro = true
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
 quote = "1.0"
 syn = { version = "1.0", features = ["full"] }
 proc-macro2 = "1.0"
 synstructure = "0.12"
 
 [dev-dependencies]
-ink_core = { version = "2.0.0", path = ".." }
+ink_core = { version = "2.1.0", path = ".." }
 trybuild = "1.0.24"
 
 [features]
diff --git a/core/src/env/api.rs b/core/src/env/api.rs
index 5ce8cd0cad..4d04ee2b05 100644
--- a/core/src/env/api.rs
+++ b/core/src/env/api.rs
@@ -506,3 +506,41 @@ where
         Env::get_runtime_storage::<R>(instance, runtime_key)
     })
 }
+
+/// Built-in efficient cryptographic hash functions.
+pub mod hash {
+    use super::*;
+
+    macro_rules! impl_hash_fn {
+        ( $(#[$doc:meta])* fn $name:ident($output_len:literal) ) => {
+            paste::item! {
+                $( #[$doc] )*
+                pub fn $name(input: &[u8], output: &mut [u8; $output_len]) {
+                    // No need to actually access the environmental instance
+                    // if we only call one of its inherent methods.
+                    <EnvInstance as Env>::[<hash_ $name>](input, output)
+                }
+            }
+        };
+    }
+    impl_hash_fn!(
+        /// Conducts the SHA2 256-bit hash of the given bytes and
+        /// puts the result into the output buffer.
+        fn sha2_256(32)
+    );
+    impl_hash_fn!(
+        /// Conducts the KECCAK 256-bit hash of the given bytes and
+        /// puts the result into the output buffer.
+        fn keccak_256(32)
+    );
+    impl_hash_fn!(
+        /// Conducts the BLAKE2 256-bit hash of the given bytes and
+        /// puts the result into the output buffer.
+        fn blake2_256(32)
+    );
+    impl_hash_fn!(
+        /// Conducts the BLAKE2 128-bit hash of the given bytes and
+        /// puts the result into the output buffer.
+        fn blake2_128(16)
+    );
+}
diff --git a/core/src/env/backend.rs b/core/src/env/backend.rs
index f8ba6a3da8..9c8957b948 100644
--- a/core/src/env/backend.rs
+++ b/core/src/env/backend.rs
@@ -77,6 +77,22 @@ pub trait Env {
 
     /// Prints the given contents to the console log.
     fn println(&mut self, content: &str);
+
+    /// Conducts the SHA2 256-bit hash of the input
+    /// puts the result into the output buffer.
+    fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]);
+
+    /// Conducts the KECCAK 256-bit hash of the input
+    /// puts the result into the output buffer.
+    fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]);
+
+    /// Conducts the BLAKE2 256-bit hash of the input
+    /// puts the result into the output buffer.
+    fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]);
+
+    /// Conducts the BLAKE2 128-bit hash of the input
+    /// puts the result into the output buffer.
+    fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]);
 }
 
 /// Environmental contract functionality.
diff --git a/core/src/env/engine/off_chain/db/accounts.rs b/core/src/env/engine/off_chain/db/accounts.rs
index cde4306179..0f35324499 100644
--- a/core/src/env/engine/off_chain/db/accounts.rs
+++ b/core/src/env/engine/off_chain/db/accounts.rs
@@ -78,6 +78,11 @@ impl AccountsDb {
         }
     }
 
+    /// Resets the account DB to uninitialized state.
+    pub fn reset(&mut self) {
+        self.accounts.clear()
+    }
+
     /// Returns the account at the given account ID or creates it.
     pub fn get_or_create_account<T>(&mut self, at: &T::AccountId) -> &mut Account
     where
diff --git a/core/src/env/engine/off_chain/db/chain_spec.rs b/core/src/env/engine/off_chain/db/chain_spec.rs
index 9e98c939d1..aa5315d74c 100644
--- a/core/src/env/engine/off_chain/db/chain_spec.rs
+++ b/core/src/env/engine/off_chain/db/chain_spec.rs
@@ -42,6 +42,14 @@ impl ChainSpec {
         }
     }
 
+    /// Resets the chain spec to uninitialized state.
+    pub fn reset(&mut self) {
+        self.gas_price = OffBalance::uninitialized();
+        self.minimum_balance = OffBalance::uninitialized();
+        self.tombstone_deposit = OffBalance::uninitialized();
+        self.block_time = OffTimestamp::uninitialized();
+    }
+
     /// Default initialization for the off-chain specification.
     pub fn initialize_as_default<T>(&mut self) -> crate::env::Result<()>
     where
diff --git a/core/src/env/engine/off_chain/db/console.rs b/core/src/env/engine/off_chain/db/console.rs
index f19f2c9e14..95c9c813f9 100644
--- a/core/src/env/engine/off_chain/db/console.rs
+++ b/core/src/env/engine/off_chain/db/console.rs
@@ -28,6 +28,11 @@ impl Console {
         }
     }
 
+    /// Resets the console to uninitialized state.
+    pub fn reset(&mut self) {
+        self.past_prints.clear();
+    }
+
     /// Prints the contents to the actual console and stores them.
     pub fn println(&mut self, contents: &str) {
         self.past_prints.push(contents.to_string());
diff --git a/core/src/env/engine/off_chain/db/events.rs b/core/src/env/engine/off_chain/db/events.rs
index 1e652e8091..0774d05ee6 100644
--- a/core/src/env/engine/off_chain/db/events.rs
+++ b/core/src/env/engine/off_chain/db/events.rs
@@ -58,6 +58,11 @@ impl EmittedEventsRecorder {
         }
     }
 
+    /// Resets the emitted events to none.
+    pub fn reset(&mut self) {
+        self.emitted_events.clear();
+    }
+
     /// Records a new emitted event.
     pub fn record<T, E>(&mut self, new_event: E)
     where
diff --git a/core/src/env/engine/off_chain/hashing.rs b/core/src/env/engine/off_chain/hashing.rs
new file mode 100644
index 0000000000..7188175da8
--- /dev/null
+++ b/core/src/env/engine/off_chain/hashing.rs
@@ -0,0 +1,47 @@
+// Copyright 2019-2020 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.
+
+//! Implementations of supported cryptographic hash functions.
+
+/// Conduct the BLAKE2 256-bit hash and place the result into `output`.
+pub fn blake2_256(input: &[u8], output: &mut [u8; 32]) {
+    output.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], input).as_bytes());
+}
+
+/// Conduct the BLAKE2 128-bit hash and place the result into `output`.
+pub fn blake2_128(input: &[u8], output: &mut [u8; 16]) {
+    output.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], input).as_bytes());
+}
+
+/// Conduct the KECCAK 256-bit hash and place the result into `output`.
+pub fn keccak_256(input: &[u8], output: &mut [u8; 32]) {
+    use ::tiny_keccak::{
+        Hasher,
+        Keccak,
+    };
+    let mut keccak = Keccak::v256();
+    keccak.update(input);
+    keccak.finalize(output)
+}
+
+/// Conduct the SHA2 256-bit hash and place the result into `output`.
+pub fn sha2_256(input: &[u8], output: &mut [u8; 32]) {
+    use ::sha2::{
+        Digest,
+        Sha256,
+    };
+    let mut hasher = Sha256::new();
+    hasher.input(input);
+    output.copy_from_slice(&hasher.result());
+}
diff --git a/core/src/env/engine/off_chain/impls.rs b/core/src/env/engine/off_chain/impls.rs
index 58da8668e3..e5d27675e4 100644
--- a/core/src/env/engine/off_chain/impls.rs
+++ b/core/src/env/engine/off_chain/impls.rs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 use super::{
+    hashing,
     Account,
     EnvInstance,
 };
@@ -111,6 +112,22 @@ impl Env for EnvInstance {
     fn println(&mut self, content: &str) {
         self.console.println(content)
     }
+
+    fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) {
+        hashing::keccak_256(input, output)
+    }
+
+    fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
+        hashing::blake2_256(input, output)
+    }
+
+    fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
+        hashing::blake2_128(input, output)
+    }
+
+    fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) {
+        hashing::sha2_256(input, output)
+    }
 }
 
 impl TypedEnv for EnvInstance {
diff --git a/core/src/env/engine/off_chain/mod.rs b/core/src/env/engine/off_chain/mod.rs
index 29945e7807..ce6f40625d 100644
--- a/core/src/env/engine/off_chain/mod.rs
+++ b/core/src/env/engine/off_chain/mod.rs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 mod db;
+mod hashing;
 mod impls;
 mod runtime_calls;
 mod runtime_storage;
@@ -109,6 +110,36 @@ impl EnvInstance {
         }
     }
 
+    /// Returns `true` if the off-chain environment is uninitialized.
+    pub fn is_initialized(&self) -> bool {
+        !self.exec_context.is_empty()
+    }
+
+    /// Either resets or initializes the off-chain environment to default values.
+    pub fn initialize_or_reset_as_default<T>(&mut self) -> crate::env::Result<()>
+    where
+        T: EnvTypes,
+        <T as EnvTypes>::AccountId: From<[u8; 32]>,
+    {
+        if self.is_initialized() {
+            self.reset()
+        }
+        self.initialize_as_default::<T>()?;
+        Ok(())
+    }
+
+    /// Resets the off-chain environment to unintialized state.
+    pub fn reset(&mut self) {
+        self.accounts.reset();
+        self.exec_context.clear();
+        self.chain_spec.reset();
+        self.blocks.clear();
+        self.console.reset();
+        self.runtime_storage.reset();
+        self.runtime_call_handler.reset();
+        self.emitted_events.reset();
+    }
+
     /// Initializes the whole off-chain environment.
     ///
     /// # Note
diff --git a/core/src/env/engine/off_chain/runtime_calls.rs b/core/src/env/engine/off_chain/runtime_calls.rs
index ec49f2c1e0..8296f4af41 100644
--- a/core/src/env/engine/off_chain/runtime_calls.rs
+++ b/core/src/env/engine/off_chain/runtime_calls.rs
@@ -37,6 +37,11 @@ impl RuntimeCallHandler {
         Self { registered: None }
     }
 
+    /// Resets the runtime call handler to uninitialized state.
+    pub fn reset(&mut self) {
+        self.registered = None;
+    }
+
     /// Register a runtime call handler.
     pub fn register<T, F>(&mut self, mut f: F)
     where
diff --git a/core/src/env/engine/off_chain/runtime_storage.rs b/core/src/env/engine/off_chain/runtime_storage.rs
index efa9d9ddae..5b4b3c17d5 100644
--- a/core/src/env/engine/off_chain/runtime_storage.rs
+++ b/core/src/env/engine/off_chain/runtime_storage.rs
@@ -34,6 +34,11 @@ impl RuntimeStorage {
         }
     }
 
+    /// Resets the runtime storage to uninitialized state.
+    pub fn reset(&mut self) {
+        self.entries.clear();
+    }
+
     /// Stores the value under the given key.
     pub fn store<T>(&mut self, key: Vec<u8>, value: T)
     where
diff --git a/core/src/env/engine/on_chain/ext.rs b/core/src/env/engine/on_chain/ext.rs
index c168e10a69..72f308bc86 100644
--- a/core/src/env/engine/on_chain/ext.rs
+++ b/core/src/env/engine/on_chain/ext.rs
@@ -101,6 +101,11 @@ mod sys {
 
         pub fn ext_random_seed(subject_ptr: u32, subject_len: u32);
         pub fn ext_println(str_ptr: u32, str_len: u32);
+
+        pub fn ext_hash_keccak_256(input_ptr: u32, input_len: u32, output_ptr: u32);
+        pub fn ext_hash_blake2_256(input_ptr: u32, input_len: u32, output_ptr: u32);
+        pub fn ext_hash_blake2_128(input_ptr: u32, input_len: u32, output_ptr: u32);
+        pub fn ext_hash_sha2_256(input_ptr: u32, input_len: u32, output_ptr: u32);
     }
 }
 
@@ -301,3 +306,23 @@ pub fn println(content: &str) {
     let bytes = content.as_bytes();
     unsafe { sys::ext_println(bytes.as_ptr() as u32, bytes.len() as u32) }
 }
+
+macro_rules! impl_hash_fn {
+    ( $name:ident, $bytes_result:literal ) => {
+        paste::item! {
+            pub fn [<hash_ $name>](input: &[u8], output: &mut [u8; $bytes_result]) {
+                unsafe {
+                    sys::[<ext_hash_ $name>](
+                        input.as_ptr() as u32,
+                        input.len() as u32,
+                        output.as_ptr() as u32,
+                    )
+                }
+            }
+        }
+    };
+}
+impl_hash_fn!(sha2_256, 32);
+impl_hash_fn!(keccak_256, 32);
+impl_hash_fn!(blake2_256, 32);
+impl_hash_fn!(blake2_128, 16);
diff --git a/core/src/env/engine/on_chain/impls.rs b/core/src/env/engine/on_chain/impls.rs
index 748ca7c75f..b66fdcff8d 100644
--- a/core/src/env/engine/on_chain/impls.rs
+++ b/core/src/env/engine/on_chain/impls.rs
@@ -178,6 +178,22 @@ impl Env for EnvInstance {
     fn println(&mut self, content: &str) {
         ext::println(content)
     }
+
+    fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) {
+        ext::hash_keccak_256(input, output)
+    }
+
+    fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
+        ext::hash_blake2_256(input, output)
+    }
+
+    fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
+        ext::hash_blake2_128(input, output)
+    }
+
+    fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) {
+        ext::hash_sha2_256(input, output)
+    }
 }
 
 impl TypedEnv for EnvInstance {
diff --git a/core/src/env/mod.rs b/core/src/env/mod.rs
index 38ee67dbf6..98000466d9 100644
--- a/core/src/env/mod.rs
+++ b/core/src/env/mod.rs
@@ -24,6 +24,9 @@ mod engine;
 mod error;
 mod types;
 
+#[cfg(test)]
+mod tests;
+
 #[cfg(any(feature = "std", test, doc))]
 #[doc(inline)]
 pub use self::engine::off_chain::test_api as test;
diff --git a/core/src/hash/accumulator.rs b/core/src/hash/accumulator.rs
new file mode 100644
index 0000000000..2f7b42d113
--- /dev/null
+++ b/core/src/hash/accumulator.rs
@@ -0,0 +1,141 @@
+// Copyright 2018-2020 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.
+
+#[cfg(feature = "std")]
+use ::std::io::{
+    Result as IoResult,
+    Write,
+};
+use ink_prelude::vec::Vec;
+
+/// Hash builder that accumulates a buffer on the contract side.
+pub trait Accumulator {
+    /// Resets the buffer which cleans all state from it.
+    ///
+    /// # Note
+    ///
+    /// Useful when using `Vec` or similar as accumulator.
+    fn reset(&mut self);
+    /// Writes the given bytes into the buffer.
+    fn write(&mut self, bytes: &[u8]);
+    /// Returns a shared reference to the slice of the current state of the buffer.
+    fn as_slice(&self) -> &[u8];
+}
+
+impl Accumulator for Vec<u8> {
+    fn reset(&mut self) {
+        self.clear()
+    }
+
+    fn write(&mut self, bytes: &[u8]) {
+        // This could theoretically be speed-up by using `unsafe` `set_len`
+        // and `[u8]` `copy_from_slice` methods.
+        self.extend_from_slice(bytes)
+    }
+
+    fn as_slice(&self) -> &[u8] {
+        self.as_slice()
+    }
+}
+
+impl<'a, T> Accumulator for &'a mut T
+where
+    T: Accumulator,
+{
+    fn reset(&mut self) {
+        <T as Accumulator>::reset(self)
+    }
+
+    fn write(&mut self, bytes: &[u8]) {
+        <T as Accumulator>::write(self, bytes)
+    }
+
+    fn as_slice(&self) -> &[u8] {
+        <T as Accumulator>::as_slice(self)
+    }
+}
+
+/// Wraps a bytes buffer and turns it into an accumulator.
+///
+/// # Panics
+///
+/// Upon hash calculation if the underlying buffer length does not suffice the
+/// needs of the accumulated hash buffer.
+pub struct Wrap<'a> {
+    /// The underlying wrapped buffer.
+    buffer: &'a mut [u8],
+    /// The current length of the filled area.
+    len: usize,
+}
+
+impl Wrap<'_> {
+    /// Returns the capacity of the underlying buffer.
+    fn capacity(&self) -> usize {
+        self.buffer.len()
+    }
+
+    /// Returns the length of the underlying buffer.
+    fn len(&self) -> usize {
+        self.len
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Write for Wrap<'a> {
+    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
+        <Self as Accumulator>::write(self, buf);
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> IoResult<()> {
+        Ok(())
+    }
+}
+
+impl<'a> From<&'a mut [u8]> for Wrap<'a> {
+    fn from(buffer: &'a mut [u8]) -> Self {
+        Self { buffer, len: 0 }
+    }
+}
+
+impl<'a> Accumulator for Wrap<'a> {
+    fn reset(&mut self) {
+        self.len = 0;
+    }
+
+    fn write(&mut self, bytes: &[u8]) {
+        debug_assert!(self.len() + bytes.len() <= self.capacity());
+        let len = self.len;
+        let bytes_len = bytes.len();
+        self.buffer[len..(len + bytes_len)].copy_from_slice(bytes);
+        self.len += bytes_len;
+    }
+
+    fn as_slice(&self) -> &[u8] {
+        &self.buffer[..self.len]
+    }
+}
+
+#[cfg(not(feature = "std"))]
+impl<'a> scale::Output for Wrap<'a> {
+    fn write(&mut self, bytes: &[u8]) {
+        <Self as Accumulator>::write(self, bytes)
+    }
+
+    fn push_byte(&mut self, byte: u8) {
+        debug_assert!(self.len() < self.capacity());
+        self.buffer[self.len] = byte;
+        self.len += 1;
+    }
+}
diff --git a/core/src/hash/builder.rs b/core/src/hash/builder.rs
new file mode 100644
index 0000000000..1e902dfc70
--- /dev/null
+++ b/core/src/hash/builder.rs
@@ -0,0 +1,304 @@
+// Copyright 2018-2020 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 super::{
+    hasher::Hasher,
+    Accumulator,
+};
+use core::marker::PhantomData;
+
+/// Type indicating that no accumulator is in use.
+///
+/// # Note
+///
+/// This means that a hash builder with this type as accumulator cannot
+/// build hashes for instances based on their SCALE encoding.
+#[derive(Debug)]
+pub enum NoAccumulator {}
+
+/// Generic hash builder to construct hashes given a builder strategy.
+///
+/// - `H` defines the crytographic hash to be conducted.
+/// - `S` defines the strategy.
+///   Currently only accumulating strategy is supported but in the future there
+///   might be support for incremental hash builders.
+///
+/// # Note
+///
+/// This is just a base type and should not be used directly.
+/// Use one of the following concrete hash builders instead:
+///
+/// - [`Sha2x256`](`crate::hash::Sha2x256`)
+/// - [`Keccak256`](`crate::hash::Keccak256`)
+/// - [`Blake2x256`](`crate::hash::Blake2x256`)
+/// - [`Blake2x128`](`crate::hash::Blake2x128`)
+#[derive(Debug)]
+pub struct HashBuilder<H, S = NoAccumulator> {
+    /// The strategy used to build up the hash.
+    strategy: S,
+    /// The underlying cryptographic hasher.
+    hasher: PhantomData<fn() -> H>,
+}
+
+impl<H, S> scale::Output for HashBuilder<H, S>
+where
+    S: Accumulator,
+{
+    fn write(&mut self, bytes: &[u8]) {
+        <S as Accumulator>::write(&mut self.strategy, bytes)
+    }
+}
+
+impl<H, S> From<S> for HashBuilder<H, S>
+where
+    S: Accumulator,
+{
+    fn from(accumulator: S) -> Self {
+        Self {
+            hasher: Default::default(),
+            strategy: accumulator,
+        }
+    }
+}
+
+impl<H, S> HashBuilder<H, S>
+where
+    H: Hasher,
+{
+    /// Conducts the hash for the given bytes.
+    ///
+    /// Puts the resulting hash into the provided output buffer.
+    ///
+    /// # Note
+    ///
+    /// Prefer the simpler [`hash_bytes`](`HashBuilder::hash_bytes`)
+    /// if you do _not_ need full control over the `output` buffer.
+    pub fn hash_bytes_using(input: &[u8], output: &mut <H as Hasher>::Output)
+    where
+        H: Hasher,
+    {
+        <H as Hasher>::finalize_immediate(input, output)
+    }
+
+    /// Returns the hash for the given bytes.
+    ///
+    /// # Note
+    ///
+    /// Use [`hash_bytes_using`](`HashBuilder::hash_bytes_using`)
+    /// if you need full control over the `output` buffer.
+    pub fn hash_bytes(input: &[u8]) -> <H as Hasher>::Output
+    where
+        H: Hasher,
+    {
+        let mut output = <<H as Hasher>::Output as Default>::default();
+        Self::hash_bytes_using(input, &mut output);
+        output
+    }
+}
+
+pub trait Finalize<H>
+where
+    H: Hasher,
+{
+    fn finalize_using(&self, output: &mut <H as Hasher>::Output);
+    fn finalize(&self) -> <H as Hasher>::Output;
+}
+
+impl<H, S> Finalize<H> for HashBuilder<H, S>
+where
+    H: Hasher,
+    S: Accumulator,
+{
+    fn finalize_using(&self, output: &mut <H as Hasher>::Output) {
+        <H as Hasher>::finalize_immediate(self.strategy.as_slice(), output)
+    }
+
+    fn finalize(&self) -> <H as Hasher>::Output {
+        let mut output = <<H as Hasher>::Output as Default>::default();
+        Self::finalize_using(self, &mut output);
+        output
+    }
+}
+
+impl<H, S> HashBuilder<H, S>
+where
+    H: Hasher,
+    S: Accumulator,
+{
+    /// Conducts the hash for the encoded input.
+    ///
+    /// Puts the resulting hash into the provided output buffer.
+    ///
+    /// # Note
+    ///
+    /// Prefer the simpler [`hash_encoded`](`HashBuilder::hash_encoded`)
+    /// if you do _not_ need full control over the `output` buffer.
+    ///
+    /// # Examples
+    ///
+    /// In the following examples the `EXPECTED` buffer is defined as:
+    ///
+    /// ```
+    /// const EXPECTED: [u8; 32] = [
+    ///     243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    ///     186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// ];
+    /// ```
+    ///
+    /// ## 1. Using a new `Vec` as accumulating buffer.
+    ///
+    /// This is the simplest way to call this API but does not avoid heap
+    /// allocations.
+    ///
+    /// ```
+    /// # use ink_core::hash::Sha2x256;
+    /// # use ink_prelude::vec::Vec;
+    /// # const EXPECTED: [u8; 32] = [
+    /// #   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    /// #   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// # ];
+    /// let hashable = (42, "foo", true); // Implements `core::hash::Hash`
+    /// let mut output = [0x00_u8; 32]; // 256-bit buffer
+    /// let mut hasher = Sha2x256::from(Vec::new());
+    /// hasher.hash_encoded_using(&hashable, &mut output);
+    /// assert_eq!(output, EXPECTED);
+    /// ```
+    ///
+    /// ## 2. Using an existing `Vec` as accumulating buffer.
+    ///
+    /// This API is preferred if the call site already has an allocated buffer
+    /// that it can reuse. This will reset the existing buffer and might grow it.
+    ///
+    /// ```
+    /// # use ink_core::hash::Sha2x256;
+    /// # use ink_prelude::vec::Vec;
+    /// # const EXPECTED: [u8; 32] = [
+    /// #   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    /// #   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// # ];
+    /// let hashable = (42, "foo", true); // Implements `core::hash::Hash`
+    /// let mut output = [0x00_u8; 32]; // 256-bit buffer
+    /// let mut accumulator = Vec::with_capacity(32);
+    /// let mut hasher = Sha2x256::from(&mut accumulator);
+    /// hasher.hash_encoded_using(&hashable, &mut output);
+    /// assert_eq!(output, EXPECTED);
+    /// ```
+    ///
+    /// ## 3. Using a wrapped static buffer as accumulating buffer.
+    ///
+    /// This API avoids heap allocation completely but might panic in cases
+    /// where the static buffer is too small.
+    ///
+    /// ```
+    /// # use ink_core::hash::{Sha2x256, Wrap};
+    /// # use ink_prelude::vec::Vec;
+    /// # const EXPECTED: [u8; 32] = [
+    /// #   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    /// #   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// # ];
+    /// let hashable = (42, "foo", true); // Implements `core::hash::Hash`
+    /// let mut output = [0x00_u8; 32]; // 256-bit buffer
+    /// let mut accumulator = [0x00_u8; 64];
+    /// let mut hasher = Sha2x256::from(Wrap::from(accumulator.as_mut()));
+    /// hasher.hash_encoded_using(&hashable, &mut output);
+    /// assert_eq!(output, EXPECTED);
+    /// ```
+    pub fn hash_encoded_using<T>(&mut self, input: &T, output: &mut <H as Hasher>::Output)
+    where
+        H: Hasher,
+        T: scale::Encode,
+    {
+        <T as scale::Encode>::encode_to(&input, self);
+        self.finalize_using(output)
+    }
+
+    /// Returns the hash for the encoded input.
+    ///
+    /// # Note
+    ///
+    /// Use [`hash_encoded_using`](`HashBuilder::hash_encoded_using`)
+    /// if you need full control over the `output` buffer.
+    ///
+    /// # Examples
+    ///
+    /// In the following examples the `EXPECTED` buffer is defined as:
+    ///
+    /// ```
+    /// const EXPECTED: [u8; 32] = [
+    ///     243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    ///     186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// ];
+    /// ```
+    ///
+    /// ## 1. Using a new `Vec` as accumulating buffer.
+    ///
+    /// This is the simplest way to call this API but does not avoid heap
+    /// allocations.
+    ///
+    /// ```
+    /// # use ink_core::hash::Sha2x256;
+    /// # use ink_prelude::vec::Vec;
+    /// # const EXPECTED: [u8; 32] = [
+    /// #   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    /// #   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// # ];
+    /// let hashable = (42, "foo", true); // Implements `core::hash::Hash`
+    /// let mut hasher = Sha2x256::from(Vec::new());
+    /// assert_eq!(hasher.hash_encoded(&hashable), EXPECTED);
+    /// ```
+    ///
+    /// ## 2. Using an existing `Vec` as accumulating buffer.
+    ///
+    /// This API is preferred if the call site already has an allocated buffer
+    /// that it can reuse. This will reset the existing buffer and might grow it.
+    ///
+    /// ```
+    /// # use ink_core::hash::Sha2x256;
+    /// # use ink_prelude::vec::Vec;
+    /// # const EXPECTED: [u8; 32] = [
+    /// #   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    /// #   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// # ];
+    /// let hashable = (42, "foo", true); // Implements `core::hash::Hash`
+    /// let mut accumulator = Vec::with_capacity(32);
+    /// let mut hasher = Sha2x256::from(&mut accumulator);
+    /// assert_eq!(hasher.hash_encoded(&hashable), EXPECTED);
+    /// ```
+    ///
+    /// ## 3. Using a wrapped static buffer as accumulating buffer.
+    ///
+    /// This API avoids heap allocation completely but might panic in cases
+    /// where the static buffer is too small.
+    ///
+    /// ```
+    /// # use ink_core::hash::{Sha2x256, Wrap};
+    /// # use ink_prelude::vec::Vec;
+    /// # const EXPECTED: [u8; 32] = [
+    /// #   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
+    /// #   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
+    /// # ];
+    /// let hashable = (42, "foo", true); // Implements `core::hash::Hash`
+    /// let mut accumulator = [0x00_u8; 64];
+    /// let mut hasher = Sha2x256::from(Wrap::from(accumulator.as_mut()));
+    /// assert_eq!(hasher.hash_encoded(&hashable), EXPECTED);
+    /// ```
+    pub fn hash_encoded<T>(&mut self, input: &T) -> <H as Hasher>::Output
+    where
+        H: Hasher,
+        T: scale::Encode,
+    {
+        <T as scale::Encode>::encode_to(&input, self);
+        self.finalize()
+    }
+}
diff --git a/core/src/hash/hasher.rs b/core/src/hash/hasher.rs
new file mode 100644
index 0000000000..27d9b1f51b
--- /dev/null
+++ b/core/src/hash/hasher.rs
@@ -0,0 +1,67 @@
+// Copyright 2018-2020 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.
+
+//! Supported cryptographic hashing algorithms.
+
+/// Types that implement this trait are marker types that identify a supported
+/// cryptographic hash function.
+pub trait Hasher {
+    /// The output of the hash function.
+    ///
+    /// # Note
+    ///
+    /// This is a byte slice with varying lengths, e.g. `[u8; 32]`, [`u8; 16]`, etc.
+    type Output: Default;
+
+    /// Finalizes the hash using the underlying procedure.
+    fn finalize_immediate(input: &[u8], output: &mut Self::Output);
+}
+
+macro_rules! impl_hasher_for {
+    (
+        $( #[$doc:meta] )*
+        struct $ty_name:ident($fn_name:ident, $output_len:literal);
+    ) => {
+        $( #[$doc] )*
+        pub enum $ty_name {}
+
+        impl Hasher for $ty_name {
+            type Output = [u8; $output_len];
+
+            fn finalize_immediate(input: &[u8], output: &mut Self::Output) {
+                crate::env::hash::$fn_name(input, output)
+            }
+        }
+    };
+}
+impl_hasher_for! {
+    /// SHA2 256-bit hasher.
+    #[derive(Debug)]
+    struct Sha2x256Hasher(sha2_256, 32);
+}
+impl_hasher_for! {
+    /// KECCAK 256-bit hasher.
+    #[derive(Debug)]
+    struct Keccak256Hasher(keccak_256, 32);
+}
+impl_hasher_for! {
+    /// BLAKE2 256-bit hasher.
+    #[derive(Debug)]
+    struct Blake2x256Hasher(blake2_256, 32);
+}
+impl_hasher_for! {
+    /// BLAKE2 128-bit hasher.
+    #[derive(Debug)]
+    struct Blake2x128Hasher(blake2_128, 16);
+}
diff --git a/core/src/hash/mod.rs b/core/src/hash/mod.rs
new file mode 100644
index 0000000000..3edc915bb8
--- /dev/null
+++ b/core/src/hash/mod.rs
@@ -0,0 +1,39 @@
+// Copyright 2018-2020 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.
+
+//! High-level, built-in and efficient cryptographic hashing routines.
+
+mod accumulator;
+mod builder;
+pub mod hasher;
+
+pub use self::{
+    accumulator::{
+        Accumulator,
+        Wrap,
+    },
+    builder::{
+        HashBuilder,
+        NoAccumulator,
+    },
+};
+
+/// SHA2 256-bit hash builder.
+pub type Sha2x256<S = NoAccumulator> = HashBuilder<hasher::Sha2x256Hasher, S>;
+/// KECCAK 256-bit hash builder.
+pub type Keccak256<S = NoAccumulator> = HashBuilder<hasher::Keccak256Hasher, S>;
+/// BLAKE2 256-bit hash builder.
+pub type Blake2x256<S = NoAccumulator> = HashBuilder<hasher::Blake2x256Hasher, S>;
+/// BLAKE2 128-bit hash builder.
+pub type Blake2x128<S = NoAccumulator> = HashBuilder<hasher::Blake2x128Hasher, S>;
diff --git a/core/src/lib.rs b/core/src/lib.rs
index d9408e2d6b..9efdc71345 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -47,6 +47,7 @@
 extern crate ink_alloc;
 
 pub mod env;
+pub mod hash;
 pub mod storage;
 
 // Needed for derive macros of `core/derive` sub crate.
diff --git a/examples/README.md b/examples/README.md
index 4842e8940c..0b0bbb371c 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -9,7 +9,7 @@ Have a look at the different examples to better understand how to use ink! to bu
 For building the example smart contracts found in this folder you will need to have [`cargo-contract`](https://github.com/paritytech/cargo-contract) installed.
 
 ```
-cargo install --force --git https://github.com/paritytech/ink cargo-contract
+cargo install cargo-contract --force
 ```
 
 We use the `--force` to update to the most recent `cargo-contract` version.
diff --git a/examples/delegator/Cargo.toml b/examples/delegator/Cargo.toml
index 2c7e62a972..5883a0d483 100644
--- a/examples/delegator/Cargo.toml
+++ b/examples/delegator/Cargo.toml
@@ -1,20 +1,20 @@
 [package]
 name = "delegator"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
-adder = { version = "2.0.0", path = "adder", default-features = false, features = ["ink-as-dependency"] }
-subber = { version = "2.0.0", path = "subber", default-features = false, features = ["ink-as-dependency"] }
-accumulator = { version = "2.0.0", path = "accumulator", default-features = false, features = ["ink-as-dependency"] }
+adder = { version = "2.1.0", path = "adder", default-features = false, features = ["ink-as-dependency"] }
+subber = { version = "2.1.0", path = "subber", default-features = false, features = ["ink-as-dependency"] }
+accumulator = { version = "2.1.0", path = "accumulator", default-features = false, features = ["ink-as-dependency"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/delegator/accumulator/Cargo.toml b/examples/delegator/accumulator/Cargo.toml
index ed2f3d83e0..9a95c775c6 100644
--- a/examples/delegator/accumulator/Cargo.toml
+++ b/examples/delegator/accumulator/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "accumulator"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/delegator/accumulator/lib.rs b/examples/delegator/accumulator/lib.rs
index 9216496647..d79375d354 100644
--- a/examples/delegator/accumulator/lib.rs
+++ b/examples/delegator/accumulator/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
diff --git a/examples/delegator/adder/Cargo.toml b/examples/delegator/adder/Cargo.toml
index 772258baa5..11f2e517dc 100644
--- a/examples/delegator/adder/Cargo.toml
+++ b/examples/delegator/adder/Cargo.toml
@@ -1,18 +1,18 @@
 [package]
 name = "adder"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../../lang", default-features = false }
 
-accumulator = { version = "2.0.0", path = "../accumulator", default-features = false, features = ["ink-as-dependency"] }
+accumulator = { version = "2.1.0", path = "../accumulator", default-features = false, features = ["ink-as-dependency"] }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/delegator/adder/lib.rs b/examples/delegator/adder/lib.rs
index fb96554d82..8c5d3d509e 100644
--- a/examples/delegator/adder/lib.rs
+++ b/examples/delegator/adder/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
diff --git a/examples/delegator/lib.rs b/examples/delegator/lib.rs
index b1d54391f5..15f9a76c21 100644
--- a/examples/delegator/lib.rs
+++ b/examples/delegator/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
diff --git a/examples/delegator/subber/Cargo.toml b/examples/delegator/subber/Cargo.toml
index 7490c5f4d1..c11dd82453 100644
--- a/examples/delegator/subber/Cargo.toml
+++ b/examples/delegator/subber/Cargo.toml
@@ -1,18 +1,18 @@
 [package]
 name = "subber"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../../lang", default-features = false }
 
-accumulator = { version = "2.0.0", path = "../accumulator", default-features = false, features = ["ink-as-dependency"] }
+accumulator = { version = "2.1.0", path = "../accumulator", default-features = false, features = ["ink-as-dependency"] }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/delegator/subber/lib.rs b/examples/delegator/subber/lib.rs
index 882f36e8bb..76451e7cbd 100644
--- a/examples/delegator/subber/lib.rs
+++ b/examples/delegator/subber/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
diff --git a/examples/dns/Cargo.toml b/examples/dns/Cargo.toml
index 46f6dc4ca7..c54f94c0ea 100644
--- a/examples/dns/Cargo.toml
+++ b/examples/dns/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "dns"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/erc20/Cargo.toml b/examples/erc20/Cargo.toml
index c056909187..148dbdeb48 100644
--- a/examples/erc20/Cargo.toml
+++ b/examples/erc20/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "erc20"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/erc20/src/lib.rs b/examples/erc20/src/lib.rs
index 22b1206857..84674e4da7 100644
--- a/examples/erc20/src/lib.rs
+++ b/examples/erc20/src/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
@@ -142,4 +142,156 @@ mod erc20 {
             *self.allowances.get(&(*owner, *spender)).unwrap_or(&0)
         }
     }
+
+    /// Unit tests.
+    #[cfg(test)]
+    mod tests {
+        /// Imports all the definitions from the outer scope so we can use them here.
+        use super::*;
+        use ink_core::env;
+
+        /// The default constructor does its job.
+        #[test]
+        fn new_works() {
+            // Constructor works.
+            let _erc20 = Erc20::new(100);
+
+            // Transfer event triggered during initial contruction.
+            let emitted_events = env::test::recorded_events().collect::<Vec<_>>();
+            assert_eq!(1, emitted_events.len());
+            let raw_event = emitted_events.first().unwrap();
+            let event = <Event as scale::Decode>::decode(&mut &raw_event.data[..])
+                .expect("Invalid contract Event");
+            if let Event::Transfer(transfer) = event {
+                assert_eq!(100, transfer.value);
+            } else {
+                panic!("Expected a Transfer Event")
+            }
+        }
+
+        /// The total supply was applied.
+        #[test]
+        fn total_supply_works() {
+            // Constructor works.
+            let erc20 = Erc20::new(100);
+            // Transfer event triggered during initial contruction.
+            assert_eq!(env::test::recorded_events().count(), 1);
+            // Get the token total supply.
+            assert_eq!(erc20.total_supply(), 100);
+        }
+
+        /// Get the actual balance of an account.
+        #[test]
+        fn balance_of_works() {
+            // Constructor works
+            let erc20 = Erc20::new(100);
+            // Transfer event triggered during initial contruction
+            assert_eq!(env::test::recorded_events().count(), 1);
+            let accounts = env::test::default_accounts::<env::DefaultEnvTypes>()
+                .expect("Cannot get accounts");
+            // Alice owns all the tokens on deployment
+            assert_eq!(erc20.balance_of(accounts.alice), 100);
+            // Bob does not owns tokens
+            assert_eq!(erc20.balance_of(accounts.bob), 0);
+        }
+
+        #[test]
+        fn transfer_works() {
+            // Constructor works.
+            let mut erc20 = Erc20::new(100);
+            // Transfer event triggered during initial contruction.
+            assert_eq!(1, env::test::recorded_events().count());
+            let accounts = env::test::default_accounts::<env::DefaultEnvTypes>()
+                .expect("Cannot get accounts");
+
+            assert_eq!(erc20.balance_of(accounts.bob), 0);
+            // Alice transfers 10 tokens to Bob.
+            assert_eq!(erc20.transfer(accounts.bob, 10), true);
+            // The second Transfer event takes place.
+            assert_eq!(2, env::test::recorded_events().count());
+            // Bob owns 10 tokens.
+            assert_eq!(erc20.balance_of(accounts.bob), 10);
+        }
+
+        #[test]
+        fn invalid_transfer_should_fail() {
+            // Constructor works.
+            let mut erc20 = Erc20::new(100);
+            // Transfer event triggered during initial contruction.
+            assert_eq!(env::test::recorded_events().count(), 1);
+            let accounts = env::test::default_accounts::<env::DefaultEnvTypes>()
+                .expect("Cannot get accounts");
+
+            assert_eq!(erc20.balance_of(accounts.bob), 0);
+            // Get contract address.
+            let callee =
+                env::account_id::<env::DefaultEnvTypes>().unwrap_or([0x0; 32].into());
+            // Create call
+            let mut data =
+                env::call::CallData::new(env::call::Selector::from_str("balance_of"));
+            data.push_arg(&accounts.bob);
+            // Push the new execution context to set Bob as caller
+            assert_eq!(
+                env::test::push_execution_context::<env::DefaultEnvTypes>(
+                    accounts.bob,
+                    callee,
+                    1000000,
+                    1000000,
+                    data
+                ),
+                ()
+            );
+
+            // Bob fails to transfers 10 tokens to Eve.
+            assert_eq!(erc20.transfer(accounts.eve, 10), false);
+            // Alice owns all the tokens.
+            assert_eq!(erc20.balance_of(accounts.alice), 100);
+            assert_eq!(erc20.balance_of(accounts.bob), 0);
+            assert_eq!(erc20.balance_of(accounts.eve), 0);
+        }
+
+        #[test]
+        fn transfer_from_works() {
+            // Constructor works.
+            let mut erc20 = Erc20::new(100);
+            // Transfer event triggered during initial contruction.
+            assert_eq!(env::test::recorded_events().count(), 1);
+            let accounts = env::test::default_accounts::<env::DefaultEnvTypes>()
+                .expect("Cannot get accounts");
+
+            // Bob fails to transfer tokens owned by Alice.
+            assert_eq!(erc20.transfer_from(accounts.alice, accounts.eve, 10), false);
+            // Alice approves Bob for token transfers on her behalf.
+            assert_eq!(erc20.approve(accounts.bob, 10), true);
+
+            // The approve event takes place.
+            assert_eq!(env::test::recorded_events().count(), 2);
+
+            // Get contract address.
+            let callee =
+                env::account_id::<env::DefaultEnvTypes>().unwrap_or([0x0; 32].into());
+            // Create call.
+            let mut data =
+                env::call::CallData::new(env::call::Selector::from_str("balance_of"));
+            data.push_arg(&accounts.bob);
+            // Push the new execution context to set Bob as caller.
+            assert_eq!(
+                env::test::push_execution_context::<env::DefaultEnvTypes>(
+                    accounts.bob,
+                    callee,
+                    1000000,
+                    1000000,
+                    data
+                ),
+                ()
+            );
+
+            // Bob transfers tokens from Alice to Eve.
+            assert_eq!(erc20.transfer_from(accounts.alice, accounts.eve, 10), true);
+            // The third event takes place.
+            assert_eq!(env::test::recorded_events().count(), 3);
+            // Eve owns tokens.
+            assert_eq!(erc20.balance_of(accounts.eve), 10);
+        }
+    }
 }
diff --git a/examples/erc721/Cargo.toml b/examples/erc721/Cargo.toml
index a8d06e2917..a083b486d3 100644
--- a/examples/erc721/Cargo.toml
+++ b/examples/erc721/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "erc721"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/flipper/Cargo.toml b/examples/flipper/Cargo.toml
index 3fb9739e67..dca2eabd2f 100644
--- a/examples/flipper/Cargo.toml
+++ b/examples/flipper/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "flipper"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/flipper/src/lib.rs b/examples/flipper/src/lib.rs
index 0ca55331e5..6876f90b98 100644
--- a/examples/flipper/src/lib.rs
+++ b/examples/flipper/src/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
diff --git a/examples/incrementer/Cargo.toml b/examples/incrementer/Cargo.toml
index 7bb7c806d3..db0340e7ca 100644
--- a/examples/incrementer/Cargo.toml
+++ b/examples/incrementer/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "incrementer"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/incrementer/src/lib.rs b/examples/incrementer/src/lib.rs
index df5bd6b84b..efc458044e 100644
--- a/examples/incrementer/src/lib.rs
+++ b/examples/incrementer/src/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
diff --git a/examples/multisig_plain/Cargo.toml b/examples/multisig_plain/Cargo.toml
index 0ed5517de6..ff9ff8b7e4 100755
--- a/examples/multisig_plain/Cargo.toml
+++ b/examples/multisig_plain/Cargo.toml
@@ -1,17 +1,17 @@
 [package]
 name = "multisig_plain"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
-ink_prelude = { version = "2.0.0", path = "../../prelude", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
+ink_prelude = { version = "2.1.0", path = "../../prelude", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/examples/multisig_plain/lib.rs b/examples/multisig_plain/lib.rs
index af8dd4fac6..9e774e80ca 100755
--- a/examples/multisig_plain/lib.rs
+++ b/examples/multisig_plain/lib.rs
@@ -107,6 +107,7 @@ mod multisig_plain {
 
     /// Indicates whether a transaction is already confirmed or needs further confirmations.
     #[derive(scale::Encode, scale::Decode, Clone, Copy)]
+    #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))]
     pub enum ConfirmationStatus {
         /// The transaction is already confirmed.
         Confirmed,
diff --git a/examples/runtime-storage/Cargo.toml b/examples/runtime-storage/Cargo.toml
index a849cc01ae..da9be814c9 100755
--- a/examples/runtime-storage/Cargo.toml
+++ b/examples/runtime-storage/Cargo.toml
@@ -1,17 +1,17 @@
 [package]
 name = "runtime_storage"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
-ink_core = { version = "2.0.0", path = "../../core", default-features = false }
-ink_lang = { version = "2.0.0", path = "../../lang", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives", default-features = false }
+ink_prelude = { version = "2.1.0", path = "../../prelude", default-features = false }
+ink_abi = { version = "2.1.0", path = "../../abi", default-features = false, features = ["derive"], optional = true }
+ink_core = { version = "2.1.0", path = "../../core", default-features = false }
+ink_lang = { version = "2.1.0", path = "../../lang", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
-blake2-rfc = { version = "0.2.18", default-features = false }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
@@ -33,7 +33,6 @@ crate-type = [
 default = ["test-env"]
 std = [
     "ink_primitives/std",
-    "blake2-rfc/std",
     "ink_abi/std",
     "ink_core/std",
     "scale/std",
diff --git a/examples/runtime-storage/src/lib.rs b/examples/runtime-storage/src/lib.rs
index 3013e3b8d7..6e1cb603f9 100755
--- a/examples/runtime-storage/src/lib.rs
+++ b/examples/runtime-storage/src/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2019-2020 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.
@@ -16,24 +16,39 @@
 
 use ink_lang as ink;
 
-mod crypto {
-    /// Do a Blake2 256-bit hash and place result in `dest`.
-    pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) {
-        dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes());
-    }
+#[ink::contract(version = "0.1.0")]
+mod runtime {
+    use ink_core::{
+        env,
+        hash::Blake2x128,
+    };
+    use ink_prelude::{
+        format,
+        vec,
+    };
+    use scale::{
+        Decode,
+        Encode,
+    };
 
-    /// Do a Blake2 256-bit hash and return result.
-    pub fn blake2_256(data: &[u8]) -> [u8; 32] {
-        let mut r = [0; 32];
-        blake2_256_into(data, &mut r);
-        r
+    /// All balance information for an account, mirroring the structure defined in the runtime.
+    /// Copied from [substrate](https://github.com/paritytech/substrate/blob/2c87fe171bc341755a43a3b32d67560469f8daac/frame/system/src/lib.rs#L307)
+    #[derive(Encode, Decode)]
+    pub struct AccountData {
+        free: Balance,
+        _reserved: Balance,
+        _misc_frozen: Balance,
+        _fee_frozen: Balance,
     }
-}
 
-#[ink::contract(version = "0.1.0")]
-mod runtime {
-    use super::crypto;
-    use scale::KeyedVec as _;
+    /// Information of an account, mirroring the structure defined in the runtime
+    /// Copied from [substrate](https://github.com/paritytech/substrate/blob/2c87fe171bc341755a43a3b32d67560469f8daac/frame/system/src/lib.rs#L307)
+    #[derive(Encode, Decode)]
+    pub struct AccountInfo {
+        _nonce: u32,
+        _refcount: u8,
+        data: AccountData,
+    }
 
     /// This simple contract reads a value from runtime storage
     #[ink(storage)]
@@ -43,19 +58,57 @@ mod runtime {
         #[ink(constructor)]
         fn new(&mut self) {}
 
-        /// Returns the account balance, read directly from runtime storage
+        /// Returns an account's free balance, read directly from runtime storage
+        ///
+        /// # Key Scheme
+        ///
+        /// A key for the [substrate storage map]
+        /// (https://github.com/paritytech/substrate/blob/dd97b1478b31a4715df7e88a5ebc6664425fb6c6/frame/support/src/storage/generator/map.rs#L28)
+        /// is constructed with:
+        ///
+        /// ```nocompile
+        /// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key))
+        /// ```
+        ///
+        /// For the `System` module's `Account` map, the [hasher implementation]
+        /// (https://github.com/paritytech/substrate/blob/2c87fe171bc341755a43a3b32d67560469f8daac/frame/system/src/lib.rs#L349)
+        /// is `blake2_128_concat`.
         #[ink(message)]
         fn get_balance(&self, account: AccountId) -> Balance {
-            const BALANCE_OF: &[u8] = b"Balances FreeBalance";
-            let key = crypto::blake2_256(&account.to_keyed_vec(BALANCE_OF));
-            let result = self.env().get_runtime_storage::<Balance>(&key[..]);
-            result.unwrap_or_else(|| Ok(0)).unwrap_or_default()
+            let mut key = vec![
+                // Precomputed: Twox128("System")
+                38, 170, 57, 78, 234, 86, 48, 224, 124, 72, 174, 12, 149, 88, 206, 247,
+                // Precomputed: Twox128("Account")
+                185, 157, 136, 14, 198, 129, 121, 156, 12, 243, 14, 136, 134, 55, 29, 169,
+            ];
+
+            let encoded_account = account.encode();
+            let hashed_account = <Blake2x128>::hash_bytes(&encoded_account);
+
+            // The hasher is `Blake2_128Concat` which appends the unhashed account to the hashed account
+            key.extend_from_slice(&hashed_account);
+            key.extend_from_slice(&encoded_account);
+
+            // fetch from runtime storage
+            let result = self.env().get_runtime_storage::<AccountInfo>(&key[..]);
+            match result {
+                Some(Ok(account_info)) => account_info.data.free,
+                Some(Err(err)) => {
+                    env::println(&format!("Error reading AccountInfo {:?}", err));
+                    0
+                }
+                None => {
+                    env::println(&format!("No data at key {:?}", key));
+                    0
+                }
+            }
         }
     }
 
     #[cfg(all(test))]
     mod tests {
         use super::*;
+        use ink_core::env;
 
         #[test]
         fn non_existent_account_returns_zero() {
@@ -63,5 +116,40 @@ mod runtime {
             let account: AccountId = [0u8; 32].into();
             assert_eq!(contract.get_balance(account), 0);
         }
+
+        #[test]
+        fn returns_account_balance_from_storage() {
+            let contract = RuntimeStorage::new();
+            let account: AccountId = [0u8; 32].into();
+            let balance = 1_000_000;
+
+            let account_info = AccountInfo {
+                data: AccountData {
+                    free: balance,
+                    _reserved: 0,
+                    _fee_frozen: 0,
+                    _misc_frozen: 0,
+                },
+                _nonce: 0,
+                _refcount: 0,
+            };
+
+            let encoded_account = &account.encode();
+
+            let mut key = vec![
+                // Precomputed: Twox128("System")
+                38, 170, 57, 78, 234, 86, 48, 224, 124, 72, 174, 12, 149, 88, 206, 247,
+                // Precomputed: Twox128("Account")
+                185, 157, 136, 14, 198, 129, 121, 156, 12, 243, 14, 136, 134, 55, 29, 169,
+            ];
+
+            let hashed_account = <Blake2x128>::hash_bytes(&encoded_account);
+
+            key.extend_from_slice(&hashed_account);
+            key.extend_from_slice(&encoded_account);
+
+            env::test::set_runtime_storage(&key, account_info);
+            assert_eq!(contract.get_balance(account), balance);
+        }
     }
 }
diff --git a/lang/Cargo.toml b/lang/Cargo.toml
index c9711bf093..abb547a775 100644
--- a/lang/Cargo.toml
+++ b/lang/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_lang"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
@@ -15,13 +15,13 @@ categories = ["no-std", "embedded"]
 include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
 
 [dependencies]
-ink_core = { version = "2.0.0", path = "../core", default-features = false }
-ink_primitives = { version = "2.0.0", path = "../primitives", default-features = false }
-ink_abi = { version = "2.0.0", path = "../abi", default-features = false, optional = true }
-ink_prelude = { version = "2.0.0", path = "../prelude/", default-features = false }
-ink_lang_macro = { version = "2.0.0", path = "macro", default-features = false }
+ink_core = { version = "2.1.0", path = "../core", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../primitives", default-features = false }
+ink_abi = { version = "2.1.0", path = "../abi", default-features = false, optional = true }
+ink_prelude = { version = "2.1.0", path = "../prelude/", default-features = false }
+ink_lang_macro = { version = "2.1.0", path = "macro", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive", "full"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }
 derive_more = { version = "0.99", default-features = false, features = ["from"] }
 
 [features]
diff --git a/lang/macro/Cargo.toml b/lang/macro/Cargo.toml
index 81d7a5df70..343dd0382b 100644
--- a/lang/macro/Cargo.toml
+++ b/lang/macro/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_lang_macro"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
@@ -15,9 +15,9 @@ categories = ["no-std", "embedded"]
 include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
 
 [dependencies]
-ink_primitives = { version = "2.0.0", path = "../../primitives/", default-features = false }
+ink_primitives = { version = "2.1.0", path = "../../primitives/", default-features = false }
 
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }
 quote = "1"
 syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] }
 proc-macro2 = "1.0"
@@ -30,9 +30,9 @@ derive_more = { version = "0.99", default-features = false, features = ["from"]
 regex = "1.3"
 
 [dev-dependencies]
-ink_abi = { version = "2.0.0", path = "../../abi/" }
-ink_core = { version = "2.0.0", path = "../../core/" }
-ink_lang = { version = "2.0.0", path = "..", default-features = false, features = ["ink-generate-abi"] }
+ink_abi = { version = "2.1.0", path = "../../abi/" }
+ink_core = { version = "2.1.0", path = "../../core/" }
+ink_lang = { version = "2.1.0", path = "..", default-features = false, features = ["ink-generate-abi"] }
 
 trybuild = "1.0.24"
 pretty_assertions = "0.6.1"
diff --git a/lang/macro/src/codegen/contract.rs b/lang/macro/src/codegen/contract.rs
index 4972e65739..92a37dd05f 100644
--- a/lang/macro/src/codegen/contract.rs
+++ b/lang/macro/src/codegen/contract.rs
@@ -69,6 +69,15 @@ impl GenerateCode for ContractModule<'_> {
         let cross_calling = self.generate_code_using::<CrossCalling>();
         let non_ink_items = &self.contract.non_ink_items;
 
+        let test_event_alias = if !self.contract.events.is_empty() {
+            quote! {
+                #[cfg(all(test, feature = "test-env"))]
+                pub type Event = self::__ink_private::Event;
+            }
+        } else {
+            quote! {}
+        };
+
         quote! {
             mod #ident {
                 #env_types
@@ -96,6 +105,8 @@ impl GenerateCode for ContractModule<'_> {
                 #[cfg(feature = "ink-as-dependency")]
                 pub type #storage_ident = self::__ink_private::StorageAsDependency;
 
+                #test_event_alias
+
                 #event_structs
 
                 #(
diff --git a/lang/macro/src/codegen/events.rs b/lang/macro/src/codegen/events.rs
index e6bd82f02f..d22596d39c 100644
--- a/lang/macro/src/codegen/events.rs
+++ b/lang/macro/src/codegen/events.rs
@@ -119,7 +119,7 @@ impl EventHelpers<'_> {
                     where
                         E: Into<Self::Event>,
                     {
-                        ink_lang::EnvAccess::<EnvTypes>::emit_event(self, event.into())
+                        ink_core::env::emit_event::<EnvTypes, Self::Event>(event.into());
                     }
                 }
             };
@@ -135,7 +135,7 @@ impl EventHelpers<'_> {
             .collect::<Vec<_>>();
 
         quote! {
-            #[derive(scale::Encode)]
+            #[derive(scale::Encode, scale::Decode)]
             pub enum Event {
                 #( #event_idents(#event_idents), )*
             }
@@ -182,7 +182,7 @@ impl EventHelpers<'_> {
 ///
 /// - making all fields `pub`
 /// - strip `#[ink(..)]` attributes
-/// - add `#[derive(scale::Encode)]`
+/// - add `#[derive(scale::Encode, scale::Decode)]`
 ///
 /// # Note
 ///
@@ -223,7 +223,7 @@ impl EventStructs<'_> {
             quote_spanned!(span =>
                 #conflic_depedency_cfg
                 #(#attrs)*
-                #[derive(scale::Encode)]
+                #[derive(scale::Encode, scale::Decode)]
                 pub struct #ident
                     #fields
             )
diff --git a/lang/src/env_access.rs b/lang/src/env_access.rs
index 637d869f57..4c0262ba6c 100644
--- a/lang/src/env_access.rs
+++ b/lang/src/env_access.rs
@@ -23,7 +23,6 @@ use ink_core::{
         },
         EnvTypes,
         Result,
-        Topics,
     },
 };
 use ink_primitives::Key;
@@ -185,18 +184,6 @@ where
         env::tombstone_deposit::<T>().expect("couldn't decode tombstone deposits")
     }
 
-    /// Emits an event with the given event data.
-    ///
-    /// # Note
-    ///
-    /// For more details visit: [`ink_core::env::emit_event`]
-    pub fn emit_event<Event>(self, event: Event)
-    where
-        Event: Topics<T> + scale::Encode,
-    {
-        env::emit_event::<T, Event>(event)
-    }
-
     /// Sets the rent allowance of the executed contract to the new value.
     ///
     /// # Note
diff --git a/prelude/Cargo.toml b/prelude/Cargo.toml
index 83b1f3c7b6..5a70c20c74 100644
--- a/prelude/Cargo.toml
+++ b/prelude/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_prelude"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Robin Freyler <robin@parity.io>", "Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml
index d008d9281b..6a70edbb0c 100644
--- a/primitives/Cargo.toml
+++ b/primitives/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ink_primitives"
-version = "2.0.0"
+version = "2.1.0"
 authors = ["Robin Freyler <robin@parity.io>", "Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
@@ -18,9 +18,9 @@ categories = ["no-std", "embedded"]
 include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"]
 
 [dependencies]
-ink_prelude = { version = "2.0.0", path = "../prelude/", default-features = false }
+ink_prelude = { version = "2.1.0", path = "../prelude/", default-features = false }
 tiny-keccak = { version = "2.0", features = ["keccak"] }
-scale = { package = "parity-scale-codec", version = "1.2", default-features = false, features = ["derive", "full"] }
+scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }
 
 [dependencies.type-metadata]
 git = "https://github.com/type-metadata/type-metadata.git"
diff --git a/scripts/pre_cache.sh b/scripts/pre_cache.sh
new file mode 100755
index 0000000000..ca14983eb9
--- /dev/null
+++ b/scripts/pre_cache.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -u
+
+# if there is no directory for this $CI_COMMIT_REF_NAME/$CI_JOB_NAME
+# create such directory and
+# copy recursively all the files from the newest dir which has $CI_JOB_NAME, if it exists
+if [[ ! -d $CARGO_TARGET_DIR ]]; then
+  mkdir -p "/ci-cache/$CI_PROJECT_NAME/targets/$CI_COMMIT_REF_NAME";
+  FRESH_CACHE=$(find "/ci-cache/$CI_PROJECT_NAME/targets" -mindepth 2 -maxdepth 2 \
+    -type d -name "$CI_JOB_NAME"  -exec stat --printf="%Y\t%n\n" {} \; |sort -n -r |head -1 |cut -f2);
+  if [[ -d $FRESH_CACHE ]]; then
+    echo "____Using" "$FRESH_CACHE" "to prepopulate the cache____";
+    time cp -r "$FRESH_CACHE" "$CARGO_TARGET_DIR";
+  else
+    echo "_____No such targets dir, proceeding from scratch_____";
+  fi
+else
+  echo "____No need to prepopulate CARGO_TARGET_DIR cache____";
+fi


Test patch:
diff --git a/core/src/env/engine/off_chain/test_api.rs b/core/src/env/engine/off_chain/test_api.rs
index 9a32ab6eff..997c6b34de 100644
--- a/core/src/env/engine/off_chain/test_api.rs
+++ b/core/src/env/engine/off_chain/test_api.rs
@@ -288,14 +288,13 @@ where
 ///
 /// - Initializes the off-chain environment with default values that fit most
 /// uses cases.
-/// - The off-chain environment _must_ be initialized before use.
-pub fn initialize_as_default<T>() -> Result<()>
+pub fn initialize_or_reset_as_default<T>() -> Result<()>
 where
     T: EnvTypes,
     <T as EnvTypes>::AccountId: From<[u8; 32]>,
 {
     <EnvInstance as OnInstance>::on_instance(|instance| {
-        instance.initialize_as_default::<T>()
+        instance.initialize_or_reset_as_default::<T>()
     })
 }
 
@@ -307,7 +306,7 @@ where
     F: FnOnce(DefaultAccounts<T>) -> Result<()>,
     <T as EnvTypes>::AccountId: From<[u8; 32]>,
 {
-    initialize_as_default::<T>()?;
+    initialize_or_reset_as_default::<T>()?;
     let default_accounts = default_accounts::<T>()?;
     f(default_accounts)
 }
diff --git a/core/src/env/tests.rs b/core/src/env/tests.rs
new file mode 100644
index 0000000000..a6ed2ebeb0
--- /dev/null
+++ b/core/src/env/tests.rs
@@ -0,0 +1,66 @@
+// Copyright 2019-2020 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 crate::env;
+
+static TEST_INPUT: &[u8] = b"DEAD_BEEF";
+
+#[test]
+fn test_hash_keccak_256() {
+    let mut output = [0x00_u8; 32];
+    env::hash::keccak_256(TEST_INPUT, &mut output);
+    assert_eq!(
+        output,
+        [
+            24, 230, 209, 59, 127, 30, 158, 244, 60, 177, 132, 150, 167, 244, 64, 69,
+            184, 123, 185, 44, 211, 199, 208, 179, 14, 64, 126, 140, 217, 69, 36, 216
+        ]
+    );
+}
+
+#[test]
+fn test_hash_sha2_256() {
+    let mut output = [0x00_u8; 32];
+    env::hash::sha2_256(TEST_INPUT, &mut output);
+    assert_eq!(
+        output,
+        [
+            136, 15, 25, 218, 88, 54, 49, 152, 115, 168, 147, 189, 207, 171, 243, 129,
+            161, 76, 15, 141, 197, 106, 111, 213, 19, 197, 133, 219, 181, 233, 195, 120
+        ]
+    );
+}
+
+#[test]
+fn test_hash_blake2_256() {
+    let mut output = [0x00_u8; 32];
+    env::hash::blake2_256(TEST_INPUT, &mut output);
+    assert_eq!(
+        output,
+        [
+            244, 247, 235, 182, 194, 161, 28, 69, 34, 106, 237, 7, 57, 87, 190, 12, 92,
+            171, 91, 176, 135, 52, 247, 94, 8, 112, 94, 183, 140, 101, 208, 120
+        ]
+    );
+}
+
+#[test]
+fn test_hash_blake2_128() {
+    let mut output = [0x00_u8; 16];
+    env::hash::blake2_128(TEST_INPUT, &mut output);
+    assert_eq!(
+        output,
+        [180, 158, 48, 21, 171, 163, 217, 175, 145, 160, 25, 159, 213, 142, 103, 242]
+    );
+}
diff --git a/lang/macro/src/codegen/testable.rs b/lang/macro/src/codegen/testable.rs
index fca7691c55..29bb580bc7 100644
--- a/lang/macro/src/codegen/testable.rs
+++ b/lang/macro/src/codegen/testable.rs
@@ -56,7 +56,7 @@ impl GenerateCode for TestWrapper<'_> {
                     type Wrapped = TestableStorage;
 
                     fn instantiate() -> Self::Wrapped {
-                        ink_core::env::test::initialize_as_default::<ink_core::env::DefaultEnvTypes>()
+                        ink_core::env::test::initialize_or_reset_as_default::<ink_core::env::DefaultEnvTypes>()
                             .expect("encountered already initialized off-chain environment");
                         let mut contract: Self = unsafe {
                             let mut alloc =