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

Refactor proxy pallet to use Consideration instead #5336

Open
wants to merge 30 commits into
base: master
Choose a base branch
from

Conversation

davidk-pt
Copy link

@davidk-pt davidk-pt commented Aug 13, 2024

Refactor proxy pallet to use Consideration #226

Based on initial PR here https://github.com/paritytech/polkadot-sdk/pull/1837/files

Adds TestDefaultConfig for proxy pallet.

Guide on how to migrate from previous proxy pallet usage

  1. Remove Currency from configuration of the proxy pallet (now currency comes from ProxyConsideration and AnnouncementConsideration)

  2. Remove the ProxyDepositBase, ProxyDepositFactor, AnnouncementDepositBase, AnnouncementDepositFactor types inside proxy pallet config and add ProxyConsideration and AnnouncementConsideration configuration types instead.

Also you need to add two hold reasons for proxy and announcement respectively

parameter_types! {
	pub const ProxyHoldReason: RuntimeHoldReason = RuntimeHoldReason::Proxy(pallet_proxy::HoldReason::Proxy);
	pub const AnnouncementHoldReason: RuntimeHoldReason = RuntimeHoldReason::Proxy(pallet_proxy::HoldReason::Announcement);
}

IMPORTANT

To preserve backwards compatible behaviour of Proxy pallet storage reservation fees use ZeroFootprintOr<LinearStoragePrice<...>, ...> conversion. This has same behaviour as previous implementation, that if there's no items in proxies or announcements then the price is zero, if there's at least one item then the price is base + items * factor * bytes.

ProxyDepositFactor and AnnouncementDepositFactor parameters in AtLeastOneLinearStoragePrice don't need to account for byte size of proxies and announcements as it is already computed so it should be renamed to ProxyDepositPerByte and AnnouncementDepositPerByte and deposit value should be divided by previous byte value that was used, for example deposit(0, 66) should be lowered to deposit(0, 1) if deposit factor reflected 66 bytes per item.

Example

Previous example proxy usage

parameter_types! {
	pub const ProxyDepositBase: Balance = deposit(1, 40);
	pub const ProxyDepositFactor: Balance = deposit(0, 33);
	pub const MaxProxies: u16 = 32;
	pub const AnnouncementDepositBase: Balance = deposit(1, 48);
	pub const AnnouncementDepositFactor: Balance = deposit(0, 66);
	pub const MaxPending: u16 = 32;
}

impl pallet_proxy::Config for Runtime {
	type RuntimeEvent = RuntimeEvent;
	type RuntimeCall = RuntimeCall;
	type Currency = Balances;
	type ProxyType = ProxyType;
	type ProxyDepositBase = ProxyDepositBase;
	type ProxyDepositFactor = ProxyDepositFactor;
	type MaxProxies = MaxProxies;
	type WeightInfo = weights::pallet_proxy::WeightInfo<Runtime>;
	type MaxPending = MaxPending;
	type CallHasher = BlakeTwo256;
	type AnnouncementDepositBase = AnnouncementDepositBase;
	type AnnouncementDepositFactor = AnnouncementDepositFactor;
}

New usage

parameter_types! {
	// One storage item; key size 32, value size 8; .
	pub const ProxyDepositBase: Balance = deposit(1, 40);
	pub const ProxyDepositPerByte: Balance = deposit(0, 1);
	pub const MaxProxies: u16 = 32;
	// One storage item; key size 32, value size 16
	pub const AnnouncementDepositBase: Balance = deposit(1, 48);
	pub const AnnouncementDepositPerByte: Balance = deposit(0, 1);
	pub const MaxPending: u16 = 32;
	pub const ProxyHoldReason: RuntimeHoldReason = RuntimeHoldReason::Proxy(pallet_proxy::HoldReason::Proxy);
	pub const AnnouncementHoldReason: RuntimeHoldReason = RuntimeHoldReason::Proxy(pallet_proxy::HoldReason::Announcement);
}

