Repository: oasisprotocol/oasis-sdk
Pull request #150 (2021-05-27 23:51:11)

combined static dispatch for methods and full dispatcher in methods
from #147 and #148



codecov[bot]: # [Codecov](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol) Report
> Merging [#150](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol) (5760c2d) into [main](https://codecov.io/gh/oasisprotocol/oasis-sdk/commit/5af8e65c2e1d38aa04580ea089b67094648396a7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol) (5af8e65) will **decrease** coverage by `2.18%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/graphs/tree.svg?width=650&height=150&src=pr&token=uscfoYjSZn&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol)](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol)

```diff
@@            Coverage Diff             @@
##             main     #150      +/-   ##
==========================================
- Coverage   70.04%   67.85%   -2.19%     
==========================================
  Files          54        8      -46     
  Lines        2944      252    -2692     
==========================================
- Hits         2062      171    -1891     
+ Misses        862       61     -801     
  Partials       20       20              
```


| [Impacted Files](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol) | Coverage Δ | |
|---|---|---|
| [runtime-sdk/src/modules/rewards/types.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL21vZHVsZXMvcmV3YXJkcy90eXBlcy5ycw==) | | |
| [runtime-sdk-macros/src/error\_derive.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGstbWFjcm9zL3NyYy9lcnJvcl9kZXJpdmUucnM=) | | |
| [runtime-sdk/src/modules/consensus/test.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL21vZHVsZXMvY29uc2Vuc3VzL3Rlc3QucnM=) | | |
| [runtime-sdk/src/crypto/signature/secp256k1.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL2NyeXB0by9zaWduYXR1cmUvc2VjcDI1NmsxLnJz) | | |
| [tests/runtimes/simple-keyvalue/src/main.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-dGVzdHMvcnVudGltZXMvc2ltcGxlLWtleXZhbHVlL3NyYy9tYWluLnJz) | | |
| [runtime-sdk/src/crypto/signature/context.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL2NyeXB0by9zaWduYXR1cmUvY29udGV4dC5ycw==) | | |
| [runtime-sdk/src/event.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL2V2ZW50LnJz) | | |
| [runtime-sdk/src/storage/overlay.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL3N0b3JhZ2Uvb3ZlcmxheS5ycw==) | | |
| [runtime-sdk/src/crypto/signature/mod.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGsvc3JjL2NyeXB0by9zaWduYXR1cmUvbW9kLnJz) | | |
| [runtime-sdk-macros/src/lib.rs](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol#diff-cnVudGltZS1zZGstbWFjcm9zL3NyYy9saWIucnM=) | | |
| ... and [16 more](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol). Last update [5af8e65...5760c2d](https://codecov.io/gh/oasisprotocol/oasis-sdk/pull/150?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oasisprotocol).

pro-wh: changing target branch to main for CI
pro-wh: things getting a little verbose with other branches rebasing
kostko: Rebase?
pro-wh: the code is very different now, and there'd be too much rewriting

On Thu, Jun 3, 2021, 1:24 AM Jernej Kos ***@***.***> wrote:

> Rebase?
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/oasisprotocol/oasis-sdk/pull/150#issuecomment-853685006>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AJDVILSDTNKTJQHYDI6EXSTTQ4345ANCNFSM45VK75GA>
> .
>

-- 
Disclaimer: This e-mail and any attachments may contain confidential 
information. If you are not the intended recipient, any disclosure, 
copying, distribution or use of any information contained herein is 
strictly prohibited. If you have received this transmission in error, 
please immediately notify the sender and destroy the original transmission 
and any attachments without reading or saving.

kostko: So this should be closed? Some things like the gas helpers seem worth extracting though.
wh0: no, this is the latest proposed version of authentication gas accounting
kostko: So this has a few versions of the same commits which looks very weird. Also it is out of date with main now that #148 has been merged.
pro-wh: I'll rebase this after all
pro-wh: reconstructed. diff from previous (archived in #178)

```diff
diff --git a/runtime-sdk/src/modules/core/mod.rs b/runtime-sdk/src/modules/core/mod.rs
index 968c44c..4324da0 100644
--- a/runtime-sdk/src/modules/core/mod.rs
+++ b/runtime-sdk/src/modules/core/mod.rs
@@ -3,12 +3,11 @@ use serde::{Deserialize, Serialize};
 use thiserror::Error;
 
 use crate::{
-    context::{Context, TxContext},
+    context::{BatchContext, Context, TxContext},
     core::common::cbor,
     dispatcher, error,
     module::{self, Module as _},
     types::transaction::{self, AddressSpec, AuthProof, Call, UnverifiedTransaction},
-    BatchContext,
 };
 
 #[cfg(test)]
```

Patch:
diff --git a/client-sdk/go/modules/core/core.go b/client-sdk/go/modules/core/core.go
new file mode 100644
index 0000000000..abf958b45e
--- /dev/null
+++ b/client-sdk/go/modules/core/core.go
@@ -0,0 +1,34 @@
+package core
+
+import (
+	"context"
+
+	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/client"
+	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
+)
+
+const (
+	methodEstimateGas = "core.EstimateGas"
+)
+
+type V1 interface {
+	EstimateGas(ctx context.Context, round uint64, tx *types.Transaction) (uint64, error)
+}
+
+type v1 struct {
+	rc client.RuntimeClient
+}
+
+// Implements V1.
+func (a *v1) EstimateGas(ctx context.Context, round uint64, tx *types.Transaction) (uint64, error) {
+	var gas uint64
+	err := a.rc.Query(ctx, round, methodEstimateGas, tx, &gas)
+	if err != nil {
+		return 0, err
+	}
+	return gas, nil
+}
+
+func NewV1(rc client.RuntimeClient) V1 {
+	return &v1{rc: rc}
+}
diff --git a/runtime-sdk/src/dispatcher.rs b/runtime-sdk/src/dispatcher.rs
index ceaeaa9596..28664ae604 100644
--- a/runtime-sdk/src/dispatcher.rs
+++ b/runtime-sdk/src/dispatcher.rs
@@ -22,7 +22,7 @@ use oasis_core_runtime::{
 };
 
 use crate::{
-    context::{BatchContext, Context, RuntimeBatchContext},
+    context::{BatchContext, Context, RuntimeBatchContext, TxContext},
     error::{Error as _, RuntimeError},
     module::{self, AuthHandler, BlockHandler, MethodHandler},
     modules,
@@ -97,6 +97,24 @@ impl<R: Runtime> Dispatcher<R> {
             .map_err(|_| modules::core::Error::MalformedTransaction)
     }
 
+    /// Run the dispatch steps inside a transaction context. This includes the before call hooks
+    /// and the call itself.
+    pub fn dispatch_tx_call<C: TxContext>(
+        ctx: &mut C,
+        call: types::transaction::Call,
+    ) -> types::transaction::CallResult {
+        if let Err(e) = R::Modules::before_handle_call(ctx, &call) {
+            return e.to_call_result();
+        }
+
+        match R::Modules::dispatch_call(ctx, &call.method, call.body) {
+            module::DispatchResult::Handled(result) => result,
+            module::DispatchResult::Unhandled(_) => {
+                modules::core::Error::InvalidMethod.to_call_result()
+            }
+        }
+    }
+
     /// Dispatch a runtime transaction in the given context.
     pub fn dispatch_tx<C: BatchContext>(
         ctx: &mut C,
@@ -108,15 +126,10 @@ impl<R: Runtime> Dispatcher<R> {
         }
 
         let (result, messages) = ctx.with_tx(tx, |mut ctx, call| {
-            let result = match R::Modules::dispatch_call(&mut ctx, &call.method, call.body) {
-                module::DispatchResult::Handled(result) => result,
-                module::DispatchResult::Unhandled(_) => {
-                    return (
-                        modules::core::Error::InvalidMethod.to_call_result().into(),
-                        Vec::new(),
-                    )
-                }
-            };
+            let result = Self::dispatch_tx_call(&mut ctx, call);
+            if !result.is_success() {
+                return (result.into(), Vec::new());
+            }
 
             // Commit store and return emitted tags and messages.
             let (tags, messages) = ctx.commit();
diff --git a/runtime-sdk/src/module.rs b/runtime-sdk/src/module.rs
index 5cff8172b0..40d63b6379 100644
--- a/runtime-sdk/src/module.rs
+++ b/runtime-sdk/src/module.rs
@@ -4,15 +4,14 @@ use std::fmt::Debug;
 use impl_trait_for_tuples::impl_for_tuples;
 use serde::{de::DeserializeOwned, Serialize};
 
-use oasis_core_runtime::common::cbor;
-
 use crate::{
     context::{Context, TxContext},
+    core::common::cbor,
     error, event, modules, storage,
     storage::Store,
     types::{
         message::MessageResult,
-        transaction::{CallResult, Transaction, UnverifiedTransaction},
+        transaction::{Call, CallResult, Transaction, UnverifiedTransaction},
     },
 };
 
@@ -139,6 +138,15 @@ pub trait AuthHandler {
         // Default implementation doesn't do any checks.
         Ok(())
     }
+
+    /// Perform any action after authentication, within the transaction context.
+    fn before_handle_call<C: TxContext>(
+        _ctx: &mut C,
+        _call: &Call,
+    ) -> Result<(), modules::core::Error> {
+        // Default implementation doesn't do anything.
+        Ok(())
+    }
 }
 
 #[impl_for_tuples(30)]
@@ -158,6 +166,14 @@ impl AuthHandler for Tuple {
         for_tuples!( #( Tuple::authenticate_tx(ctx, tx)?; )* );
         Ok(())
     }
+
+    fn before_handle_call<C: TxContext>(
+        ctx: &mut C,
+        call: &Call,
+    ) -> Result<(), modules::core::Error> {
+        for_tuples!( #( Tuple::before_handle_call(ctx, call)?; )* );
+        Ok(())
+    }
 }
 
 /// Migration handler.
diff --git a/runtime-sdk/src/modules/core/mod.rs b/runtime-sdk/src/modules/core/mod.rs
index 358e1a69a4..4324da0f6a 100644
--- a/runtime-sdk/src/modules/core/mod.rs
+++ b/runtime-sdk/src/modules/core/mod.rs
@@ -2,13 +2,12 @@
 use serde::{Deserialize, Serialize};
 use thiserror::Error;
 
-use oasis_core_runtime::common::cbor;
-
 use crate::{
-    context::{Context, TxContext},
+    context::{BatchContext, Context, TxContext},
+    core::common::cbor,
     dispatcher, error,
     module::{self, Module as _},
-    types::transaction::{self, AuthProof, UnverifiedTransaction},
+    types::transaction::{self, AddressSpec, AuthProof, Call, UnverifiedTransaction},
 };
 
 #[cfg(test)]
@@ -82,6 +81,16 @@ pub enum Error {
     MultisigTooManySigners,
 }
 
+/// Gas costs.
+#[derive(Clone, Debug, Default, Serialize, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct GasCosts {
+    #[serde(rename = "auth_signature")]
+    pub auth_signature: u64,
+    #[serde(rename = "auth_multisig_signer")]
+    pub auth_multisig_signer: u64,
+}
+
 /// Parameters for the core module.
 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
 #[serde(deny_unknown_fields)]
@@ -92,6 +101,8 @@ pub struct Parameters {
     pub max_tx_signers: u32,
     #[serde(rename = "max_multisig_signers")]
     pub max_multisig_signers: u32,
+    #[serde(rename = "gas_costs")]
+    pub gas_costs: GasCosts,
 }
 
 impl module::Parameters for Parameters {
@@ -190,11 +201,13 @@ impl Module {
         ctx: &mut C,
         args: transaction::Transaction,
     ) -> Result<u64, Error> {
-        ctx.with_simulation(|mut ctx| {
-            dispatcher::Dispatcher::<C::Runtime>::dispatch_tx(&mut ctx, args).ok();
-            // Warning: we don't report success or failure. If the call fails, we still report
-            // how much gas it uses while it fails.
-            Ok(*ctx.value::<u64>(CONTEXT_KEY_GAS_USED).or_default())
+        ctx.with_simulation(|mut sim_ctx| {
+            sim_ctx.with_tx(args, |mut tx_ctx, call| {
+                dispatcher::Dispatcher::<C::Runtime>::dispatch_tx_call(&mut tx_ctx, call);
+                // Warning: we don't report success or failure. If the call fails, we still report
+                // how much gas it uses while it fails.
+                Ok(*tx_ctx.value::<u64>(CONTEXT_KEY_GAS_USED).or_default())
+            })
         })
     }
 }
@@ -224,6 +237,34 @@ impl module::AuthHandler for Module {
         }
         Ok(())
     }
+
+    fn before_handle_call<C: TxContext>(ctx: &mut C, _call: &Call) -> Result<(), Error> {
+        let mut num_signature: u64 = 0;
+        let mut num_multisig_signer: u64 = 0;
+        for si in &ctx.tx_auth_info().signer_info {
+            match &si.address_spec {
+                AddressSpec::Signature(_) => {
+                    num_signature = num_signature.checked_add(1).ok_or(Error::GasOverflow)?;
+                }
+                AddressSpec::Multisig(config) => {
+                    num_multisig_signer = num_multisig_signer
+                        .checked_add(config.signers.len() as u64)
+                        .ok_or(Error::GasOverflow)?;
+                }
+            }
+        }
+        let params = Self::params(ctx.runtime_state());
+        let total = (|| {
+            let signature_cost = num_signature.checked_mul(params.gas_costs.auth_signature)?;
+            let multisig_signer_cost =
+                num_multisig_signer.checked_mul(params.gas_costs.auth_multisig_signer)?;
+            let sum = signature_cost.checked_add(multisig_signer_cost)?;
+            Some(sum)
+        })()
+        .ok_or(Error::GasOverflow)?;
+        Self::use_tx_gas(ctx, total)?;
+        Ok(())
+    }
 }
 
 impl module::MigrationHandler for Module {
diff --git a/runtime-sdk/src/types/transaction.rs b/runtime-sdk/src/types/transaction.rs
index a10f8992f2..fa85eef498 100644
--- a/runtime-sdk/src/types/transaction.rs
+++ b/runtime-sdk/src/types/transaction.rs
@@ -190,6 +190,14 @@ impl SignerInfo {
             nonce,
         }
     }
+
+    /// Create a new signer info from a multisig configuration and a nonce.
+    pub fn new_multisig(config: multisig::Config, nonce: u64) -> Self {
+        Self {
+            address_spec: AddressSpec::Multisig(config),
+            nonce,
+        }
+    }
 }
 
 /// Call result.


Test patch:
diff --git a/runtime-sdk/src/modules/core/test.rs b/runtime-sdk/src/modules/core/test.rs
index f081114855..e1c85a7ff3 100644
--- a/runtime-sdk/src/modules/core/test.rs
+++ b/runtime-sdk/src/modules/core/test.rs
@@ -1,6 +1,7 @@
 use crate::{
     context::{BatchContext, Context, Mode, TxContext},
     core::common::{cbor, version::Version},
+    crypto::multisig,
     module,
     module::{AuthHandler as _, Module as _},
     runtime::Runtime,
@@ -22,6 +23,7 @@ fn test_use_gas() {
             max_batch_gas: BLOCK_MAX_GAS,
             max_tx_signers: 8,
             max_multisig_signers: 8,
+            gas_costs: Default::default(),
         },
     );
 
@@ -66,7 +68,7 @@ fn test_use_gas() {
 struct GasWasterModule;
 
 impl GasWasterModule {
-    const MAX_GAS: u64 = 100;
+    const CALL_GAS: u64 = 100;
     const METHOD_WASTE_GAS: &'static str = "test.WasteGas";
 }
 
@@ -85,7 +87,7 @@ impl module::MethodHandler for GasWasterModule {
     ) -> module::DispatchResult<cbor::Value, transaction::CallResult> {
         match method {
             Self::METHOD_WASTE_GAS => {
-                Core::use_tx_gas(ctx, Self::MAX_GAS).expect("use_gas should succeed");
+                Core::use_tx_gas(ctx, Self::CALL_GAS).expect("use_gas should succeed");
                 module::DispatchResult::Handled(transaction::CallResult::Ok(cbor::Value::Null))
             }
             _ => module::DispatchResult::Unhandled(body),
@@ -102,6 +104,11 @@ impl module::MigrationHandler for GasWasterModule {
 // Runtime that knows how to waste gas.
 struct GasWasterRuntime;
 
+impl GasWasterRuntime {
+    const AUTH_SIGNATURE_GAS: u64 = 1;
+    const AUTH_MULTISIG_GAS: u64 = 10;
+}
+
 impl Runtime for GasWasterRuntime {
     const VERSION: Version = Version::new(0, 0, 0);
 
@@ -114,6 +121,10 @@ impl Runtime for GasWasterRuntime {
                     max_batch_gas: u64::MAX,
                     max_tx_signers: 8,
                     max_multisig_signers: 8,
+                    gas_costs: super::GasCosts {
+                        auth_signature: Self::AUTH_SIGNATURE_GAS,
+                        auth_multisig_signer: Self::AUTH_MULTISIG_GAS,
+                    },
                 },
             },
             (),
@@ -135,7 +146,19 @@ fn test_query_estimate_gas() {
             body: cbor::Value::Null,
         },
         auth_info: transaction::AuthInfo {
-            signer_info: vec![transaction::SignerInfo::new(keys::alice::pk(), 0)],
+            signer_info: vec![
+                transaction::SignerInfo::new(keys::alice::pk(), 0),
+                transaction::SignerInfo::new_multisig(
+                    multisig::Config {
+                        signers: vec![multisig::Signer {
+                            public_key: keys::bob::pk(),
+                            weight: 1,
+                        }],
+                        threshold: 1,
+                    },
+                    0,
+                ),
+            ],
             fee: transaction::Fee {
                 amount: token::BaseUnits::new(0.into(), token::Denomination::NATIVE),
                 gas: u64::MAX,
@@ -144,11 +167,10 @@ fn test_query_estimate_gas() {
     };
 
     let est = Core::query_estimate_gas(&mut ctx, tx).expect("query_estimate_gas should succeed");
-    assert_eq!(
-        est,
-        GasWasterModule::MAX_GAS,
-        "estimated gas should be correct"
-    );
+    let reference_gas = GasWasterRuntime::AUTH_SIGNATURE_GAS
+        + GasWasterRuntime::AUTH_MULTISIG_GAS
+        + GasWasterModule::CALL_GAS;
+    assert_eq!(est, reference_gas, "estimated gas should be correct");
 }
 
 #[test]
@@ -161,6 +183,7 @@ fn test_approve_unverified_tx() {
             max_batch_gas: u64::MAX,
             max_tx_signers: 2,
             max_multisig_signers: 2,
+            gas_costs: Default::default(),
         },
     );
     let dummy_bytes = b"you look, you die".to_vec();
diff --git a/tests/e2e/simplekvtest.go b/tests/e2e/simplekvtest.go
index 365b0132c7..9b0e10620d 100644
--- a/tests/e2e/simplekvtest.go
+++ b/tests/e2e/simplekvtest.go
@@ -20,6 +20,7 @@ import (
 	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/client"
 	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature"
 	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/accounts"
+	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/core"
 	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rewards"
 	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/testing"
 	"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
@@ -31,7 +32,7 @@ import (
 const EventWaitTimeout = 20 * time.Second
 
 // defaultGasAmount is the default amount of gas to specify.
-const defaultGasAmount = 100
+const defaultGasAmount = 200
 
 // The kvKey type must match the Key type from the simple-keyvalue runtime
 // in ../runtimes/simple-keyvalue/src/keyvalue/types.rs.
@@ -91,6 +92,13 @@ func kvInsert(rtc client.RuntimeClient, signer signature.Signer, key, value []by
 		Value: value,
 	})
 	tx.AppendAuthSignature(signer.Public(), nonce)
+
+	gas, err := core.NewV1(rtc).EstimateGas(ctx, client.RoundLatest, tx)
+	if err != nil {
+		return err
+	}
+	tx.AuthInfo.Fee.Gas = gas
+
 	stx := tx.PrepareForSigning()
 	if err = stx.AppendSign(chainCtx, signer); err != nil {
 		return err
@@ -121,6 +129,13 @@ func kvRemove(rtc client.RuntimeClient, signer signature.Signer, key []byte) err
 		Key: key,
 	})
 	tx.AppendAuthSignature(signer.Public(), nonce)
+
+	gas, err := core.NewV1(rtc).EstimateGas(ctx, client.RoundLatest, tx)
+	if err != nil {
+		return err
+	}
+	tx.AuthInfo.Fee.Gas = gas
+
 	stx := tx.PrepareForSigning()
 	if err = stx.AppendSign(chainCtx, signer); err != nil {
 		return err
@@ -516,7 +531,7 @@ func KVMultisigTest(sc *RuntimeScenario, log *logging.Logger, conn *grpc.ClientC
 	}
 
 	tx := types.NewTransaction(&types.Fee{
-		Gas: 200,
+		Gas: 300,
 	}, "keyvalue.Insert", kvKeyValue{
 		Key:   []byte("from-KVMultisigTest"),
 		Value: []byte("hi"),
diff --git a/tests/runtimes/simple-consensus/src/lib.rs b/tests/runtimes/simple-consensus/src/lib.rs
index afb691e447..8ea47ae077 100644
--- a/tests/runtimes/simple-consensus/src/lib.rs
+++ b/tests/runtimes/simple-consensus/src/lib.rs
@@ -18,12 +18,9 @@ impl sdk::Runtime for Runtime {
             Default::default(),
             modules::consensus_accounts::Genesis {
                 parameters: modules::consensus_accounts::Parameters {
-                    gas_costs: modules::consensus_accounts::GasCosts {
-                        // These are free, in order to simplify testing. We do test gas accounting
-                        // with other methods elsewhere though.
-                        tx_deposit: 0,
-                        tx_withdraw: 0,
-                    },
+                    // These are free, in order to simplify testing. We do test gas accounting
+                    // with other methods elsewhere though.
+                    gas_costs: Default::default(),
                 },
             },
             modules::core::Genesis {
@@ -31,6 +28,8 @@ impl sdk::Runtime for Runtime {
                     max_batch_gas: 10_000,
                     max_tx_signers: 8,
                     max_multisig_signers: 8,
+                    // These are free, in order to simplify testing.
+                    gas_costs: Default::default(),
                 },
             },
         )
diff --git a/tests/runtimes/simple-keyvalue/src/lib.rs b/tests/runtimes/simple-keyvalue/src/lib.rs
index 88f8e6c46e..01af78f633 100644
--- a/tests/runtimes/simple-keyvalue/src/lib.rs
+++ b/tests/runtimes/simple-keyvalue/src/lib.rs
@@ -99,6 +99,10 @@ impl sdk::Runtime for Runtime {
                     max_batch_gas: 10_000,
                     max_tx_signers: 8,
                     max_multisig_signers: 8,
+                    gas_costs: modules::core::GasCosts {
+                        auth_signature: 10,
+                        auth_multisig_signer: 10,
+                    },
                 },
             },
         )
diff --git a/tests/runtimes/simple-keyvalue/src/test.rs b/tests/runtimes/simple-keyvalue/src/test.rs
index d878dbe8a9..512132ce30 100644
--- a/tests/runtimes/simple-keyvalue/src/test.rs
+++ b/tests/runtimes/simple-keyvalue/src/test.rs
@@ -16,6 +16,7 @@ fn test_impl_for_tuple() {
             max_batch_gas: u64::MAX,
             max_tx_signers: 1,
             max_multisig_signers: 1,
+            gas_costs: Default::default(),
         },
     );
     let dummy_bytes = b"you look, you die".to_vec();