From 85a78bc8d84f26f4b08efa451399cc826b4dc51d Mon Sep 17 00:00:00 2001
From: Xiliang Chen <xlchen1291@gmail.com>
Date: Mon, 29 Jun 2020 13:44:10 +1200
Subject: [PATCH] add with_transaction_result (#217)

---
 utilities/Cargo.toml |  4 +++
 utilities/src/lib.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/utilities/Cargo.toml b/utilities/Cargo.toml
index 5d73bc2..47adf0d 100644
--- a/utilities/Cargo.toml
+++ b/utilities/Cargo.toml
@@ -10,11 +10,14 @@ edition = "2018"
 [dependencies]
 serde = { version = "1.0.111", optional = true }
 codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false }
+frame-support = { version = "2.0.0-rc4", default-features = false }
 sp-runtime = { version = "2.0.0-rc4", default-features = false }
 sp-std = { version = "2.0.0-rc4", default-features = false }
 
 [dev-dependencies]
 serde_json = "1.0.53"
+frame-system = { version = "2.0.0-rc4" }
+sp-io = { version = "2.0.0-rc4" }
 
 clear_on_drop = { version = "0.2.4", features = ["no_cc"] }	# https://github.com/paritytech/substrate/issues/4179
 
@@ -23,6 +26,7 @@ default = ["std"]
 std = [
 	"serde",
 	"codec/std",
+	"frame-support/std",
 	"sp-runtime/std",
 	"sp-std/std",
 ]
diff --git a/utilities/src/lib.rs b/utilities/src/lib.rs
index 2741e62..c7d523a 100644
--- a/utilities/src/lib.rs
+++ b/utilities/src/lib.rs
@@ -1,5 +1,82 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
+use frame_support::storage::{with_transaction, TransactionOutcome};
+use sp_runtime::DispatchError;
+use sp_std::result::Result;
+
 pub mod ordered_set;
 
 pub use ordered_set::OrderedSet;
+
+pub fn with_transaction_result<R>(f: impl FnOnce() -> Result<R, DispatchError>) -> Result<R, DispatchError> {
+	with_transaction(|| {
+		let res = f();
+		if res.is_ok() {
+			TransactionOutcome::Commit(res)
+		} else {
+			TransactionOutcome::Rollback(res)
+		}
+	})
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use frame_support::{assert_err, assert_ok, decl_module, decl_storage};
+	use sp_io::TestExternalities;
+	use sp_runtime::{DispatchError, DispatchResult};
+
+	pub trait Trait: frame_system::Trait {}
+
+	decl_module! {
+		pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
+	}
+
+	decl_storage! {
+		trait Store for Module<T: Trait> as StorageTransactions {
+			pub Value: u32;
+			pub Map: map hasher(twox_64_concat) String => u32;
+		}
+	}
+
+	#[test]
+	fn storage_transaction_basic_commit() {
+		TestExternalities::default().execute_with(|| {
+			assert_eq!(Value::get(), 0);
+			assert!(!Map::contains_key("val0"));
+
+			assert_ok!(with_transaction_result(|| -> DispatchResult {
+				Value::set(99);
+				Map::insert("val0", 99);
+				assert_eq!(Value::get(), 99);
+				assert_eq!(Map::get("val0"), 99);
+				Ok(())
+			}));
+
+			assert_eq!(Value::get(), 99);
+			assert_eq!(Map::get("val0"), 99);
+		});
+	}
+
+	#[test]
+	fn storage_transaction_basic_rollback() {
+		TestExternalities::default().execute_with(|| {
+			assert_eq!(Value::get(), 0);
+			assert_eq!(Map::get("val0"), 0);
+
+			assert_err!(
+				with_transaction_result(|| -> DispatchResult {
+					Value::set(99);
+					Map::insert("val0", 99);
+					assert_eq!(Value::get(), 99);
+					assert_eq!(Map::get("val0"), 99);
+					Err("test".into())
+				}),
+				DispatchError::Other("test")
+			);
+
+			assert_eq!(Value::get(), 0);
+			assert_eq!(Map::get("val0"), 0);
+		});
+	}
+}
-- 
GitLab