Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FRAME: Revamp Preimage pallet to use Consideration #1363

Merged
merged 55 commits into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
fe5e59e
Consideration (abstraction over storage deposits)
gavofyork Sep 2, 2023
176194a
Fix stuff
gavofyork Sep 2, 2023
ae05a0d
Whitespace
gavofyork Sep 2, 2023
b14f28d
Repot
gavofyork Sep 2, 2023
13be42a
Docs and fixes
gavofyork Sep 2, 2023
4eebde0
Fixes and docs
gavofyork Sep 2, 2023
d94f888
Consideration trait
gavofyork Sep 2, 2023
3570b1b
Merge branch 'master' into gav-consideration-preimage
gavofyork Sep 2, 2023
9e2dd10
Merge branch 'gav-consideration' into gav-consideration-preimage
gavofyork Sep 2, 2023
c0d8ca6
Merge branch 'master' into gav-consideration
gavofyork Sep 2, 2023
0766ba0
Avoid associated type in Consideration
gavofyork Sep 3, 2023
eae1767
Merge branch 'gav-consideration' into gav-consideration-preimage
gavofyork Sep 3, 2023
f773a55
Fix for new API
gavofyork Sep 6, 2023
7aeae8c
Remove type params from preimage
gavofyork Sep 6, 2023
ae6d315
Make benches compile
ggwpez Sep 6, 2023
45b4160
Expose ensure_updated
ggwpez Sep 6, 2023
3479c19
Fixup mocks
ggwpez Sep 6, 2023
22e3fcf
Fix more mocks
ggwpez Sep 6, 2023
27f5885
More weight fixes
ggwpez Sep 6, 2023
6167e4a
Clippy
ggwpez Sep 6, 2023
c20a5f5
More clippy
ggwpez Sep 6, 2023
2582232
".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime…
Sep 6, 2023
4922ba1
Merge branch 'master' into gav-consideration
gavofyork Sep 7, 2023
8971c64
Merge branch 'master' into gav-consideration
gavofyork Sep 7, 2023
fd0a3d7
Add proper hold reasons
ggwpez Sep 7, 2023
05ac24e
Fix mocks
ggwpez Sep 7, 2023
bdb5407
Fix mock
ggwpez Sep 7, 2023
6d04572
Always use whitelisted caller
ggwpez Sep 8, 2023
aaeb552
Set MaxHolds to 1
ggwpez Sep 8, 2023
915cdc0
Update substrate/frame/support/src/traits/tokens/fungible/freeze.rs
gavofyork Sep 8, 2023
c549398
Update substrate/frame/support/src/traits/tokens/fungible/freeze.rs
gavofyork Sep 8, 2023
d781c55
Update substrate/frame/support/src/traits/storage.rs
gavofyork Sep 8, 2023
4da8bc9
Update substrate/frame/support/src/traits/tokens/fungible/mod.rs
gavofyork Sep 8, 2023
47fce97
Merge branch 'master' into gav-consideration
gavofyork Sep 8, 2023
1ba478f
Clippy
ggwpez Sep 8, 2023
87d182c
Merge remote-tracking branch 'origin/master' into gav-consideration-p…
ggwpez Sep 8, 2023
5b29c2a
import
ggwpez Sep 8, 2023
2f2924e
".git/.scripts/commands/fmt/fmt.sh"
Sep 8, 2023
90c4440
Merge branch 'master' into gav-consideration
gavofyork Sep 8, 2023
ced055e
Add
gavofyork Sep 8, 2023
161755d
Merge branch 'gav-consideration' into gav-consideration-preimage
gavofyork Sep 8, 2023
52233f0
fmt
ggwpez Sep 8, 2023
a742bd9
Update substrate/frame/preimage/src/lib.rs
ggwpez Sep 8, 2023
0b757e8
Merge remote-tracking branch 'origin/master' into gav-consideration-p…
gavofyork Sep 8, 2023
de459b3
Add tests
ggwpez Sep 8, 2023
b10b7aa
Benchmark one account per depositor
ggwpez Sep 8, 2023
b5f484c
Merge branch 'master' into gav-consideration-preimage
gavofyork Sep 10, 2023
fdbacb1
Update substrate/frame/preimage/src/lib.rs
gavofyork Sep 12, 2023
c2097b2
Update substrate/frame/preimage/src/lib.rs
gavofyork Sep 12, 2023
97542d2
Update substrate/frame/preimage/src/tests.rs
gavofyork Sep 12, 2023
2ed225d
Minor tweaks
gavofyork Sep 14, 2023
095a56d
Merge branch 'gav-consideration-preimage' of github.com:paritytech/po…
gavofyork Sep 14, 2023
369f8f5
Merge branch 'master' into gav-consideration-preimage
gavofyork Sep 14, 2023
061573f
Fixes
gavofyork Sep 14, 2023
86d8022
Merge branch 'gav-consideration-preimage' of github.com:paritytech/po…
gavofyork Sep 14, 2023
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
47 changes: 22 additions & 25 deletions substrate/frame/support/src/traits/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,41 +156,38 @@ impl Footprint {
/// holding some data `Footprint` in state.
///
/// The cost may be increased, reduced or dropped entirely as the footprint changes.
pub trait Consideration<AccountId> {
/// A single ticket corresponding to some particular datum held in storage. This is an opaque
/// type, but must itself be stored and generally it should be placed alongside whatever data
/// the ticket was created for.
///
/// While not technically a linear type owing to the need for `FullCodec`, *this should be
/// treated as one*. Don't type to duplicate it, and remember to drop it when you're done with
/// it.
type Ticket: Member + FullCodec + TypeInfo + MaxEncodedLen + Default;
///
/// A single ticket corresponding to some particular datum held in storage. This is an opaque
/// type, but must itself be stored and generally it should be placed alongside whatever data
/// the ticket was created for.
///
/// While not technically a linear type owing to the need for `FullCodec`, *this should be
/// treated as one*. Don't type to duplicate it, and remember to drop it when you're done with
/// it.
#[must_use]
pub trait Consideration<AccountId>: Member + FullCodec + TypeInfo + MaxEncodedLen {
/// Create a ticket for the `new` footprint attributable to `who`. This ticket *must* ultimately
/// be consumed through `update` or `drop` once the footprint changes or is removed.
fn new(who: &AccountId, new: Footprint) -> Result<Self, DispatchError>;

/// Optionally consume an old ticket and alter the footprint, enforcing the new cost to `who`
/// and returning the new ticket (or an error if there was an issue).
///
/// For creating tickets and dropping them, you can use the simpler `new` and `drop` instead.
fn update(
who: &AccountId,
old: Option<Self::Ticket>,
new: Option<Footprint>,
) -> Result<Self::Ticket, DispatchError>;

/// Create a ticket for the `new` footprint attributable to `who`. This ticket *must* be
/// consumed (through either `drop` or `update`) if the footprint changes or is removed.
fn new(who: &AccountId, new: Footprint) -> Result<Self::Ticket, DispatchError> {
Self::update(who, None, Some(new))
}
fn update(self, who: &AccountId, new: Footprint) -> Result<Self, DispatchError>;

/// Consume a ticket for some `old` footprint attributable to `who` which has now been freed.
fn drop(who: &AccountId, old: Self::Ticket) -> Result<(), DispatchError> {
Self::update(who, Some(old), None).map(|_| ())
}
fn drop(self, who: &AccountId) -> Result<(), DispatchError>;
}

impl<A> Consideration<A> for () {
type Ticket = ();
fn update(_: &A, _: Option<()>, _: Option<Footprint>) -> Result<(), DispatchError> {
fn new(_: &A, _: Footprint) -> Result<Self, DispatchError> {
Ok(())
}
fn update(self, _: &A, _: Footprint) -> Result<(), DispatchError> {
Ok(())
}
fn drop(self, _: &A) -> Result<(), DispatchError> {
Ok(())
}
}
Expand Down
222 changes: 136 additions & 86 deletions substrate/frame/support/src/traits/tokens/fungible/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ mod imbalance;
mod item_of;
mod regular;

use super::Precision::BestEffort;
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support_procedural::{CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound};
use scale_info::TypeInfo;
use sp_std::marker::PhantomData;

use super::{Fortitude::Polite, Precision::BestEffort};
pub use freeze::{Inspect as InspectFreeze, Mutate as MutateFreeze};
pub use hold::{
Balanced as BalancedHold, Inspect as InspectHold, Mutate as MutateHold,
Expand All @@ -69,72 +74,86 @@ use crate::{
///
/// The aggregate amount frozen under `R::get()` for any account which has multiple tickets,
/// is the *cumulative* amounts of each ticket's footprint (each individually determined by `D`).
pub struct FreezeConsideration<A, F, R, D>(sp_std::marker::PhantomData<(A, F, R, D)>);
impl<A, F: MutateFreeze<A>, R: Get<F::Id>, D: Convert<Footprint, F::Balance>> Consideration<A>
for FreezeConsideration<A, F, R, D>
#[derive(
CloneNoBound,
EqNoBound,
PartialEqNoBound,
Encode,
Decode,
TypeInfo,
MaxEncodedLen,
RuntimeDebugNoBound,
)]
#[scale_info(skip_type_params(A, F, R, D))]
#[codec(mel_bound())]
pub struct FreezeConsideration<A, F, R, D>(F::Balance, PhantomData<fn() -> (A, R, D)>)
where
F: MutateFreeze<A>;
impl<
A: 'static,
F: 'static + MutateFreeze<A>,
R: 'static + Get<F::Id>,
D: 'static + Convert<Footprint, F::Balance>,
> Consideration<A> for FreezeConsideration<A, F, R, D>
{
type Ticket = F::Balance;
fn update(
who: &A,
old: Option<Self::Ticket>,
new: Option<Footprint>,
) -> Result<Self::Ticket, sp_runtime::DispatchError> {
match (old, new) {
(None, Some(footprint)) => {
let new = D::convert(footprint);
F::increase_frozen(&R::get(), who, new)?;
Ok(new)
},
(Some(old), Some(footprint)) => {
let new = D::convert(footprint);
if old > new {
F::decrease_frozen(&R::get(), who, old - new)?;
} else if new > old {
F::increase_frozen(&R::get(), who, new - old)?;
}
Ok(new)
},
(Some(old), None) => {
F::decrease_frozen(&R::get(), who, old)?;
Ok(Default::default())
},
(None, None) => Ok(Default::default()),
fn new(who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
let new = D::convert(footprint);
F::increase_frozen(&R::get(), who, new)?;
Ok(Self(new, PhantomData))
}
fn update(self, who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
let new = D::convert(footprint);
if self.0 > new {
F::decrease_frozen(&R::get(), who, self.0 - new)?;
} else if new > self.0 {
F::increase_frozen(&R::get(), who, new - self.0)?;
}
Ok(Self(new, PhantomData))
}
fn drop(self, who: &A) -> Result<(), DispatchError> {
F::decrease_frozen(&R::get(), who, self.0).map(|_| ())
}
}

/// Consideration method using a `fungible` balance frozen as the cost exacted for the footprint.
pub struct HoldConsideration<A, F, R, D>(sp_std::marker::PhantomData<(A, F, R, D)>);
impl<A, F: MutateHold<A>, R: Get<F::Reason>, D: Convert<Footprint, F::Balance>> Consideration<A>
for HoldConsideration<A, F, R, D>
#[derive(
CloneNoBound,
EqNoBound,
PartialEqNoBound,
Encode,
Decode,
TypeInfo,
MaxEncodedLen,
RuntimeDebugNoBound,
)]
#[scale_info(skip_type_params(A, F, R, D))]
#[codec(mel_bound())]
pub struct HoldConsideration<A, F, R, D>(F::Balance, PhantomData<fn() -> (A, R, D)>)
where
F: MutateHold<A>;
impl<
A: 'static,
F: 'static + MutateHold<A>,
R: 'static + Get<F::Reason>,
D: 'static + Convert<Footprint, F::Balance>,
> Consideration<A> for HoldConsideration<A, F, R, D>
{
type Ticket = F::Balance;
fn update(
who: &A,
old: Option<Self::Ticket>,
new: Option<Footprint>,
) -> Result<Self::Ticket, sp_runtime::DispatchError> {
match (old, new) {
(None, Some(footprint)) => {
let new = D::convert(footprint);
F::hold(&R::get(), who, new)?;
Ok(new)
},
(Some(old), Some(footprint)) => {
let new = D::convert(footprint);
if old > new {
F::release(&R::get(), who, old - new, BestEffort)?;
} else if new > old {
F::hold(&R::get(), who, new - old)?;
}
Ok(new)
},
(Some(old), None) => {
F::release(&R::get(), who, old, BestEffort)?;
Ok(Default::default())
},
(None, None) => Ok(Default::default()),
fn new(who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
let new = D::convert(footprint);
F::hold(&R::get(), who, new)?;
Ok(Self(new, PhantomData))
}
fn update(self, who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
let new = D::convert(footprint);
if self.0 > new {
F::release(&R::get(), who, self.0 - new, BestEffort)?;
} else if new > self.0 {
F::hold(&R::get(), who, new - self.0)?;
}
Ok(Self(new, PhantomData))
}
fn drop(self, who: &A) -> Result<(), DispatchError> {
F::release(&R::get(), who, self.0, BestEffort).map(|_| ())
}
}

Expand All @@ -145,21 +164,35 @@ impl<A, F: MutateHold<A>, R: Get<F::Reason>, D: Convert<Footprint, F::Balance>>
/// account has only a single active ticket associated with it since individual tickets do not
/// track the specific balance which is frozen. If you are uncertain then use `FreezeConsideration`
/// instead, since this works in all circumstances.
pub struct SingletonFreezeConsideration<A, F, R, D>(sp_std::marker::PhantomData<(A, F, R, D)>);
impl<A, F: MutateFreeze<A>, R: Get<F::Id>, D: Convert<Footprint, F::Balance>> Consideration<A>
for SingletonFreezeConsideration<A, F, R, D>
#[derive(
CloneNoBound,
EqNoBound,
PartialEqNoBound,
Encode,
Decode,
TypeInfo,
MaxEncodedLen,
RuntimeDebugNoBound,
)]
#[scale_info(skip_type_params(A, Fx, Rx, D))]
#[codec(mel_bound())]
pub struct LoneFreezeConsideration<A, Fx, Rx, D>(PhantomData<fn() -> (A, Fx, Rx, D)>);
impl<
A: 'static,
Fx: 'static + MutateFreeze<A>,
Rx: 'static + Get<Fx::Id>,
D: 'static + Convert<Footprint, Fx::Balance>,
> Consideration<A> for LoneFreezeConsideration<A, Fx, Rx, D>
{
type Ticket = ();
fn update(
who: &A,
_old: Option<Self::Ticket>,
new: Option<Footprint>,
) -> Result<Self::Ticket, DispatchError> {
ensure!(F::balance_frozen(&R::get(), who).is_zero(), DispatchError::Unavailable);
match new {
Some(footprint) => F::set_freeze(&R::get(), who, D::convert(footprint)),
None => F::thaw(&R::get(), who),
}
fn new(who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
ensure!(Fx::balance_frozen(&Rx::get(), who).is_zero(), DispatchError::Unavailable);
Fx::set_frozen(&Rx::get(), who, D::convert(footprint), Polite).map(|_| Self(PhantomData))
}
fn update(self, who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
Fx::set_frozen(&Rx::get(), who, D::convert(footprint), Polite).map(|_| Self(PhantomData))
}
fn drop(self, who: &A) -> Result<(), DispatchError> {
Fx::thaw(&Rx::get(), who).map(|_| ())
}
}

Expand All @@ -170,20 +203,37 @@ impl<A, F: MutateFreeze<A>, R: Get<F::Id>, D: Convert<Footprint, F::Balance>> Co
/// account has only a single active ticket associated with it since individual tickets do not
/// track the specific balance which is frozen. If you are uncertain then use `FreezeConsideration`
/// instead, since this works in all circumstances.
pub struct SingletonHoldConsideration<A, F, R, D>(sp_std::marker::PhantomData<(A, F, R, D)>);
impl<A, F: MutateHold<A>, R: Get<F::Reason>, D: Convert<Footprint, F::Balance>> Consideration<A>
for SingletonHoldConsideration<A, F, R, D>
#[derive(
CloneNoBound,
EqNoBound,
PartialEqNoBound,
Encode,
Decode,
TypeInfo,
MaxEncodedLen,
RuntimeDebugNoBound,
)]
#[scale_info(skip_type_params(A, Fx, Rx, D))]
#[codec(mel_bound())]
pub struct LoneHoldConsideration<A, Fx, Rx, D>(PhantomData<fn() -> (A, Fx, Rx, D)>);
impl<
A: 'static,
F: 'static + MutateHold<A>,
R: 'static + Get<F::Reason>,
D: 'static + Convert<Footprint, F::Balance>,
> Consideration<A> for LoneHoldConsideration<A, F, R, D>
{
type Ticket = ();
fn update(
who: &A,
_old: Option<Self::Ticket>,
new: Option<Footprint>,
) -> Result<Self::Ticket, sp_runtime::DispatchError> {
fn new(who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
ensure!(F::balance_on_hold(&R::get(), who).is_zero(), DispatchError::Unavailable);
match new {
Some(footprint) => F::set_on_hold(&R::get(), who, D::convert(footprint)),
None => F::release_all(&R::get(), who, super::Precision::BestEffort).map(|_| ()),
}
F::set_on_hold(&R::get(), who, D::convert(footprint)).map(|_| Self(PhantomData))
}
fn update(self, who: &A, footprint: Footprint) -> Result<Self, DispatchError> {
F::set_on_hold(&R::get(), who, D::convert(footprint)).map(|_| Self(PhantomData))
}
fn drop(self, who: &A) -> Result<(), DispatchError> {
F::release_all(&R::get(), who, BestEffort).map(|_| ())
}
}

#[test]
fn it_builds() {}