impl pallet_proxy::Config for Runtime {
	type RuntimeEvent = RuntimeEvent;
	type RuntimeCall = RuntimeCall;
	type Currency = Balances;
	type ProxyType = ProxyType;
	type MaxProxies = MaxProxies;
	type WeightInfo = weights::pallet_proxy::WeightInfo<Runtime>;
	type MaxPending = MaxPending;
	type CallHasher = BlakeTwo256;
	type ProxyConsideration = fungible::HoldConsideration<
		AccountId,
		Balances,
		ProxyHoldReason,
		ZeroFootprintOr<
			LinearStoragePrice<
				ProxyDepositBase,
				ProxyDepositPerByte,
				Balance,
			>,
			Balance,
		>,
	>;
	type AnnouncementConsideration = fungible::HoldConsideration<
		AccountId,
		Balances,
		ProxyHoldReason,
		ZeroFootprintOr<
			LinearStoragePrice<
				AnnouncementDepositBase,
				AnnouncementDepositPerByte,
				Balance,
			>,
			Balance,
		>,
	>;
}

@seadanda @muharem

@davidk-pt davidk-pt added the T2-pallets This PR/Issue is related to a particular pallet. label Aug 13, 2024
@davidk-pt davidk-pt requested a review from a team as a code owner August 13, 2024 08:31
@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch from bebc66f to 130be66 Compare August 13, 2024 08:33
@davidk-pt davidk-pt marked this pull request as draft August 13, 2024 09:08
@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch 2 times, most recently from ac65fc0 to 912f663 Compare August 19, 2024 10:29
@davidk-pt davidk-pt changed the title WIP: Refactor proxy pallet to use Consideration instead Refactor proxy pallet to use Consideration instead Aug 19, 2024
@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch 7 times, most recently from 8ff747d to 6ae7b4a Compare August 21, 2024 13:33
@davidk-pt davidk-pt marked this pull request as ready for review August 21, 2024 14:11
@davidk-pt davidk-pt requested a review from athei as a code owner August 21, 2024 14:11
@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch from f901e22 to ad31477 Compare August 23, 2024 04:44
Copy link
Contributor

@kianenigma kianenigma left a comment

Choose a reason for hiding this comment

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

Here we need a new runtime API, or a pallet view function, that would allow a UI to query how much the deposit would be.

We can go with the runtime API approach, but then it is really hard to get this API integrated across all runtimes..

The PR itself is pretty good, but I think this is tapping into another unsolved problem that we have now, so we should pause and first consolidate on how the broader issue is solved.

I have recently re-summarized the issue at hand here:

https://forum.polkadot.network/t/wasm-view-functions/1045

@kianenigma
Copy link
Contributor

kianenigma commented Aug 27, 2024

This PR per-se is one where we would benefit most from view-functions, as they would be shipped automatically, and the logic that needs to be encapsulated is pallet-specific.

@davidk-pt
Copy link
Author

Here we need a new runtime API, or a pallet view function, that would allow a UI to query how much the deposit would be.

We can go with the runtime API approach, but then it is really hard to get this API integrated across all runtimes..

The PR itself is pretty good, but I think this is tapping into another unsolved problem that we have now, so we should pause and first consolidate on how the broader issue is solved.

I have recently re-summarized the issue at hand here:

https://forum.polkadot.network/t/wasm-view-functions/1045

It does sound like proxy pallet could benefit from the view functions so all users could see their proxy deposit sizes. However, from the storage and implementation perspective, would we need to change anything to create view functions? For me it seems these are independent problems and we could resolve these in the future once view functions for pallets are established. PRs to create view functions would be much smaller this way.

@paritytech-review-bot paritytech-review-bot bot requested a review from a team August 30, 2024 08:45
@paritytech-cicd-pr
Copy link

The CI pipeline was cancelled due to failure one of the required jobs.
Job name: test-linux-stable 3/3
Logs: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7248521

