Преглед изворни кода

runtime: blog: add editable/non-editable reply options

conectado пре 3 година
родитељ
комит
bc8cc4fdb1

+ 2 - 3
runtime-modules/blog/Cargo.toml

@@ -12,23 +12,22 @@ frame-system = { package = 'frame-system', default-features = false, git = 'http
 codec = { package = 'parity-scale-codec', version = '1.0.0', default-features = false, features = ['derive'] }
 sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 common = { package = 'pallet-common', default-features = false, path = '../common'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
 #Benchmark dependencies
 frame-benchmarking = { package = 'frame-benchmarking', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca', optional = true}
 membership = { package = 'pallet-membership', default-features = false, path = '../membership', optional = true}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca', optional = true}
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 membership = { package = 'pallet-membership', default-features = false, path = '../membership' }
 staking-handler = { package = 'pallet-staking-handler', default-features = false, path = '../staking-handler' }
 pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
 [features]
 default = ['std']
-runtime-benchmarks = ['frame-benchmarking', 'membership', 'balances']
+runtime-benchmarks = ['frame-benchmarking', 'membership']
 std = [
 	'codec/std',
 	'sp-std/std',

+ 19 - 8
runtime-modules/blog/src/benchmarking.rs

@@ -113,12 +113,18 @@ fn generate_reply<T: Trait<I>, I: Instance>(
         post_id,
         None,
         vec![0u8],
+        true,
     )
     .unwrap();
 
     assert_eq!(
         Blog::<T, I>::reply_by_id(post_id, T::ReplyId::zero()),
-        Reply::<T, I>::new(vec![0u8], participant_id, ParentId::Post(post_id))
+        Reply::<T, I>::new(
+            vec![0u8],
+            participant_id,
+            ParentId::Post(post_id),
+            T::ReplyDeposit::get()
+        )
     );
 
     T::ReplyId::zero()
@@ -194,7 +200,7 @@ benchmarks_instance! {
         let (account_id, participant_id) = member_funded_account::<T, I>("caller", 0);
         let origin = RawOrigin::Signed(account_id);
         let text = vec![0u8; t.try_into().unwrap()];
-    }: create_reply(origin.clone(), participant_id, post_id, None, text.clone())
+    }: create_reply(origin.clone(), participant_id, post_id, None, text.clone(), true)
     verify {
         let mut expected_post = Post::<T, I>::new(&vec![0u8], &vec![0u8]);
         expected_post.increment_replies_counter();
@@ -204,7 +210,8 @@ benchmarks_instance! {
             Reply::<T, I>::new(
                 text.clone(),
                 participant_id,
-                ParentId::Post(post_id)
+                ParentId::Post(post_id),
+                T::ReplyDeposit::get(),
             )
         );
 
@@ -213,7 +220,8 @@ benchmarks_instance! {
                 participant_id,
                 post_id,
                 Zero::zero(),
-                text
+                text,
+                true
             ).into()
         );
     }
@@ -229,7 +237,7 @@ benchmarks_instance! {
         expected_post.increment_replies_counter();
         assert_eq!(Blog::<T, I>::post_by_id(post_id), expected_post);
         let text = vec![0u8; t.try_into().unwrap()];
-    }: create_reply(origin.clone(), participant_id, post_id, Some(reply_id), text.clone())
+    }: create_reply(origin.clone(), participant_id, post_id, Some(reply_id), text.clone(), true)
     verify {
         expected_post.increment_replies_counter();
         assert_eq!(Blog::<T, I>::post_by_id(post_id), expected_post);
@@ -238,7 +246,8 @@ benchmarks_instance! {
             Reply::<T, I>::new(
                 text.clone(),
                 participant_id,
-                ParentId::Reply(reply_id)
+                ParentId::Reply(reply_id),
+                T::ReplyDeposit::get(),
             )
         );
 
@@ -248,7 +257,8 @@ benchmarks_instance! {
                 post_id,
                 reply_id,
                 One::one(),
-                text
+                text,
+                true,
             ).into()
         );
     }
