Repository: CosmWasm/cosmwasm
Pull request #1120 (2021-09-29 13:43:54)

Benchmark Wasm via argon2 and change gas price to 150_000 per op


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 65887b7dc..1baba57a7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -42,6 +42,7 @@ workflows:
                 - load-wasm-speed
                 - cache-analyze
                 - fix-benches
+                - benchmark_argon2
   deploy:
     jobs:
       - build_and_upload_devcontracts:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 40dce49c8..fdaadec05 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -45,6 +45,8 @@ and this project adheres to
   and deprecated.
 - cosmwasm-vm: Bump required marker export `interface_version_7` to
   `interface_version_8`.
+- cosmwasm-vm: Increase cost per Wasm operation from 1 to 150_000 and adjust
+  crypto API gas cost based on the target of 1 Teragas per millisecond.
 
 ### Removed
 
diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock
index 80209aac1..fe9193a8a 100644
--- a/contracts/hackatom/Cargo.lock
+++ b/contracts/hackatom/Cargo.lock
@@ -17,6 +17,18 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "arrayref"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
 [[package]]
 name = "autocfg"
 version = "1.0.1"
@@ -50,6 +62,17 @@ version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
+[[package]]
+name = "blake2b_simd"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
 [[package]]
 name = "block-buffer"
 version = "0.9.0"
@@ -89,6 +112,12 @@ version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "44c32f031ea41b4291d695026c023b95d59db2d8a2c7640800ed56bc8f510f22"
 
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
 [[package]]
 name = "cosmwasm-crypto"
 version = "1.0.0-soon"
@@ -557,6 +586,7 @@ dependencies = [
  "cosmwasm-std",
  "cosmwasm-storage",
  "cosmwasm-vm",
+ "rust-argon2",
  "schemars",
  "serde",
  "sha2",
@@ -991,6 +1021,18 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "rust-argon2"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
+dependencies = [
+ "base64",
+ "blake2b_simd",
+ "constant_time_eq",
+ "crossbeam-utils",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.20"
diff --git a/contracts/hackatom/Cargo.toml b/contracts/hackatom/Cargo.toml
index d6541333b..813bfdda6 100644
--- a/contracts/hackatom/Cargo.toml
+++ b/contracts/hackatom/Cargo.toml
@@ -31,6 +31,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"]
 
 [dependencies]
 cosmwasm-std = { path = "../../packages/std", default-features = false }
+rust-argon2 = "0.8"
 schemars = "0.8.1"
 serde = { version = "1.0.103", default-features = false, features = ["derive"] }
 sha2 = "0.9.1"
diff --git a/contracts/hackatom/schema/execute_msg.json b/contracts/hackatom/schema/execute_msg.json
index b98431246..96131414d 100644
--- a/contracts/hackatom/schema/execute_msg.json
+++ b/contracts/hackatom/schema/execute_msg.json
@@ -15,6 +15,37 @@
       },
       "additionalProperties": false
     },