@kianenigma
Copy link
Contributor

kianenigma commented Sep 4, 2024

Here we need a new runtime API, or a pallet view function, that would allow a UI to query how much the deposit would be.
We can go with the runtime API approach, but then it is really hard to get this API integrated across all runtimes..
The PR itself is pretty good, but I think this is tapping into another unsolved problem that we have now, so we should pause and first consolidate on how the broader issue is solved.
I have recently re-summarized the issue at hand here:
https://forum.polkadot.network/t/wasm-view-functions/1045

It does sound like proxy pallet could benefit from the view functions so all users could see their proxy deposit sizes. However, from the storage and implementation perspective, would we need to change anything to create view functions? For me it seems these are independent problems and we could resolve these in the future once view functions for pallets are established. PRs to create view functions would be much smaller this way.

We have a PR to ship the view functions, and the discussion in the forum thread is converging towards using them.

So, in principle, once we have them, we can provide a view fn that returns the deposit amount of a new proxy to be created.

I am a bit hesitant to green-light this PR before the above is done though. Imagine: if DApps rely on ProxyDepositBase (which had #[pallet::constant], which means it is in the metadata), we break things for them once now, and once later when we provide the fix: view functions.

I suggest:

  1. Option 1: Pause this PR until the view fn matter is resolved, make it be a first-time user of the new view fn paradaigm.
  2. Option 2: With #[pallet::extra_constants] we can do this migration, but keep the old values in the metadata. This is a hack, and I am not sure if it would even make sense, because the pallet won't even know the final deposit amount... worth exploring, but I cannot be sure it works.

FWIW, I think pausing the PR is not bad, or anything short of success here, especially in this day and age where we value stability. We can then use the learnings here to shift focus towards merging view functions, then resuming the work here.

Side note: this conversation might be of interest for your learning @davidk-pt :) #3238 (comment)

@@ -81,11 +89,13 @@ fn add_announcements<T: Config>(
}