@@ -272,7 +282,8 @@ benchmarks_instance! {
             Reply::<T, I>::new(
                 updated_text.clone(),
                 participant_id,
-                ParentId::Post(post_id)
+                ParentId::Post(post_id),
+                T::ReplyDeposit::get(),
             )
         );
 

+ 3 - 3
runtime-modules/blog/src/errors.rs

@@ -25,10 +25,10 @@ decl_error! {
         /// Number of posts exceeds limits.
         PostLimitReached,
 
-        /// Number of maximum replies reached
-        RepliesLimitReached,
-
         /// Reaction doesn't exists
         InvalidReactionIndex,
+
+        /// Insuficient balance for reply creation
+        InsufficientBalanceForReply
     }
 }

+ 137 - 42
runtime-modules/blog/src/lib.rs

@@ -38,13 +38,17 @@ use codec::{Codec, Decode, Encode};
 use common::membership::MemberOriginValidator;
 use errors::Error;
 pub use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::{Currency, ExistenceRequirement};
 use frame_support::weights::Weight;
 use frame_support::{
     decl_event, decl_module, decl_storage, ensure, traits::Get, Parameter, StorageDoubleMap,
 };
 use sp_arithmetic::traits::{BaseArithmetic, One};
-use sp_runtime::traits::{Hash, MaybeSerialize, Member};
 use sp_runtime::SaturatedConversion;
+use sp_runtime::{
+    traits::{AccountIdConversion, Hash, MaybeSerialize, Member},
+    ModuleId,
+};
 use sp_std::prelude::*;
 
 mod benchmarking;
@@ -61,6 +65,11 @@ pub type PostId = u64;
 /// Blogger participant ID alias for the member of the system.
 pub type ParticipantId<T> = common::MemberId<T>;
 
+/// Balance alias for `balances` module.
+pub type BalanceOf<T> = <T as balances::Trait>::Balance;
+
+type Balances<T> = balances::Module<T>;
+
 /// blog WeightInfo.
 /// Note: This was auto generated through the benchmark CLI using the `--weight-trait` flag
 pub trait WeightInfo {
@@ -73,9 +82,11 @@ pub trait WeightInfo {
     fn edit_reply(t: u32) -> Weight;
 }
 
+type BlogWeightInfo<T, I> = <T as Trait<I>>::WeightInfo;
+
 // The pallet's configuration trait.
 pub trait Trait<I: Instance = DefaultInstance>:
-    frame_system::Trait + common::membership::Trait
+    frame_system::Trait + common::membership::Trait + balances::Trait
 {
     /// Origin from which participant must come.
     type ParticipantEnsureOrigin: MemberOriginValidator<
@@ -90,9 +101,6 @@ pub trait Trait<I: Instance = DefaultInstance>:
     /// The maximum number of posts in a blog.
     type PostsMaxNumber: Get<MaxNumber>;
 
-    /// The maximum number of replies to a post.
-    type RepliesMaxNumber: Get<MaxNumber>;
-
     /// Type of identifier for replies.
     type ReplyId: Parameter
         + Member
@@ -107,6 +115,12 @@ pub trait Trait<I: Instance = DefaultInstance>:
 
     /// Weight information for extrinsics in this pallet.
     type WeightInfo: WeightInfo;
+
+    /// Deposit needed to create a reply
+    type ReplyDeposit: Get<Self::Balance>;
+
+    /// The forum module Id, used to derive the account Id to hold the thread bounty
+    type ModuleId: Get<ModuleId>;
 }
 
 /// Type, representing blog related post structure
@@ -233,6 +247,8 @@ pub struct Reply<T: Trait<I>, I: Instance> {
     owner: ParticipantId<T>,
     /// Reply`s parent id
     parent_id: ParentId<T::ReplyId, PostId>,
+    /// Pay off by deleting post
+    cleanup_pay_off: T::Balance,
 }
 
 // Note: we derive it by hand because the derive isn't working because of a Rust problem
@@ -270,6 +286,7 @@ impl<T: Trait<I>, I: Instance> Default for Reply<T, I> {
             text_hash: Default::default(),
             owner: Default::default(),
             parent_id: Default::default(),
+            cleanup_pay_off: Default::default(),
         }
     }
 }
