From 77d0c065d349940854b8a2bf87430cc88ce715f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= <tomusdrw@users.noreply.github.com>
Date: Wed, 27 Nov 2019 19:23:55 +0100
Subject: [PATCH] Hard-cap the execution time of custom contract calls. (#4226)

* Reject call requests that allocate too high gas limit.

* Lower to 5x
---
 substrate/frame/contracts/rpc/src/lib.rs | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/contracts/rpc/src/lib.rs b/substrate/frame/contracts/rpc/src/lib.rs
index e330e9efcc0..6f357f53b85 100644
--- a/substrate/frame/contracts/rpc/src/lib.rs
+++ b/substrate/frame/contracts/rpc/src/lib.rs
@@ -39,7 +39,16 @@ const RUNTIME_ERROR: i64 = 1;
 const CONTRACT_DOESNT_EXIST: i64 = 2;
 const CONTRACT_IS_A_TOMBSTONE: i64 = 3;
 
-// A private newtype for converting `GetStorageError` into an RPC error.
+/// A rough estimate of how much gas a decent hardware consumes per second,
+/// using native execution.
+/// This value is used to set the upper bound for maximal contract calls to
+/// prevent blocking the RPC for too long.
+///
+/// Based on W3F research spreadsheet:
+/// https://docs.google.com/spreadsheets/d/1h0RqncdqiWI4KgxO0z9JIpZEJESXjX_ZCK6LFX6veDo/view
+const GAS_PER_SECOND: u64 = 1_000_000_000;
+
+/// A private newtype for converting `GetStorageError` into an RPC error.
 struct GetStorageError(runtime_api::GetStorageError);
 impl From<GetStorageError> for Error {
 	fn from(e: GetStorageError) -> Error {
@@ -148,6 +157,19 @@ where
 			data: None,
 		})?;
 
+		let max_gas_limit = 5 * GAS_PER_SECOND;
+		if gas_limit > max_gas_limit {
+			return Err(Error {
+				code: ErrorCode::InvalidParams,
+				message: format!(
+					"Requested gas limit is greater than maximum allowed: {} > {}",
+					gas_limit,
+					max_gas_limit
+				),
+				data: None,
+			});
+		}
+
 		let exec_result = api
 			.call(&at, origin, dest, value, gas_limit, input_data.to_vec())
 			.map_err(|e| Error {
-- 
GitLab