Commit 0297ee0c authored by Chris D'Costa's avatar Chris D'Costa
Browse files

v1.12.0 Update - Locking Mechanism first pass

This update is a second major update to the code, amending the Substrate Standard to physically remove funds when funds are locked.

There is still some work to do to ensure that the mechanism is robust enough.
parent 56d8b602
......@@ -4,7 +4,7 @@ path = "node/src/main.rs"
[package]
name = "totem-meccano"
version = "1.11.0"
version = "1.12.0"
authors = ["Totem Live Accounting <chris.dcosta@totemaccounting.com>"]
build = "build.rs"
edition = "2018"
......
......@@ -153,7 +153,8 @@ decl_module! {
user_hash: UserNameHash, // this is what is signed
signature: Ed25519signature
) -> Result {
// ensure that the transaction is signed. Nothing to do woth what happens next!
let _user = ensure_signed(origin)?;
// provided you are the owner of the keys you can remove them entirely from storage.
let sign_key = Self::public_key_sign(&user_hash).ok_or("Storage Read Error: cannot get signature key")?;
ensure!(signature.verify(&user_hash[..], &sign_key), "Invalid signature for this key");
......
......@@ -98,7 +98,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// for block authoring // fork risk, on change
authoring_version: 1,
// spec version // fork risk, on change
spec_version: 11,
spec_version: 12,
// incremental changes
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
......@@ -223,6 +223,7 @@ impl balances::Trait for Runtime {
type DustRemoval = ();
type TransferPayment = ();
type Accounting = accounting::Module<Self>;
type BalancesConversions = ConversionHandler;
}
impl consensus::Trait for Runtime {
......
......@@ -185,20 +185,21 @@ decl_module! {
// Order is owned by sender, status unaccepted a
let approver: T::AccountId = order.approver;
let order_status: u16 = order.order_status;
if let (approver, order_status) = (who, 0u16) {
if (approver.clone(), order_status) == (who.clone(), 0u16) {
<Owner<T>>::mutate(&order.commander, |owner| {
owner.retain(|v| v != &tx_keys_medium.record_id)
});
<Beneficiary<T>>::mutate(&order.fulfiller, |owner| {
owner.retain(|v| v != &tx_keys_medium.record_id)
});
<Approver<T>>::mutate(&approver, |owner| {
// <Approver<T>>::mutate(&approver, |owner| {
<Approver<T>>::mutate(approver, |owner| {
owner.retain(|v| v != &tx_keys_medium.record_id)
});
<Postulate<T>>::remove(&tx_keys_medium.record_id);
<Orders<T>>::remove(&tx_keys_medium.record_id);
<OrderItems<T>>::remove(&tx_keys_medium.record_id);
} else {
} else if (approver, order_status) != (who, 0u16) {
Self::deposit_event(RawEvent::ErrorStatusNotAllowed6(tx_keys_medium.tx_uid));
return Err("This is not your order or wrong status");
}
......
......@@ -18,6 +18,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
sr-primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false }
# For test cases
[dev-dependencies]
sr-io = { path = "../../core/sr-io" }
......
......@@ -128,9 +128,8 @@ pub trait Trait: system::Trait + timestamp::Trait {
+ MaybeSerializeDebug;
type AccountingConversions: Convert<Self::CoinAmount, LedgerBalance>
+ Convert<LedgerBalance, i128>; // Used
// Convert<Self::CoinAmount, u128>;
+ Convert<LedgerBalance, i128>;
// Convert<i128, AccountBalanceOf<Self>> +
// Convert<i128, u128> +
// Convert<bool, UnLocked<Self>> +
......
......@@ -174,7 +174,7 @@
use parity_codec::{Codec, Decode, Encode};
use primitives::traits::{
As, CheckedAdd, CheckedSub, MaybeSerializeDebug, Member, Saturating, SimpleArithmetic,
StaticLookup, Zero,
StaticLookup, Zero, Convert,
};
use rstd::prelude::*;
use rstd::{cmp, result};
......@@ -219,6 +219,9 @@ pub trait Subtrait<I: Instance = DefaultInstance>:
/// Totem Accounting type
type Accounting: Posting<Self::AccountId, Self::Hash, Self::BlockNumber, Self::Balance>;
type BalancesConversions: Convert<u128, Self::Balance>
+ Convert<u64, Self::BlockNumber>;
}
pub trait Trait<I: Instance = DefaultInstance>:
......@@ -259,6 +262,9 @@ pub trait Trait<I: Instance = DefaultInstance>:
/// Totem Accounting type
type Accounting: Posting<Self::AccountId, Self::Hash, Self::BlockNumber, Self::Balance>;
type BalancesConversions: Convert<u128, Self::Balance>
+ Convert<u64, Self::BlockNumber>;
}
impl<T: Trait<I>, I: Instance> Subtrait<I> for T {
......@@ -266,6 +272,7 @@ impl<T: Trait<I>, I: Instance> Subtrait<I> for T {
type OnFreeBalanceZero = T::OnFreeBalanceZero;
type OnNewAccount = T::OnNewAccount;
type Accounting = T::Accounting;
type BalancesConversions = T::BalancesConversions;
}
decl_event!(
......@@ -735,6 +742,7 @@ impl<T: Subtrait<I>, I: Instance> Trait<I> for ElevatedTrait<T, I> {
type TransferPayment = ();
type DustRemoval = ();
type Accounting = T::Accounting;
type BalancesConversions = T::BalancesConversions;
}
impl<T: Trait<I>, I: Instance> Currency<T::AccountId> for Module<T, I>
......@@ -835,11 +843,10 @@ where
Self::new_account(dest, new_to_balance);
}
Self::set_free_balance(dest, new_to_balance);
// Account for fees in Totem
match <T::Accounting as Posting<T::AccountId,T::Hash,T::BlockNumber,T::Balance>>::account_for_fees(fee, dest.clone()) {
Ok(_) => (),
Err(_e) => {
// Self::deposit_event(RawEvent::ErrorInAccounting1(uid));
return Err("An error occured posting to accounts");
},
}
......@@ -1065,7 +1072,26 @@ where
if let Some(lock) = new_lock {
locks.push(lock)
}
<Locks<T, I>>::insert(who, locks);
// Totem Update
// The standard lock only stacks locks - it does not actually lock user's funds.
// Reserved balances can also be slashed, so to ensure that escrow funds are properly locked
// this function has been adapted to physically remove the associated funds. Note this
// also reduces the Total Issuance. The only way to recover the funds is to unlock.
match Self::withdraw(
who,
amount,
WithdrawReason::Escrow,
ExistenceRequirement::KeepAlive,
) {
Ok(_) => {
<Locks<T, I>>::insert(who, locks);
},
Err(_e) => {
// Lock not set
();
},
}
// <Locks<T, I>>::insert(who, locks);
}
fn extend_lock(
......@@ -1102,22 +1128,73 @@ where
if let Some(lock) = new_lock {
locks.push(lock)
}
<Locks<T, I>>::insert(who, locks);
// Totem Update
// The standard lock only stacks locks - it does not actually lock user's funds.
// Reserved balances can also be slashed, so to ensure that escrow funds are properly locked
// this function has been adapted to physically remove the associated funds. Note this
// also reduces the Total Issuance. The only way to recover the funds is to unlock.
match Self::withdraw(
who,
amount,
WithdrawReason::Escrow,
ExistenceRequirement::KeepAlive,
) {
Ok(_) => {
<Locks<T, I>>::insert(who, locks);
},
Err(_e) => {
// Lock not set
();
},
}
// <Locks<T, I>>::insert(who, locks);
}
fn remove_lock(id: LockIdentifier, who: &T::AccountId) {
let now = <system::Module<T>>::block_number();
// Totem Update
// dummy placeholders
let amount: T::Balance = <T::BalancesConversions as Convert<u128, T::Balance>>::convert(0u128);
let until: T::BlockNumber = <T::BalancesConversions as Convert<u64, T::BlockNumber>>::convert(0u64);
let reasons: WithdrawReasons = WithdrawReasons::all();
// For holding a single lock value
let mut lock = Some(BalanceLockV1 {
id,
amount,
until,
reasons,
});
// If the id is valid get the amount from the lock record
// and at the same time return a Vec containing all the lock records minus the one we've taken
let locks = Self::locks(who)
.into_iter()
.filter_map(|l| {
if l.until > now && l.id != id {
Some(l)
} else {
None
}
})
.collect::<Vec<_>>();
<Locks<T, I>>::insert(who, locks);
.into_iter()
.filter_map(|ls| {
if ls.until > now && ls.id == id {
lock.take().map(|_l| BalanceLockV1 {
id: ls.id,
amount: ls.amount,
until: ls.until,
reasons: ls.reasons,
})
} else if ls.until > now && ls.id != id {
Some(ls)
} else {
None
}
})
.collect::<Vec<_>>();
// If there is an amount then recover funds, clean up records storage
match lock {
Some(l) => {
// Recovering the now unlocked funds.
Self::deposit_into_existing(&who, l.amount).ok();
<Locks<T, I>>::insert(who, locks);
}
None => (),
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment