Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
d2a1c7b
Improve naming.
gavofyork Nov 2, 2022
a1748df
More improvements to naming
gavofyork Nov 2, 2022
8394666
Fungible counterpart
gavofyork Nov 2, 2022
c81e4a4
Shared pot instead of reserve
gavofyork Nov 2, 2022
9a78199
Transferable receipts
gavofyork Nov 2, 2022
556aee9
Better naming
gavofyork Nov 2, 2022
326bed5
Use u128 for counterpart
gavofyork Nov 3, 2022
fb9857f
Partial thawing
gavofyork Nov 3, 2022
b232a35
Docs
gavofyork Nov 3, 2022
66fa13b
Remove AdminOrigin
gavofyork Nov 3, 2022
3855ed0
Integrate into Kitchen Sink
gavofyork Nov 3, 2022
ed21e76
Thaw throttling
gavofyork Nov 3, 2022
c2fd94e
Remove todo
gavofyork Nov 3, 2022
ec6b594
Docs
gavofyork Nov 3, 2022
1442179
Fix benchmarks
gavofyork Nov 3, 2022
86ceb01
Building
gavofyork Nov 4, 2022
54609be
Tests work
gavofyork Nov 4, 2022
085996b
New benchmarks
gavofyork Nov 5, 2022
077afbe
Benchmarking tests
gavofyork Nov 5, 2022
3ca6918
Test new defensive_saturating_* functions
ggwpez Nov 5, 2022
25d80d3
fmt
ggwpez Nov 5, 2022
9ea6681
Formatting
gavofyork Nov 6, 2022
be66334
Update frame/nis/src/lib.rs
gavofyork Nov 6, 2022
471c83b
Apply suggestions from code review
gavofyork Nov 6, 2022
c668161
Merge branch 'gav-ref-nis' of github.com:paritytech/substrate into ga…
gavofyork Nov 6, 2022
a44dc75
Events added
gavofyork Nov 6, 2022
f89b093
Fix kitchensink
gavofyork Nov 6, 2022
f5a3e3d
Update frame/nis/src/lib.rs
gavofyork Nov 8, 2022
1474a75
Review niggles
gavofyork Nov 10, 2022
376132d
Merge branch 'gav-ref-nis' of github.com:paritytech/substrate into ga…
gavofyork Nov 11, 2022
bafbdff
Merge remote-tracking branch 'origin/master' into gav-ref-nis
gavofyork Nov 11, 2022
ef9a239
Remove genesis build requirements
gavofyork Nov 11, 2022
207a4b5
Grumbles
gavofyork Nov 14, 2022
e395e84
Merge remote-tracking branch 'origin/master' into gav-ref-nis
gavofyork Nov 14, 2022
6a85012
Fixes
gavofyork Nov 14, 2022
d11f04e
Fixes
gavofyork Nov 14, 2022
8b47006
Fixes
gavofyork Nov 14, 2022
2a59d93
Update frame/nis/src/lib.rs
gavofyork Nov 22, 2022
cd45d8a
Update primitives/runtime/src/traits.rs
gavofyork Nov 22, 2022
d201b05
Merge remote-tracking branch 'origin/master' into gav-ref-nis
gavofyork Nov 22, 2022
990f280
Formatting
gavofyork Nov 22, 2022
15bd0ac
Fixes
gavofyork Nov 23, 2022
9578bf0
Fix node genesis config
ggwpez Nov 23, 2022
ecf4bc1
Fix node chain specs
ggwpez Nov 23, 2022
0a57aed
Use free asset ID as counterpart
ggwpez Nov 23, 2022
6e13e91
Account for rounding errors in fund_deficit bench
ggwpez Nov 23, 2022
45c58b4
clippy
ggwpez Nov 23, 2022
e4499b4
fmt
ggwpez Nov 23, 2022
335ca07
Fix
gavofyork Nov 27, 2022
314728f
Rename
gavofyork Nov 27, 2022
ab31838
Merge branch 'gav-ref-nis' of github.com:paritytech/substrate into ga…
gavofyork Nov 27, 2022
57402c0
Merge remote-tracking branch 'origin/master' into gav-ref-nis
gavofyork Nov 27, 2022
52e6430
Fixes
gavofyork Nov 27, 2022
5817e46
Fixes
gavofyork Nov 27, 2022
fd2575a
Merge branch 'master' into gav-ref-nis
gavofyork Dec 1, 2022
14a4085
Merge remote-tracking branch 'origin/master' into gav-ref-nis
gavofyork Dec 2, 2022
2a18a46
Formatting
gavofyork Dec 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Thaw throttling
  • Loading branch information
gavofyork committed Nov 3, 2022
commit ed21e766f669c981806cb6ba6a3a60a8ae680ec4
8 changes: 6 additions & 2 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,9 +1451,11 @@ parameter_types! {
pub const MaxQueueLen: u32 = 1000;
pub const FifoQueueLen: u32 = 500;
pub const Period: BlockNumber = 30 * DAYS;
pub const MinFreeze: Balance = 100 * DOLLARS;
pub const MinBid: Balance = 100 * DOLLARS;
pub const MinReceipt: Perquintill = Perquintill::from_percent(1);
pub const IntakePeriod: BlockNumber = 10;
pub const MaxIntakeBids: u32 = 10;
pub const ThawThrottle: (Perquintill, BlockNumber) = (Perquintill::from_percent(25), 5);
pub Target: Perquintill = Perquintill::zero();
pub const NisPalletId: PalletId = PalletId(*b"py/nis ");
}
Expand All @@ -1474,9 +1476,11 @@ impl pallet_nis::Config for Runtime {
type MaxQueueLen = MaxQueueLen;
type FifoQueueLen = FifoQueueLen;
type Period = Period;
type MinFreeze = MinFreeze;
type MinBid = MinBid;
type MinReceipt = MinReceipt;
type IntakePeriod = IntakePeriod;
type MaxIntakeBids = MaxIntakeBids;
type ThawThrottle = ThawThrottle;
}