@@ -280,11 +297,13 @@ impl<T: Trait<I>, I: Instance> Reply<T, I> {
         text: Vec<u8>,
         owner: ParticipantId<T>,
         parent_id: ParentId<T::ReplyId, PostId>,
+        cleanup_pay_off: T::Balance,
     ) -> Self {
         Self {
             text_hash: T::Hashing::hash(&text),
             owner,
             parent_id,
+            cleanup_pay_off,
         }
     }
 
@@ -338,7 +357,7 @@ decl_module! {
         /// - DB:
         ///    - O(1) doesn't depend on the state or parameters
         /// # </weight>
-        #[weight = T::WeightInfo::create_post(
+        #[weight = BlogWeightInfo::<T, I>::create_post(
                 title.len().saturated_into(),
                 body.len().saturated_into()
             )]
@@ -377,7 +396,7 @@ decl_module! {
         /// - DB:
         ///    - O(1) doesn't depend on the state or parameters
         /// # </weight>
-        #[weight = T::WeightInfo::lock_post()]
+        #[weight = BlogWeightInfo::<T, I>::lock_post()]
         pub fn lock_post(origin, post_id: PostId) -> DispatchResult {
 
             // Ensure blog -> owner relation exists
@@ -408,7 +427,7 @@ decl_module! {
         /// - DB:
         ///    - O(1) doesn't depend on the state or parameters
         /// # </weight>
-        #[weight = T::WeightInfo::unlock_post()]
+        #[weight = BlogWeightInfo::<T, I>::unlock_post()]
         pub fn unlock_post(origin, post_id: PostId) -> DispatchResult {
 
             // Ensure blog -> owner relation exists
@@ -486,9 +505,10 @@ decl_module! {
             participant_id: ParticipantId<T>,
             post_id: PostId,
             reply_id: Option<T::ReplyId>,
-            text: Vec<u8>
+            text: Vec<u8>,
+            editable: bool,
         ) -> DispatchResult {
-            Self::ensure_valid_participant(origin, participant_id)?;
+            let account_id = Self::ensure_valid_participant(origin, participant_id)?;
 
             // Ensure post with given id exists
             let post = Self::ensure_post_exists(post_id)?;
@@ -496,35 +516,62 @@ decl_module! {
             // Ensure post unlocked, so mutations can be performed
             Self::ensure_post_unlocked(&post)?;
 
-            // Ensure root replies limit not reached
-            Self::ensure_replies_limit_not_reached(&post)?;
-
-            // New reply creation
-            let reply = if let Some(reply_id) = reply_id {
+            if let Some(reply_id) = reply_id {
                 // Check parent reply existance in case of direct reply
                 Self::ensure_reply_exists(post_id, reply_id)?;
-                Reply::<T, I>::new(text.clone(), participant_id, ParentId::Reply(reply_id))
-            } else {
-                Reply::<T, I>::new(text.clone(), participant_id, ParentId::Post(post_id))
-            };
+            }
+
+            if editable {
+
+                ensure!(
+                    Balances::<T>::usable_balance(&account_id) >= T::ReplyDeposit::get(),
+                    Error::<T, I>::InsufficientBalanceForReply
+                );
+            }
 
             //
             // == MUTATION SAFE ==
             //
 
+            if editable {
+                Self::transfer_to_state_cleanup_treasury_account(
+                    T::ReplyDeposit::get(),
+                    post_id,
+                    &account_id
+                )?;
+            }
+
             // Update runtime storage with new reply
             let post_replies_count = post.replies_count();
-            <ReplyById<T, I>>::insert(post_id, post_replies_count, reply);
 
             // Increment replies counter, associated with given post
             <PostById<T, I>>::mutate(post_id, |inner_post| inner_post.increment_replies_counter());
 
+            if editable {
+                let parent_id = if let Some(reply_id) = reply_id {
+                    Self::ensure_reply_exists(post_id, reply_id)?;
+                    ParentId::Reply(reply_id)
+                } else {
+                    ParentId::Post(post_id)
+                };
+
+
+                let reply = Reply::<T, I>::new(
+                    text.clone(),
+                    participant_id,
+                    parent_id,
+                    T::ReplyDeposit::get()
+                );
+
+                <ReplyById<T, I>>::insert(post_id, post_replies_count, reply);
+            }
+
             if let Some(reply_id) = reply_id {
                 // Trigger event
-                Self::deposit_event(RawEvent::DirectReplyCreated(participant_id, post_id, reply_id, post_replies_count, text));
+                Self::deposit_event(RawEvent::DirectReplyCreated(participant_id, post_id, reply_id, post_replies_count, text, editable));
             } else {
                 // Trigger event
-                Self::deposit_event(RawEvent::ReplyCreated(participant_id, post_id, post_replies_count, text));
+                Self::deposit_event(RawEvent::ReplyCreated(participant_id, post_id, post_replies_count, text, editable));
             }
             Ok(())
         }
@@ -540,7 +587,7 @@ decl_module! {
         /// - DB:
         ///    - O(1) doesn't depend on the state or parameters
         /// # </weight>
-        #[weight = T::WeightInfo::edit_reply(new_text.len().saturated_into())]
+        #[weight = BlogWeightInfo::<T, I>::edit_reply(new_text.len().saturated_into())]
         pub fn edit_reply(
             origin,
             participant_id: ParticipantId<T>,
@@ -578,36 +625,93 @@ decl_module! {
             Ok(())
         }
 
+        #[weight = 1_000_000] // TODO: Adjust weight
+        pub fn delete_reply(
+            origin,
+            participant_id: ParticipantId<T>,
+            post_id: PostId,
+            reply_id: T::ReplyId,
+        ) -> DispatchResult {
+            let account_id = Self::ensure_valid_participant(origin, participant_id)?;
+
+            if let Ok(post) = Self::ensure_post_exists(post_id) {
+                // Ensure post unlocked, so mutations can be performed
+                Self::ensure_post_unlocked(&post)?;
+            }
+
+            // Ensure reply with given id exists
+            let reply = Self::ensure_reply_exists(post_id, reply_id)?;
+
+            // Ensure reply -> owner relation exists
+            Self::ensure_reply_ownership(&reply, &participant_id)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::pay_off(post_id, reply.cleanup_pay_off, &account_id)?;
+
+            // Update reply with new text
+            <ReplyById<T, I>>::remove(post_id, reply_id);
+
+            // Trigger event
+            Self::deposit_event(RawEvent::ReplyDeleted(participant_id, post_id, reply_id));
+            Ok(())
+        }
+
     }
 }
 
 impl<T: Trait<I>, I: Instance> Module<T, I> {
+    fn pay_off(post_id: PostId, amount: BalanceOf<T>, account_id: &T::AccountId) -> DispatchResult {
+        let state_cleanup_treasury_account = T::ModuleId::get().into_sub_account(post_id);
+        <Balances<T> as Currency<T::AccountId>>::transfer(
+            &state_cleanup_treasury_account,
+            account_id,
+            amount,
+            ExistenceRequirement::AllowDeath,
+        )
+    }
+
+    fn transfer_to_state_cleanup_treasury_account(
+        amount: BalanceOf<T>,
+        post_id: PostId,
+        account_id: &T::AccountId,
+    ) -> DispatchResult {
+        let state_cleanup_treasury_account = T::ModuleId::get().into_sub_account(post_id);
+        <Balances<T> as Currency<T::AccountId>>::transfer(
+            account_id,
+            &state_cleanup_treasury_account,
+            amount,
+            ExistenceRequirement::AllowDeath,
+        )
+    }
     // edit_post_weight
     fn edit_post_weight(title: &Option<Vec<u8>>, body: &Option<Vec<u8>>) -> Weight {
         let title_len: u32 = title.as_ref().map_or(0, |t| t.len().saturated_into());
         let body_len: u32 = body.as_ref().map_or(0, |b| b.len().saturated_into());
 
-        T::WeightInfo::edit_post(title_len, body_len)
+        BlogWeightInfo::<T, I>::edit_post(title_len, body_len)
     }
 
     // calculate create_reply weight
     fn create_reply_weight(text_len: usize) -> Weight {
         let text_len: u32 = text_len.saturated_into();
-        T::WeightInfo::create_reply_to_post(text_len)
-            .max(T::WeightInfo::create_reply_to_reply(text_len))
+        BlogWeightInfo::<T, I>::create_reply_to_post(text_len)
+            .max(BlogWeightInfo::<T, I>::create_reply_to_reply(text_len))
     }
 
     // Get participant id from origin
     fn ensure_valid_participant(
         origin: T::Origin,
         participant_id: ParticipantId<T>,
-    ) -> Result<(), DispatchError> {
+    ) -> Result<T::AccountId, DispatchError> {
         let account_id = frame_system::ensure_signed(origin)?;
         ensure!(
             T::ParticipantEnsureOrigin::is_member_controller_account(&participant_id, &account_id),
             Error::<T, I>::MembershipError
         );
-        Ok(())
+        Ok(account_id)
     }
 
     fn ensure_post_exists(post_id: PostId) -> Result<Post<T, I>, DispatchError> {
@@ -665,18 +769,6 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
 
         Ok(posts_count)
     }
-
-    fn ensure_replies_limit_not_reached(post: &Post<T, I>) -> Result<(), DispatchError> {
-        // Get replies count, associated with given post
-        let root_replies_count = post.replies_count();
-
-        ensure!(
-            root_replies_count < T::RepliesMaxNumber::get().into(),
-            Error::<T, I>::RepliesLimitReached
-        );
-
-        Ok(())
-    }
 }
 
 decl_event!(
@@ -703,10 +795,13 @@ decl_event!(
         PostEdited(PostId, UpdatedTitle, UpdatedBody),
 
         /// A reply to a post was created
-        ReplyCreated(ParticipantId, PostId, ReplyId, Text),
+        ReplyCreated(ParticipantId, PostId, ReplyId, Text, bool),
 
         /// A reply to a reply was created
-        DirectReplyCreated(ParticipantId, PostId, ReplyId, ReplyId, Text),
+        DirectReplyCreated(ParticipantId, PostId, ReplyId, ReplyId, Text, bool),
+
+        /// A reply was deleted from storage
+        ReplyDeleted(ParticipantId, PostId, ReplyId),
 
         /// A reply was edited
         ReplyEdited(ParticipantId, PostId, ReplyId, Text),

+ 11 - 2
runtime-modules/blog/src/mock.rs

@@ -222,17 +222,20 @@ impl membership::WeightInfo for Weights {
 parameter_types! {
     pub const PostsMaxNumber: u64 = 20;
     pub const RepliesMaxNumber: u64 = 100;
+    pub const ReplyDeposit: u64 = 500;
+    pub const BlogModuleId: ModuleId = ModuleId(*b"m00:blog"); // module : blog
 }
 
 impl Trait for Runtime {
     type Event = TestEvent;
 
     type PostsMaxNumber = PostsMaxNumber;
-    type RepliesMaxNumber = RepliesMaxNumber;
     type ParticipantEnsureOrigin = MockEnsureParticipant;
     type WeightInfo = ();
 
     type ReplyId = u64;
+    type ReplyDeposit = ReplyDeposit;
+    type ModuleId = BlogModuleId;
 }
 
 impl WeightInfo for () {
@@ -402,7 +405,12 @@ pub fn get_reply(
     parent_id: ParentId<<Runtime as Trait>::ReplyId, PostId>,
 ) -> Reply<Runtime, DefaultInstance> {
     let reply_text = get_reply_text();
-    Reply::new(reply_text, owner, parent_id)
+    Reply::new(
+        reply_text,
+        owner,
+        parent_id,
+        <Runtime as Trait>::ReplyDeposit::get(),
+    )
 }
 
 pub fn create_reply(
@@ -418,6 +426,7 @@ pub fn create_reply(
         post_id,
         reply_id,
         reply,
+        true,
     )
 }
 

+ 46 - 33
runtime-modules/blog/src/tests.rs

@@ -410,6 +410,11 @@ fn reply_creation_success() {
         // Create post for future replies
         create_post(Origin::root()).unwrap();
 
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         let reply_owner_id = ensure_signed(Origin::signed(SECOND_OWNER_ORIGIN)).unwrap();
 
         // Events number before tested call
@@ -443,8 +448,9 @@ fn reply_creation_success() {
             FIRST_ID,
             FIRST_ID,
             get_reply_text(),
+            true,
         ));
-        assert_event_success(reply_created_event, number_of_events_before_call + 1)
+        assert_event_success(reply_created_event, number_of_events_before_call + 4)
     })
 }
 
@@ -453,6 +459,17 @@ fn direct_reply_creation_success() {
     ExtBuilder::default().build().execute_with(|| {
         // Create post for future replies
         create_post(Origin::root()).unwrap();
+
+        Balances::<Runtime>::make_free_balance_be(
+            &FIRST_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         let direct_reply_owner_id = ensure_signed(Origin::signed(SECOND_OWNER_ORIGIN)).unwrap();
 
         assert_ok!(create_reply(
@@ -490,8 +507,10 @@ fn direct_reply_creation_success() {
             FIRST_ID,
             SECOND_ID,
             get_reply_text(),
+            true,
         ));
-        assert_event_success(reply_created_event, number_of_events_before_call + 1)
+
+        assert_event_success(reply_created_event, number_of_events_before_call + 2)
     })
 }
 
@@ -550,43 +569,17 @@ fn reply_creation_post_not_found() {
     })
 }
 
-#[test]
-fn reply_creation_limit_reached() {
-    ExtBuilder::default().build().execute_with(|| {
-        // Create post for future replies
-        create_post(Origin::root()).unwrap();
-        loop {
-            // Events number before tested call
-            let number_of_events_before_call = System::events().len();
-            if let Err(create_reply_err) = create_reply(
-                FIRST_OWNER_ORIGIN,
-                FIRST_OWNER_PARTICIPANT_ID,
-                FIRST_ID,
-                None,
-            ) {
-                let post = post_by_id(FIRST_ID).unwrap();
-
-                // Root post replies counter & reply root max number contraint equality checked
-                assert_eq!(post.replies_count(), RepliesMaxNumber::get());
-
-                // Last reply creation, before limit reached, failure checked
-                assert_failure(
-                    Err(create_reply_err),
-                    Error::RepliesLimitReached,
-                    number_of_events_before_call,
-                );
-                break;
-            }
-        }
-    })
-}
-
 #[test]
 fn direct_reply_creation_reply_not_found() {
     ExtBuilder::default().build().execute_with(|| {
         // Create post for future replies
         create_post(Origin::root()).unwrap();
 
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         // Events number before tested call
         let number_of_events_before_call = System::events().len();
 
@@ -618,6 +611,11 @@ fn reply_editing_success() {
 
         let reply_owner_id = ensure_signed(Origin::signed(SECOND_OWNER_ORIGIN)).unwrap();
 
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         create_reply(
             SECOND_OWNER_ORIGIN,
             SECOND_OWNER_PARTICIPANT_ID,
@@ -661,6 +659,11 @@ fn reply_editing_post_locked_error() {
 
         let reply_owner_id = ensure_signed(Origin::signed(SECOND_OWNER_ORIGIN)).unwrap();
 
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         create_reply(
             SECOND_OWNER_ORIGIN,
             SECOND_OWNER_PARTICIPANT_ID,
@@ -728,6 +731,11 @@ fn reply_editing_ownership_error() {
         // Create post for future replies
         create_post(Origin::root()).unwrap();
 
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         let reply_owner_id = ensure_signed(Origin::signed(SECOND_OWNER_ORIGIN)).unwrap();
 
         create_reply(
@@ -790,6 +798,11 @@ fn reply_editing_participant_error() {
 
         let reply_owner_id = ensure_signed(Origin::signed(SECOND_OWNER_ORIGIN)).unwrap();
 
+        Balances::<Runtime>::make_free_balance_be(
+            &SECOND_OWNER_ORIGIN,
+            <Runtime as Trait>::ReplyDeposit::get(),
+        );
+
         create_reply(
             SECOND_OWNER_ORIGIN,
             SECOND_OWNER_PARTICIPANT_ID,