+    {
+      "description": "Hashes some data. Uses CPU and memory, but no external calls.",
+      "type": "object",
+      "required": [
+        "argon2"
+      ],
+      "properties": {
+        "argon2": {
+          "type": "object",
+          "required": [
+            "mem_cost",
+            "time_cost"
+          ],
+          "properties": {
+            "mem_cost": {
+              "description": "The amount of memory requested (KB).",
+              "type": "integer",
+              "format": "uint32",
+              "minimum": 0.0
+            },
+            "time_cost": {
+              "description": "The number of passes.",
+              "type": "integer",
+              "format": "uint32",
+              "minimum": 0.0
+            }
+          }
+        }
+      },
+      "additionalProperties": false
+    },
     {
       "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)",
       "type": "object",
diff --git a/contracts/hackatom/src/contract.rs b/contracts/hackatom/src/contract.rs
index 9155f5899..ae772ffa9 100644
--- a/contracts/hackatom/src/contract.rs
+++ b/contracts/hackatom/src/contract.rs
@@ -66,6 +66,10 @@ pub fn execute(
 ) -> Result<Response, HackError> {
     match msg {
         ExecuteMsg::Release {} => do_release(deps, env, info),
+        ExecuteMsg::Argon2 {
+            mem_cost,
+            time_cost,
+        } => do_argon2(mem_cost, time_cost),
         ExecuteMsg::CpuLoop {} => do_cpu_loop(),
         ExecuteMsg::StorageLoop {} => do_storage_loop(deps),
         ExecuteMsg::MemoryLoop {} => do_memory_loop(),
@@ -101,6 +105,28 @@ fn do_release(deps: DepsMut, env: Env, info: MessageInfo) -> Result<Response, Ha
     }
 }
 
+fn do_argon2(mem_cost: u32, time_cost: u32) -> Result<Response, HackError> {
+    let password = b"password";
+    let salt = b"othersalt";
+    let config = argon2::Config {
+        variant: argon2::Variant::Argon2i,
+        version: argon2::Version::Version13,
+        mem_cost,
+        time_cost,
+        lanes: 4,
+        thread_mode: argon2::ThreadMode::Sequential,
+        secret: &[],
+        ad: &[],
+        hash_length: 32,
+    };
+    let hash = argon2::hash_encoded(password, salt, &config)
+        .map_err(|e| StdError::generic_err(format!("hash_encoded errored: {}", e)))?;
+    // let matches = argon2::verify_encoded(&hash, password).unwrap();
+    // assert!(matches);
+    Ok(Response::new().set_data(hash.into_bytes()))
+    //Ok(Response::new())
+}
+
 fn do_cpu_loop() -> Result<Response, HackError> {
     let mut counter = 0u64;
     loop {
diff --git a/contracts/hackatom/src/msg.rs b/contracts/hackatom/src/msg.rs
index 6b51d1c85..0ce872245 100644
--- a/contracts/hackatom/src/msg.rs
+++ b/contracts/hackatom/src/msg.rs
@@ -40,6 +40,13 @@ pub enum SudoMsg {
 pub enum ExecuteMsg {
     /// Releasing all funds in the contract to the beneficiary. This is the only "proper" action of this demo contract.
     Release {},
+    /// Hashes some data. Uses CPU and memory, but no external calls.
+    Argon2 {
+        /// The amount of memory requested (KB).
+        mem_cost: u32,
+        /// The number of passes.
+        time_cost: u32,
+    },
     /// Infinite loop to burn cpu cycles (only run when metering is enabled)
     CpuLoop {},
     /// Infinite loop making storage calls (to test when their limit hits)
diff --git a/docs/GAS.md b/docs/GAS.md
new file mode 100644
index 000000000..4456a89af
--- /dev/null
+++ b/docs/GAS.md
@@ -0,0 +1,40 @@
+# Gas
+
+Gas is a way to measure computational expense of a smart contract execution,
+including CPU time and storage cost. It's unit is 1, i.e. you can think of it as
+countable points. Gas consumption is deterministic, so executing the same thing
+costs the same amount of gas across all hardware and operating systems.
+
+CosmWasm charges gas for Wasm operations, calls to host functions and calls to
+the Cosmos SDK. CosmWasm gas is different from Cosmos SDK gas as the numbers
+here are much larger. Since we charge gas for arbitrary user defined operations,
+we need to charge each Wasm operation individually and cannot group larger tasks
+together. As a result, the gas values become much larger than in Cosmos SDK even
+for very fast executions. There is a [multiplier][defaultgasmultiplier] to
+translate between CosmWasm gas and Cosmos SDK. It was measured and set to 100 a
+while ago and can be adjusted when necessary.
+
+For CosmWasm gas, the target gas consumption is 1 Teragas (10^12 gas) per
+millisecond. This idea is [inspired by NEAR][neargas] and we encourage you to
+read their excellent docs on that topic.
+
+In order to meet this target, we execute Argon2 in a test contract ([#1120]).
+This is a CPU and memory intense job that does not call out into the host. At a
+constant gas cost per operation of 1 (pre CosmWasm 1.0), this consumed 96837752
+gas and took 15ms on our CI system. The ideal cost per operation for this system
+is `10**12 / (96837752 / 15)`: 154898. This is rounded to 150000 for simplicity.
+
+Each machine is different, we know that. But the above target helps us in
+multiple ways:
+
+1. Develop an intuition what it means to burn X gas or how much gas can be used
+   if a block should be executable in e.g. 1 second
+2. Have a target for adjustments, e.g. when the Wasm runtime becomes faster or
+   slower
+3. Allow pricing of calls that are not executed in Wasm, such as crypto APIs
+4. Find significant over or underpricing
+
+[defaultgasmultiplier]:
+  https://github.com/CosmWasm/wasmd/blob/v0.19.0/x/wasm/keeper/gas_register.go#L18
+[neargas]: https://docs.near.org/docs/concepts/gas
+[#1120]: https://github.com/CosmWasm/cosmwasm/pull/1120
diff --git a/packages/vm/benches/main.rs b/packages/vm/benches/main.rs
index 01c80e919..7eaa5272e 100644
--- a/packages/vm/benches/main.rs
+++ b/packages/vm/benches/main.rs
@@ -13,11 +13,13 @@ use cosmwasm_vm::{
 
 // Instance
 const DEFAULT_MEMORY_LIMIT: Size = Size::mebi(64);
-const DEFAULT_GAS_LIMIT: u64 = 400_000;
+const DEFAULT_GAS_LIMIT: u64 = 1_000_000_000_000; // ~1ms
 const DEFAULT_INSTANCE_OPTIONS: InstanceOptions = InstanceOptions {
     gas_limit: DEFAULT_GAS_LIMIT,
     print_debug: false,
 };
+const HIGH_GAS_LIMIT: u64 = 20_000_000_000_000_000; // ~20s, allows many calls on one instance
+
 // Cache
 const MEMORY_CACHE_SIZE: Size = Size::mebi(200);
 
@@ -38,7 +40,7 @@ fn bench_instance(c: &mut Criterion) {
     group.bench_function("execute init", |b| {
         let backend = mock_backend(&[]);
         let much_gas: InstanceOptions = InstanceOptions {
-            gas_limit: 500_000_000_000,
+            gas_limit: HIGH_GAS_LIMIT,
             ..DEFAULT_INSTANCE_OPTIONS
         };
         let mut instance =
@@ -53,10 +55,10 @@ fn bench_instance(c: &mut Criterion) {
         });
     });
 
-    group.bench_function("execute execute", |b| {
+    group.bench_function("execute execute (release)", |b| {
         let backend = mock_backend(&[]);
         let much_gas: InstanceOptions = InstanceOptions {
-            gas_limit: 500_000_000_000,
+            gas_limit: HIGH_GAS_LIMIT,
             ..DEFAULT_INSTANCE_OPTIONS
         };
         let mut instance =
@@ -77,6 +79,34 @@ fn bench_instance(c: &mut Criterion) {
         });
     });
 
+    group.bench_function("execute execute (argon2)", |b| {
+        let backend = mock_backend(&[]);
+        let much_gas: InstanceOptions = InstanceOptions {
+            gas_limit: HIGH_GAS_LIMIT,
+            ..DEFAULT_INSTANCE_OPTIONS
+        };
+        let mut instance =
+            Instance::from_code(CONTRACT, backend, much_gas, Some(DEFAULT_MEMORY_LIMIT)).unwrap();
+
+        let info = mock_info("creator", &coins(1000, "earth"));
+        let msg = br#"{"verifier": "verifies", "beneficiary": "benefits"}"#;
+        let contract_result =
+            call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap();
+        assert!(contract_result.into_result().is_ok());
+
+        let mut gas_used = 0;
+        b.iter(|| {
+            let gas_before = instance.get_gas_left();
+            let info = mock_info("hasher", &[]);
+            let msg = br#"{"argon2":{"mem_cost":256,"time_cost":3}}"#;
+            let contract_result =
+                call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap();
+            assert!(contract_result.into_result().is_ok());
+            gas_used = gas_before - instance.get_gas_left();
+        });
+        println!("Gas used: {}", gas_used);
+    });
+
     group.finish();
 }
 
diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs
index 3d709fc4e..866ca5653 100644
--- a/packages/vm/src/cache.rs
+++ b/packages/vm/src/cache.rs
@@ -382,7 +382,7 @@ mod tests {
     use std::iter::FromIterator;
     use tempfile::TempDir;
 
-    const TESTING_GAS_LIMIT: u64 = 4_000_000;
+    const TESTING_GAS_LIMIT: u64 = 500_000_000_000; // ~0.5ms
     const TESTING_MEMORY_LIMIT: Size = Size::mebi(16);
     const TESTING_OPTIONS: InstanceOptions = InstanceOptions {
         gas_limit: TESTING_GAS_LIMIT,
diff --git a/packages/vm/src/environment.rs b/packages/vm/src/environment.rs
index 6ef1333aa..fb71d064c 100644
--- a/packages/vm/src/environment.rs
+++ b/packages/vm/src/environment.rs
@@ -31,47 +31,21 @@ pub struct GasConfig {
     pub ed25519_batch_verify_one_pubkey_cost: u64,
 }
 
-impl GasConfig {
-    // Base crypto-verify gas cost: 1000 Cosmos SDK * 100 CosmWasm factor
-    const BASE_CRYPTO_COST: u64 = 100_000;
-
-    // secp256k1 cost factor (reference)
-    const SECP256K1_VERIFY_FACTOR: (u64, u64) = (154, 154); // ~154 us in crypto benchmarks
-
-    // Gas cost factors, relative to secp256k1_verify cost
-    const SECP256K1_RECOVER_PUBKEY_FACTOR: (u64, u64) = (162, 154); // 162 us / 154 us ~ 1.05
-    const ED25519_VERIFY_FACTOR: (u64, u64) = (63, 154); // 63 us / 154 us ~ 0.41
-
-    // Gas cost factors, relative to ed25519_verify cost
-    // From https://docs.rs/ed25519-zebra/2.2.0/ed25519_zebra/batch/index.html
-    const ED255219_BATCH_VERIFY_FACTOR: (u64, u64) = (
-        GasConfig::ED25519_VERIFY_FACTOR.0,
-        GasConfig::ED25519_VERIFY_FACTOR.1 * 2,
-    ); // 0.41 / 2. ~ 0.21
-    const ED255219_BATCH_VERIFY_ONE_PUBKEY_FACTOR: (u64, u64) = (
-        GasConfig::ED25519_VERIFY_FACTOR.0,
-        GasConfig::ED25519_VERIFY_FACTOR.1 * 4,
-    ); // 0.41 / 4. ~ 0.1
-
-    fn calc_crypto_cost(factor: (u64, u64)) -> u64 {
-        (GasConfig::BASE_CRYPTO_COST * factor.0) / factor.1
-    }
-}
-
 impl Default for GasConfig {
     fn default() -> Self {
+        // Target is 10^12 per millisecond (see GAS.md), i.e. 10^9 gas per µ second.
+        const GAS_PER_US: u64 = 1_000_000_000;
         Self {
-            secp256k1_verify_cost: GasConfig::calc_crypto_cost(GasConfig::SECP256K1_VERIFY_FACTOR),
-            secp256k1_recover_pubkey_cost: GasConfig::calc_crypto_cost(
-                GasConfig::SECP256K1_RECOVER_PUBKEY_FACTOR,
-            ),
-            ed25519_verify_cost: GasConfig::calc_crypto_cost(GasConfig::ED25519_VERIFY_FACTOR),
-            ed25519_batch_verify_cost: GasConfig::calc_crypto_cost(
-                GasConfig::ED255219_BATCH_VERIFY_FACTOR,
-            ),
-            ed25519_batch_verify_one_pubkey_cost: GasConfig::calc_crypto_cost(
-                GasConfig::ED255219_BATCH_VERIFY_ONE_PUBKEY_FACTOR,
-            ),
+            // ~154 us in crypto benchmarks
+            secp256k1_verify_cost: 154 * GAS_PER_US,
+            // ~162 us in crypto benchmarks
+            secp256k1_recover_pubkey_cost: 162 * GAS_PER_US,
+            // ~63 us in crypto benchmarks
+            ed25519_verify_cost: 63 * GAS_PER_US,
+            // Gas cost factors, relative to ed25519_verify cost
+            // From https://docs.rs/ed25519-zebra/2.2.0/ed25519_zebra/batch/index.html
+            ed25519_batch_verify_cost: 63 * GAS_PER_US / 2,
+            ed25519_batch_verify_one_pubkey_cost: 63 * GAS_PER_US / 4,
         }
     }
 }
@@ -406,7 +380,7 @@ mod tests {
     const INIT_AMOUNT: u128 = 500;
     const INIT_DENOM: &str = "TOKEN";
 
-    const TESTING_GAS_LIMIT: u64 = 500_000;
+    const TESTING_GAS_LIMIT: u64 = 500_000_000_000; // ~0.5ms
     const DEFAULT_QUERY_GAS_LIMIT: u64 = 300_000;
     const TESTING_MEMORY_LIMIT: Option<Size> = Some(Size::mebi(16));
 
diff --git a/packages/vm/src/imports.rs b/packages/vm/src/imports.rs
index e34d192c5..013f12c59 100644
--- a/packages/vm/src/imports.rs
+++ b/packages/vm/src/imports.rs
@@ -460,7 +460,7 @@ mod tests {
     const INIT_AMOUNT: u128 = 500;
     const INIT_DENOM: &str = "TOKEN";
 
-    const TESTING_GAS_LIMIT: u64 = 500_000;
+    const TESTING_GAS_LIMIT: u64 = 500_000_000_000; // ~0.5ms
     const TESTING_MEMORY_LIMIT: Option<Size> = Some(Size::mebi(16));
 
     const ECDSA_HASH_HEX: &str = "5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0";
diff --git a/packages/vm/src/instance.rs b/packages/vm/src/instance.rs
index 28f6d1664..3693e864e 100644
--- a/packages/vm/src/instance.rs
+++ b/packages/vm/src/instance.rs
@@ -673,7 +673,7 @@ mod tests {
 
     #[test]
     fn create_gas_report_works() {
-        const LIMIT: u64 = 7_000_000;
+        const LIMIT: u64 = 700_000_000_000;
         let mut instance = mock_instance_with_gas_limit(CONTRACT, LIMIT);
 
         let report1 = instance.create_gas_report();
@@ -691,7 +691,7 @@ mod tests {
 
         let report2 = instance.create_gas_report();
         assert_eq!(report2.used_externally, 73);
-        assert_eq!(report2.used_internally, 39202);
+        assert_eq!(report2.used_internally, 5863800110);
         assert_eq!(report2.limit, LIMIT);
         assert_eq!(
             report2.remaining,
@@ -890,7 +890,7 @@ mod singlepass_tests {
             .unwrap();
 
         let init_used = orig_gas - instance.get_gas_left();
-        assert_eq!(init_used, 39275);
+        assert_eq!(init_used, 5863800183);
     }
 
     #[test]
@@ -913,7 +913,7 @@ mod singlepass_tests {
             .unwrap();
 
         let execute_used = gas_before_execute - instance.get_gas_left();
-        assert_eq!(execute_used, 162233);
+        assert_eq!(execute_used, 8805403606);
     }
 
     #[test]
@@ -947,6 +947,6 @@ mod singlepass_tests {
         assert_eq!(answer.as_slice(), b"{\"verifier\":\"verifies\"}");
 
         let query_used = gas_before_query - instance.get_gas_left();
-        assert_eq!(query_used, 30646);
+        assert_eq!(query_used, 4598550006);
     }
 }
diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs
index 91272334e..4103d118d 100644
--- a/packages/vm/src/modules/file_system_cache.rs
+++ b/packages/vm/src/modules/file_system_cache.rs
@@ -114,7 +114,7 @@ mod tests {
     use wasmer_middlewares::metering::set_remaining_points;
 
     const TESTING_MEMORY_LIMIT: Option<Size> = Some(Size::mebi(16));
-    const TESTING_GAS_LIMIT: u64 = 5_000;
+    const TESTING_GAS_LIMIT: u64 = 500_000_000;
 
     #[test]
     fn file_system_cache_run() {
diff --git a/packages/vm/src/modules/in_memory_cache.rs b/packages/vm/src/modules/in_memory_cache.rs
index 9a0f95a56..9a14ac996 100644
--- a/packages/vm/src/modules/in_memory_cache.rs
+++ b/packages/vm/src/modules/in_memory_cache.rs
@@ -99,7 +99,7 @@ mod tests {
     use wasmer::{imports, Instance as WasmerInstance};
     use wasmer_middlewares::metering::set_remaining_points;
 
-    const TESTING_GAS_LIMIT: u64 = 5_000;
+    const TESTING_GAS_LIMIT: u64 = 500_000_000;
     // Based on `examples/module_size.sh`
     const TESTING_WASM_SIZE_FACTOR: usize = 18;
 
diff --git a/packages/vm/src/modules/pinned_memory_cache.rs b/packages/vm/src/modules/pinned_memory_cache.rs
index 24d397c19..61ef8cc74 100644
--- a/packages/vm/src/modules/pinned_memory_cache.rs
+++ b/packages/vm/src/modules/pinned_memory_cache.rs
@@ -63,7 +63,7 @@ mod tests {
     use wasmer::{imports, Instance as WasmerInstance};
     use wasmer_middlewares::metering::set_remaining_points;
 
-    const TESTING_GAS_LIMIT: u64 = 5_000;
+    const TESTING_GAS_LIMIT: u64 = 500_000_000;
 
     #[test]
     fn pinned_memory_cache_run() {
diff --git a/packages/vm/src/wasm_backend/store.rs b/packages/vm/src/wasm_backend/store.rs
index 25496bcf9..3c9f3ce83 100644
--- a/packages/vm/src/wasm_backend/store.rs
+++ b/packages/vm/src/wasm_backend/store.rs
@@ -22,10 +22,13 @@ use super::limiting_tunables::LimitingTunables;
 const MAX_WASM_MEMORY: usize = 4 * 1024 * 1024 * 1024;
 
 fn cost(_operator: &Operator) -> u64 {
-    // A flat fee in order to maintain roughly the same pricing as with Wasmer 0.17
-    // (https://github.com/wasmerio/wasmer/blob/0.17.1/lib/middleware-common/src/metering.rs#L43-L113).
-    // This should become more advanced soon: https://github.com/CosmWasm/cosmwasm/issues/670
-    1
+    // A flat fee for each operation
+    // The target is 1 Teragas per millisecond (see GAS.md).
+    //
+    // In https://github.com/CosmWasm/cosmwasm/pull/1042 a profiler is developed to
+    // identify runtime differences between different Wasm operation, but this is not yet
+    // precise enough to derive insights from it.
+    150_000
 }
 
 /// Created a store with the default compiler and the given memory limit (in bytes).


Test patch:
diff --git a/contracts/hackatom/tests/integration.rs b/contracts/hackatom/tests/integration.rs
index 7f13e484e..beea741e7 100644
--- a/contracts/hackatom/tests/integration.rs
+++ b/contracts/hackatom/tests/integration.rs
@@ -25,7 +25,8 @@ use cosmwasm_vm::{
     call_execute, from_slice,
     testing::{
         execute, instantiate, migrate, mock_env, mock_info, mock_instance,
-        mock_instance_with_balances, query, sudo, test_io, MOCK_CONTRACT_ADDR,
+        mock_instance_with_balances, mock_instance_with_gas_limit, query, sudo, test_io,
+        MOCK_CONTRACT_ADDR,
     },
     Storage, VmError,
 };
@@ -306,6 +307,35 @@ fn execute_release_fails_for_wrong_sender() {
     );
 }
 
+#[test]
+fn execute_argon2() {
+    let mut deps = mock_instance_with_gas_limit(WASM, 100_000_000_000_000);
+
+    let (instantiate_msg, creator) = make_init_msg();
+    let init_info = mock_info(creator.as_str(), &[]);
+    let init_res: Response =
+        instantiate(&mut deps, mock_env(), init_info, instantiate_msg).unwrap();
+    assert_eq!(0, init_res.messages.len());
+
+    let gas_before = deps.get_gas_left();
+    let _execute_res: Response = execute(
+        &mut deps,
+        mock_env(),
+        mock_info(creator.as_str(), &[]),
+        ExecuteMsg::Argon2 {
+            mem_cost: 256,
+            time_cost: 5,
+        },
+    )
+    .unwrap();
+    let gas_used = gas_before - deps.get_gas_left();
+    // Note: the exact gas usage depends on the Rust version used to compile Wasm,
+    // which we only fix when using rust-optimizer, not integration tests.
+    let expected = 23611119600000; // +/- 20%
+    assert!(gas_used > expected * 80 / 100, "Gas used: {}", gas_used);
+    assert!(gas_used < expected * 120 / 100, "Gas used: {}", gas_used);
+}
+
 #[test]
 fn execute_cpu_loop() {
     let mut deps = mock_instance(WASM, &[]);
@@ -403,9 +433,9 @@ fn execute_allocate_large_memory() {
     );
     let gas_used = gas_before - deps.get_gas_left();
     // Gas consumption is relatively small
-    // Note: the exact gas usage depends on the Rust version used to compile WASM,
-    // which we only fix when using cosmwasm-opt, not integration tests.
-    let expected = 27880; // +/- 20%
+    // Note: the exact gas usage depends on the Rust version used to compile Wasm,
+    // which we only fix when using rust-optimizer, not integration tests.
+    let expected = 4413600000; // +/- 20%
     assert!(gas_used > expected * 80 / 100, "Gas used: {}", gas_used);
     assert!(gas_used < expected * 120 / 100, "Gas used: {}", gas_used);
     let used = deps.memory_pages();
@@ -424,9 +454,9 @@ fn execute_allocate_large_memory() {
     assert_eq!(result.unwrap_err(), "Generic error: memory.grow failed");
     let gas_used = gas_before - deps.get_gas_left();
     // Gas consumption is relatively small
-    // Note: the exact gas usage depends on the Rust version used to compile WASM,
-    // which we only fix when using cosmwasm-opt, not integration tests.
-    let expected = 31076; // +/- 20%
+    // Note: the exact gas usage depends on the Rust version used to compile Wasm,
+    // which we only fix when using rust-optimizer, not integration tests.
+    let expected = 4859700000; // +/- 20%
     assert!(gas_used > expected * 80 / 100, "Gas used: {}", gas_used);
     assert!(gas_used < expected * 120 / 100, "Gas used: {}", gas_used);
     let used = deps.memory_pages();
diff --git a/contracts/queue/tests/integration.rs b/contracts/queue/tests/integration.rs
index d096ad938..7fa738054 100644
--- a/contracts/queue/tests/integration.rs
+++ b/contracts/queue/tests/integration.rs
@@ -34,7 +34,7 @@ use queue::msg::{InstantiateMsg, MigrateMsg};
 static WASM: &[u8] = include_bytes!("../target/wasm32-unknown-unknown/release/queue.wasm");
 
 fn create_contract() -> (Instance<MockApi, MockStorage, MockQuerier>, MessageInfo) {
-    let gas_limit = 500_000_000; // enough for many executions within one instance
+    let gas_limit = 1_000_000_000_000; // ~1ms, enough for many executions within one instance
     let mut deps = mock_instance_with_gas_limit(WASM, gas_limit);
     let creator = String::from("creator");
     let info = mock_info(&creator, &[]);
diff --git a/packages/vm/src/testing/instance.rs b/packages/vm/src/testing/instance.rs
index 93d4aa774..2bba244ee 100644
--- a/packages/vm/src/testing/instance.rs
+++ b/packages/vm/src/testing/instance.rs
@@ -17,7 +17,7 @@ use super::storage::MockStorage;
 /// This gas limit is used in integration tests and should be high enough to allow a reasonable
 /// number of contract executions and queries on one instance. For this reason it is significatly
 /// higher than the limit for a single execution that we have in the production setup.
-const DEFAULT_GAS_LIMIT: u64 = 5_000_000;
+const DEFAULT_GAS_LIMIT: u64 = 500_000_000_000; // ~0.5ms
 const DEFAULT_MEMORY_LIMIT: Option<Size> = Some(Size::mebi(16));
 const DEFAULT_PRINT_DEBUG: bool = true;