parameter_types! {
Expand Down
62 changes: 46 additions & 16 deletions frame/nis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
//! bid size so that smaller bids fall off as it gets too large.
//!
//! Account may enqueue a balance with some number of `Period`s lock up, up to a maximum of
//! `QueueCount`. The balance gets reserved. There's a minimum of `MinFreeze` to avoid dust.
//! `QueueCount`. The balance gets reserved. There's a minimum of `MinBid` to avoid dust.
//!
//! Until your bid is consolidated and you receive a receipt, you can retract it instantly and the
//! funds are unreserved.
Expand Down Expand Up @@ -145,6 +145,7 @@ pub mod pallet {
<T as frame_system::Config>::AccountId,
<T as frame_system::Config>::BlockNumber,
>;
type SummaryRecordOf<T> = SummaryRecord<<T as frame_system::Config>::BlockNumber>;

pub struct NoCounterpart<T>(sp_std::marker::PhantomData<T>);
impl<T> FungibleInspect<T> for NoCounterpart<T> {
Expand Down Expand Up @@ -197,6 +198,10 @@ pub mod pallet {
/// Overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// The treasury's pallet id, used for deriving its sovereign account ID.
#[pallet::constant]
type PalletId: Get<PalletId>;

/// Currency type that this works on.
type Currency: ReservableCurrency<Self::AccountId, Balance = Self::CurrencyBalance>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NamedReservableCurrency can help with bookkeeping

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's no need to use that trait specifically in this pallet and force it to handle the naming. If naming is needed by the runtime then it can be done through an adapter struct at the pallet config level. I'll provide such an adapter in this PR.


Expand Down Expand Up @@ -260,7 +265,12 @@ pub mod pallet {
/// It should be at least big enough to ensure that there is no possible storage spam attack
/// or queue-filling attack.
#[pallet::constant]
type MinFreeze: Get<BalanceOf<Self>>;
type MinBid: Get<BalanceOf<Self>>;

/// The minimum amount of funds which may intentionally be left remaining under a single
/// receipt.
#[pallet::constant]
type MinReceipt: Get<Perquintill>;

/// The number of blocks between consecutive attempts to dequeue bids and create receipts.
///
Expand All @@ -275,9 +285,9 @@ pub mod pallet {
#[pallet::constant]
type MaxIntakeBids: Get<u32>;

/// The treasury's pallet id, used for deriving its sovereign account ID.
/// The maximum proportion which may be thawed and the period over which it is reset.
#[pallet::constant]
type PalletId: Get<PalletId>;
type ThawThrottle: Get<(Perquintill, Self::BlockNumber)>;
}

#[pallet::pallet]
Expand Down Expand Up @@ -322,11 +332,15 @@ pub mod pallet {
#[derive(
Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen,
)]
pub struct SummaryRecord {
pub struct SummaryRecord<BlockNumber> {
/// The proportion of funds that the `frozen` balance represents to total issuance.
pub proportion_owed: Perquintill,
/// The total number of bonds issued so far.
pub index: ActiveIndex,
/// The amount (as a proportion of ETI) which has been thawed in this period so far.
pub thawed: Perquintill,
/// The current thaw period's beginning.
pub last_period: BlockNumber,
}

/// The totals of items and balances within each queue. Saves a lot of storage reads in the
Expand All @@ -350,7 +364,7 @@ pub mod pallet {

/// Information relating to the bonds currently active.
#[pallet::storage]
pub type Summary<T> = StorageValue<_, SummaryRecord, ValueQuery>;
pub type Summary<T> = StorageValue<_, SummaryRecordOf<T>, ValueQuery>;

/// The currently active bonds, indexed according to the order of creation.
#[pallet::storage]
Expand Down Expand Up @@ -432,6 +446,10 @@ pub mod pallet {
Unfunded,
/// There are enough funds for what is required.
Funded,
/// The thaw throttle has been reached for this period.
Throttled,
/// The operation would result in a receipt worth an insignficant value.
MakesDust,
}

#[pallet::hooks]
Expand All @@ -453,7 +471,7 @@ pub mod pallet {
///
/// - `amount`: The amount of the bid; these funds will be reserved. If the bid is
/// successfully elevated into a bond, then these funds will continue to be
/// reserved until the bond thaws. Must be at least `MinFreeze`.
/// reserved until the bond thaws. Must be at least `MinBid`.
/// - `duration`: The number of periods before which the bond may be thawed.
/// Must be greater than 1 and no more than `QueueCount`.
///
Expand All @@ -467,7 +485,7 @@ pub mod pallet {
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;

ensure!(amount >= T::MinFreeze::get(), Error::<T>::AmountTooSmall);
ensure!(amount >= T::MinBid::get(), Error::<T>::AmountTooSmall);
let queue_count = T::QueueCount::get() as usize;
let queue_index = duration.checked_sub(1).ok_or(Error::<T>::DurationTooSmall)? as usize;
ensure!(queue_index < queue_count, Error::<T>::DurationTooBig);
Expand Down Expand Up @@ -527,7 +545,6 @@ pub mod pallet {
let queue_count = T::QueueCount::get() as usize;
let queue_index = duration.checked_sub(1).ok_or(Error::<T>::DurationTooSmall)? as usize;
ensure!(queue_index < queue_count, Error::<T>::DurationTooBig);
// TODO: ensure!(have_in_reserve(amount))

let bid = Bid { amount, who };
let new_len = Queues::<T>::try_mutate(duration, |q| -> Result<u32, DispatchError> {
Expand All @@ -554,7 +571,7 @@ pub mod pallet {
#[pallet::weight(T::WeightInfo::fund_deficit())]
pub fn fund_deficit(origin: OriginFor<T>) -> DispatchResult {
T::FundOrigin::ensure_origin(origin)?;
let summary: SummaryRecord = Summary::<T>::get();
let summary: SummaryRecordOf<T> = Summary::<T>::get();
let our_account = Self::account_id();
let issuance = Self::issuance_with(&our_account, &summary);
let deficit = issuance.required.saturating_sub(issuance.holdings);
Expand Down Expand Up @@ -586,19 +603,32 @@ pub mod pallet {
let now = frame_system::Pallet::<T>::block_number();
ensure!(now >= receipt.expiry, Error::<T>::NotExpired);

let mut summary: SummaryRecordOf<T> = Summary::<T>::get();

let proportion = if let Some(counterpart) = portion {
let proportion = T::CounterpartAmount::convert_back(counterpart);
ensure!(proportion <= receipt.proportion, Error::<T>::TooMuch);
// TODO: check if `proportion` is below a minimum bond size and if so then fail.
let remaining = receipt.proportion.saturating_sub(proportion);
ensure!(
remaining.is_zero() || remaining >= T::MinReceipt::get(),
Error::<T>::MakesDust
);
proportion
} else {
let fung_eq = T::CounterpartAmount::convert(receipt.proportion);
T::Counterpart::burn_from(&who, fung_eq)?;
receipt.proportion
};

let (throttle, throttle_period) = T::ThawThrottle::get();
if now.saturating_sub(summary.last_period) >= throttle_period {
summary.thawed = Zero::zero();
summary.last_period = now;
}
summary.thawed.saturating_accrue(proportion);
ensure!(summary.thawed <= throttle, Error::<T>::Throttled);

T::Counterpart::burn_from(&who, T::CounterpartAmount::convert(proportion))?;

// Multiply the proportion it is by the total issued.
let mut summary: SummaryRecord = Summary::<T>::get();
let our_account = Self::account_id();
let effective_issuance = Self::issuance_with(&our_account, &summary).effective;
let amount = proportion * effective_issuance;
Expand Down Expand Up @@ -685,7 +715,7 @@ pub mod pallet {
/// Also provides the summary and this pallet's account ID.
pub fn issuance_with(
our_account: &T::AccountId,
summary: &SummaryRecord,
summary: &SummaryRecordOf<T>,
) -> IssuanceInfo<BalanceOf<T>> {
let total_issuance =
T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get());
Expand All @@ -700,7 +730,7 @@ pub mod pallet {
/// Attempt to enlarge our bond-set from bids in order to satisfy our desired target amount
/// of funds frozen into bonds.
pub fn pursue_target(max_bids: u32) -> Weight {
let summary: SummaryRecord = Summary::<T>::get();
let summary: SummaryRecordOf<T> = Summary::<T>::get();
let target = T::Target::get();
if summary.proportion_owed < target {
let missing = target.saturating_sub(summary.proportion_owed);
Expand Down
10 changes: 6 additions & 4 deletions frame/nis/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,18 @@ parameter_types! {
pub IgnoredIssuance: u64 = Balances::total_balance(&0); // Account zero is ignored.
pub const NisPalletId: PalletId = PalletId(*b"py/nis ");
pub static Target: Perquintill = Perquintill::zero();
pub const MinReceipt: Perquintill = Perquintill::from_percent(1);
pub const ThawThrottle: (Perquintill, u64) = (Perquintill::from_percent(25), 5);
}

ord_parameter_types! {
pub const One: u64 = 1;
}

// TODO: Throttled thawing.

impl pallet_nis::Config for Test {
type WeightInfo = ();
type RuntimeEvent = RuntimeEvent;
type PalletId = NisPalletId;
type Currency = Balances;
type CurrencyBalance = <Self as pallet_balances::Config<Instance1>>::Balance;
type FundOrigin = frame_system::EnsureSigned<Self::AccountId>;
Expand All @@ -134,10 +135,11 @@ impl pallet_nis::Config for Test {
type MaxQueueLen = ConstU32<3>;
type FifoQueueLen = ConstU32<1>;
type Period = ConstU64<3>;
type MinFreeze = ConstU64<2>;
type MinBid = ConstU64<2>;
type IntakePeriod = ConstU64<2>;
type MaxIntakeBids = ConstU32<2>;
type PalletId = NisPalletId;
type MinReceipt = MinReceipt;
type ThawThrottle = ThawThrottle;
}

// This function basically just builds a genesis storage key/value store according to
Expand Down
Loading