benchmarks! {
where_clause { where T: Config + pallet_balances::Config }
Copy link
Member

@ggwpez ggwpez Sep 4, 2024

Choose a reason for hiding this comment

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

There are different cases to handle this, but specifically requiring that pallet balances is deployed does not seem very clean to me.
You can either create a BenchmarkHelper trait with a Currency or Fungible config item and then have that feature-gated in the main config, or require it here.
Alternatively the BenchmarkHelper trait can also just have a fund_account function, since that is the only thing that it needs to do. Not sure.

Copy link
Member

Choose a reason for hiding this comment

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

PS what Muharem wrote about Consideration::ensure_successful is better and exactly what it is intended for.

use frame_system::pallet_prelude::*;

#[pallet::pallet]
pub struct Pallet<T>(_);

/// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
pub mod config_preludes {
Copy link
Member

Choose a reason for hiding this comment

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

🙏 thanks for adding this.

substrate/frame/proxy/src/lib.rs Outdated Show resolved Hide resolved
substrate/frame/proxy/src/lib.rs Outdated Show resolved Hide resolved
T::Currency::unreserve(&spawner, deposit);
if let Some((_, ticket)) = Proxies::<T>::take(&who) {
if let Err(e) = ticket.drop(&spawner) {
log::error!(
Copy link
Member

Choose a reason for hiding this comment

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

Yes, defensive panics only in tests and logs a magic string in production, that we can filter for in our monitoring.
Otherwise this error log would probably get lost.
You can use it like
let _ = ticket.drop(&spawner).defensive_proof("something..");

pending.try_push(announcement).map_err(|_| Error::<T>::TooMany)?;
let new_ticket = ticket.update(
&who,
Footprint::from_parts(pending.len(), Self::announcement_size_bytes()),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Footprint::from_parts(pending.len(), Self::announcement_size_bytes()),
Footprint::from_parts(pending.len(), Announcement::<...>::max_encoded_len()),

Looks like there should be no difference between max and actual encoded len for this struct.

T::AnnouncementConsideration::new(
&who,
Footprint::from_parts(0, Self::announcement_size_bytes()),
)?,
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if i get this? Mabe a case distinction could work, that either updates or creates a new ticket.

Copy link
Author

Choose a reason for hiding this comment

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

Rewritten this section

T::ProxyConsideration::new(
delegator,
Footprint::from_parts(0, Self::proxy_def_size_bytes()),
)?,
Copy link
Member

Choose a reason for hiding this comment

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

I think these intermediary tickets are not so nice, as they are updated anyway. Could either not be created at all, or dropped.

let (_, old_deposit) = Proxies::<T>::take(&delegator);
T::Currency::unreserve(&delegator, old_deposit);
if let Some((_, ticket)) = Proxies::<T>::take(&delegator) {
if let Err(e) = ticket.drop(&delegator) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if let Err(e) = ticket.drop(&delegator) {
let _ = ticket.drop(&delegator).defensive_proof("..");

@@ -200,6 +200,23 @@ where
}
}

/// A storage price modifier that returns zero if number of elements is zero,
Copy link
Member

Choose a reason for hiding this comment

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

Where is this useful? Couldn't there still be a base deposit?

Copy link
Author

Choose a reason for hiding this comment

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

This is the behaviour of Proxy pallet before Consideration, there's no base deposit, if items in footprint is zero then storage price is 0. This is to keep Proxy pallet backwards compatible with this behaviour not to break existing runtimes.

@davidk-pt
Copy link
Author

davidk-pt commented Sep 5, 2024

Here we need a new runtime API, or a pallet view function, that would allow a UI to query how much the deposit would be.
We can go with the runtime API approach, but then it is really hard to get this API integrated across all runtimes..
The PR itself is pretty good, but I think this is tapping into another unsolved problem that we have now, so we should pause and first consolidate on how the broader issue is solved.
I have recently re-summarized the issue at hand here:
https://forum.polkadot.network/t/wasm-view-functions/1045

It does sound like proxy pallet could benefit from the view functions so all users could see their proxy deposit sizes. However, from the storage and implementation perspective, would we need to change anything to create view functions? For me it seems these are independent problems and we could resolve these in the future once view functions for pallets are established. PRs to create view functions would be much smaller this way.

We have a PR to ship the view functions, and the discussion in the forum thread is converging towards using them.

So, in principle, once we have them, we can provide a view fn that returns the deposit amount of a new proxy to be created.

I am a bit hesitant to green-light this PR before the above is done though. Imagine: if DApps rely on ProxyDepositBase (which had #[pallet::constant], which means it is in the metadata), we break things for them once now, and once later when we provide the fix: view functions.

I suggest:

  1. Option 1: Pause this PR until the view fn matter is resolved, make it be a first-time user of the new view fn paradaigm.
  2. Option 2: With #[pallet::extra_constants] we can do this migration, but keep the old values in the metadata. This is a hack, and I am not sure if it would even make sense, because the pallet won't even know the final deposit amount... worth exploring, but I cannot be sure it works.

FWIW, I think pausing the PR is not bad, or anything short of success here, especially in this day and age where we value stability. We can then use the learnings here to shift focus towards merging view functions, then resuming the work here.

Side note: this conversation might be of interest for your learning @davidk-pt :) #3238 (comment)

Okay in this context it makes sense to pause for now, this PR is mostly done just needs few tweaks like view functions, some refactor to benchmarks and so on

@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch from 5f8b6c3 to 6576a7a Compare September 17, 2024 12:35
@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch from 6576a7a to 0332ab4 Compare September 17, 2024 12:36
@davidk-pt davidk-pt force-pushed the davidk/refactor-proxy-pallet-to-use-consideration branch from 322a251 to c680f8d Compare September 20, 2024 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T2-pallets This PR/Issue is related to a particular pallet.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants