Polkadot Release Analysis v0.9.43

Polkadot Release Analysis v0.9.43

:warning: The following report is not an exhaustive list of changes included in the release, but a set of changes that we felt deserved to be highlighted due to their impact on the Polkadot ecosystem builders.

Please do not stop reading the release notes v0.9.43. This report is complementary to the changelogs, not a replacement.

Highlights are categorized into High Impact, Medium Impact, and Low Impact for ease of navigation.
Also there is a section related to all note worthy changes related to tooling integration.

Help us improve the release analysis by filling out this 6 question survey.

Summary

In this release we are covering Polkadot release v0.9.43. Notable changes include:

  • breaking changes made to the try-runtime feature
  • the removal of CLI options and old macros
  • changes related to asset accounts
  • first steps towards deprecating controller accounts
  • new pallets as well as several other features

Runtimes built on release v0.9.43

  • Rococo v9430
  • Westend v9430
  • Kusama v9430
  • Polkadot v9430

:hammer_and_wrench: Tooling Section

First beta release of Asset Transfer API is out. Aiming to provide tools for easily transferring assets across common good parachains.



:exclamation: High Impact

BREAKING - Try-runtime: Use proper error types

PR: BREAKING - Try-runtime: Use proper error types by Szegoo · Pull Request #13993 · paritytech/substrate · GitHub

Why is this change interesting for builders?

At the moment, all runtime upgrade hooks, which are enabled with try-runtime feature uses &'static str as error type. These hooks are helpful to inspect and compare the runtime state before and after a runtime upgrade for testing purposes but the current error type is not very helpful to handle the errors.

As a part of this PR, a new error type TryRuntimeError has been introduced, which is an alias for DispatchError.

How does this impact the Polkadot builders?

After this PR, &'static str will not be supported as error return type for these hooks. If you are using runtime upgrade hooks, you MUST update the return type, otherwise, this would cause a compilation failure.

How to use?

  1. Please refer below example to update error types
- fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
+ fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
    
- fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
+ fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {

  1. Also from now onwards, you should not use assert!, assert_eq! or similar because code in these macros may panic. instead in case of an error we should return the TryRuntimeError type.

This Cumulus companion PR is a perfect example of how to incorporate this new change.

Polkadot companion PR: #7146
Cumulus companion PR: #2615
Related Issue: #13736


:warning: Medium Impact

Staking::{bond, set_controller} to set controllers to stash only.

PR: Staking::{bond, set_controller} to set controllers to stash only. by rossbulat · Pull Request #14039 · paritytech/substrate · GitHub

Why is this important?

Controller accounts are in the process of being deprecated in favor of proxy accounts.

This PR makes it so it is no longer possible to set a unique address for a stash’s controller. set_controller call logic has been changed to (re)-set the controller of a stash to the stash itself. This call previously accepted a controller argument to set the controller to an account other than the stash itself. This functionality has now been removed, now only setting the controller to the stash, if it is not already.

The bond call no longer takes a controller account as an argument and uses the stash account in its place.

How does this impacts the Polkadot builders?

If you are building any staking UIs, it is important for your team to update your UIs accordingly.

Why is this change interesting for builders?

This change turns off the ability to create new unique stash & controller pairs, aiding in the controller account deprecation and migration to proxy accounts.

How to use?

  • set_controller(controller) has become set_controller(). This call simply sets the controller account to the caller’s stash account, if it is not already.
  • bond(controller, value, payee) has become bond(value, payee). This call now sets the caller as the controller account (same as the stash).

Allow Creation of Asset Accounts That Don’t Exist Yet and Add Blocked Status

PR: Allow Creation of Asset Accounts That Don't Exist Yet and Add `Blocked` Status by joepetrowski · Pull Request #13843 · paritytech/substrate · GitHub

Why is this important?

This PR does the following:

  • adds dispatchables touch_other and refund_other to the assets pallet which allows the asset class’s Freezer or Admin to create an account with zero balance in the asset class by placing a deposit; and to remove/refund.
  • adds a new AccountTouch trait that allows other pallets to touch an account into existence for an asset class
  • adds a new account status of Blocked (invoked by the asset class’s Freezer via the new dispatchable block). Unlike Frozen, which prevents withdrawals from an account, Blocked prevents both withdrawals from and deposits into the blocked account.

How to use?

The new AccountTouch trait that is available to pallets:

/// Trait for creating an asset account with a deposit taken from a designated depositor specified
/// by the client.
pub trait AccountTouch<AssetId, AccountId> {
	/// The type for currency units of the deposit.
	type Balance;

	/// The deposit amount of a native currency required for creating an asset account.
	fn deposit_required() -> Self::Balance;

	/// Create an account for `who` of the `asset` with a deposit taken from the `depositor`.
	fn touch(asset: AssetId, who: AccountId, depositor: AccountId) -> DispatchResult;
}    

An example of the AccountTouch trait implementation can be found in pallet assets:

/// Implements [AccountTouch] trait.
/// Note that a depositor can be any account, without any specific privilege.
/// This implementation is supposed to be used only for creation of system accounts.
impl<T: Config<I>, I: 'static> AccountTouch<T::AssetId, T::AccountId> for Pallet<T, I> {
    type Balance = DepositBalanceOf<T, I>;

    fn deposit_required() -> Self::Balance {
        T::AssetAccountDeposit::get()
    }

    fn touch(asset: T::AssetId, who: T::AccountId, depositor: T::AccountId) -> DispatchResult {
        Self::do_touch(asset, who, depositor, false)
    }
} 

And an example usage of it can be found in pallet asset-conversion:

/// Registry for the assets.
type Assets: Inspect<Self::AccountId, AssetId = Self::AssetId, Balance = Self::AssetBalance>
    + Mutate<Self::AccountId>
    + AccountTouch<Self::AssetId, Self::AccountId>
    + ContainsPair<Self::AssetId, Self::AccountId>;

Create an asset account for who.

pub fn touch_other(origin: OriginFor<T>, id: T::AssetIdParameter, who: AccountIdLookupOf<T>,)

Cumulus Companion PR: #2437


rpc server: break legacy CLI options and remove “backward compatible HTTP server”

PR: https://github.com/paritytech/substrate/pull/13384

Why is this important?
After #12663 was merged the RPC server supports WS/HTTP on the same socket and the HTTP server was kept for backwards compatibility.

This PR removes the HTTP server on port 9933, makes the default RPC port 9944 and removes / renames all websocket / HTTP specific options, as follows:

  • --rpc-max-payload replaced by --rpc-max-request-size and --rpc-max-response-size
  • --ws-external replaced by --rpc-external
  • --unsafe-ws-extneral replaced by --unsafe-rpc-external
  • --ws-port replaced by --rpc-port
  • --ws-max-connections replaced by --rpc-max-connections
  • --rpc-http replaced by --rpc-addr
  • --rpc-ws replaced by --rpc-addr
  • removed --ws-max-out-buffer-capacity
  • removed --ipc-path

XCM remote lock consumers

PR: https://github.com/paritytech/polkadot/pull/6947

Why is this important?

This PR introduces into pallet-xcm Config trait the following types

/// The maximum number of consumers a single remote lock may have.
type MaxRemoteLockConsumers: Get<u32>;
/// The ID type for local consumers of remote locks.
type RemoteLockConsumerIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy;

This allows for partial locking and unlocking of the remote lock as well as extending the lock for a specific user.

RemoteLockedFungibleRecord has been redefined:

- pub struct RemoteLockedFungibleRecord {}

+ pub struct RemoteLockedFungibleRecord<ConsumerIdentifier, MaxConsumers: Get<u32>> {}

The field pub users whitin the previos struct is also substituted:

- pub users: u32,
+ /// Local consumers of the remote lock with a consumer identifier and the amount
+ /// of fungible asset every consumer holds.
+ /// Every consumer can hold up to total amount of the remote lock.
+ pub consumers: BoundedVec<(ConsumerIdentifier, u128), MaxConsumers>,

How does this impacts the Polkadot builders?

The changes concerning RemoteLockedFungibleRecord require that all users of remote locks write migrations of their data to this new storage version.

Cumulus companion PR: #2463


:information_source: Low Impact

NFTs fractionalization

PR: NFTs fractionalization by lana-shanghai · Pull Request #12565 · paritytech/substrate · GitHub

Why is this change interesting for builders?
As a part of this PR, a new pallet, NFT Fractionalization Pallet has been introduced. Using this pallet, one can leverage partial ownership, transfers, and sales, of illiquid assets. This pallet:

  • Takes the ownership of an NFT from the pallet-nfts.
  • It allows uers to lock the NFT, they own and create and mint a new fungible asset in the pallet-assets
  • It allows user to burn the total issuance of the fungible asset and to unlock the NFT into their account.

Cumulus companion PR: #2600

Assets: impl ContainsPair for asset and account IDs

PR: Assets: impl ContainsPair for asset and account IDs by muharem · Pull Request #14119 · paritytech/substrate · GitHub

Why is this change interesting for builders?

This PR introduced the implementation of ContainsPair trait in Assets Pallet. This will check whether a specific account exists for a given asset ID and account address.

How to use?

If you are using Assets pallet in your pallet you can have something like below:

type Assets: Inspect<Self::AccountId, AssetId = Self::AssetId, Balance = Self::AssetBalance>
			+ Mutate<Self::AccountId>
			+ ContainsPair<Self::AssetId, Self::AccountId>;
    
// You can call its contains method
if T::Assets::contains(&asset_id, &account_address) {
    // Write your code
}

For more detailed example, you can also refer to Asset-conversion pallet.

add swapped event to registrar

PR: https://github.com/paritytech/polkadot/pull/5990

Why is this important?

Before this PR there were no events emitted when a parachain swapped with another parachain.

This PR introduces a Swapped event:

Swapped { para_id: ParaId, other_id: ParaId },

How does this impacts the Polkadot builders?

Builders can now have confirmation through events that a parachain has swapped with another parachain.

Improve handling of unset StorageVersion

PR: https://github.com/paritytech/substrate/pull/13417

Why is this change interesting for builders?

If the StorageVersion is not set properly, it may lead to potential issues with migrations because currently we assume that on_chain_storage_version() == current_storage_version() for all pallets.

This PR makes the compilation fail if we forget to set the storage version in a pallet and do on_chain_storage_version() == current_storage_version(). This PR also checks in post_upgrade that the storage version on chain matches with the current storage version. This will make sure that no migration has been missed.

How does this impact the Polkadot builders?

If your pallet doesn’t have the proper StorageVersion set on chain, try-runtime tests may start failing. To fix this:

fn on_runtime_upgrade() {
    StorageVersion::new(EXPECTED_VERSION).put::<Pallet_That_Is_failing>();
}

Related Issue: #13062

AccountTouch trait: deposit_required accepts asset id

PR: AccountTouch trait: deposit_required accepts asset id by muharem · Pull Request #14147 · paritytech/substrate · GitHub

Why is this important?

This PR adds AssetId to deposit_required which allows to specify the asset id of the account to be created which can be used to determine the required deposit for account creation for that asset:

/// Trait for creating an asset account with a deposit taken from a designated depositor specified
/// by the client.
pub trait AccountTouch<AssetId, AccountId> {
	/// The type for currency units of the deposit.
	type Balance;

	/// The deposit amount of a native currency required for creating an account of the `asset`.
	fn deposit_required(asset: AssetId) -> Self::Balance;

	/// Create an account for `who` of the `asset` with a deposit taken from the `depositor`.
	fn touch(asset: AssetId, who: AccountId, depositor: AccountId) -> DispatchResult;
}

Deprecate Pallet decl_* Macros

PR: Deprecate Pallet `decl_*` Macros by ggwpez · Pull Request #13705 · paritytech/substrate · GitHub

Why is this change interesting for builders?

As a part of this PR, all decl_* macros(decl_module, decl_storage, decl_error and decl_event) have been deprecated and will be removed soon. If you are using these deprecated macros in your application, you should start using #[frame_support::pallet] attribute.

Related Issue: #12248
Depends on: #12445, #12401


Prepare sc-network for ProtocolController/NotificationService

PR: https://github.com/paritytech/substrate/pull/14080

Why is this important?

In preparation for an upcoming refactor of the notification protocol subsystem, the initialization process of network protocols have been modified. A new network configuration object has been introduced which allows storing consumable, networking-related configuration before build_network() is called, providing a more flexible way of initializing protocols.

How does this impacts the Polkadot builders?

Moreover, these changes include FullNetworkConfiguration as the store for protocol-related configuration which is consumable by sc-network, allowing protocols to be fully initialized before the network is started. The net_config of your chain might need a few modifications in your node/service.rs file. For examples, please refer to the companion PRs.

Polkadot commpanion PR: #7184
Cumulus companion PR: #2526


Adds ability to use default hasher in dev_mode for explicit key binding

PR: https://github.com/paritytech/substrate/pull/14164

Why is this important?

This PR adds a default hasher (Blake2_128Concat) todev_mode.

Why is this change interesting for builders?

One more feature added to dev_mode. Using dev_mode helps focus on core pallet logic, quickly create prototypes, and overall speed up development.

How to use?

When in dev_mode the syntax is as follows:

#[pallet::storage]
pub type Baz<T: Config> = StorageMap<Key = T::AccountId, Value = T::Balance>; 

When not in dev_mode the above will throw an error.

Keep in mind dev_mode is for development puposes and not meant to be used in production.

Related Issue: #14118

Actually respect locks of zero

PR: Actually respect locks of zero by gavofyork · Pull Request #14144 · paritytech/substrate · GitHub

Why is this important?

Previously, if set_lock was called with an amount of zero, it would result in a no-op. With this PR, if the balance is zero then Self::remove_lock(id, who); is called:

- // Is a no-op if lock amount is zero or `reasons` `is_none()`.
// Set or alter a lock on the balance of `who`
fn set_lock(...) {
-    if amount.is_zero() || reasons.is_empty() {
+    if reasons.is_empty() || amount.is_zero() {
+        Self::remove_lock(id, who);
        return
    }

How to use?

#[test]
fn set_lock_with_amount_zero_removes_lock() {
	ExtBuilder::default()
		.existential_deposit(1)
		.monied(true)
		.build_and_execute_with(|| {
			Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all());
			Balances::set_lock(ID_1, &1, 0, WithdrawReasons::all());
			assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
		});
} 

[Feature] XCM-Emulator

PR: https://github.com/paritytech/cumulus/pull/2447

Why is this important?

XCM-Emulator is a tool to emulate XCM program execution using pre-configured runtimes, including those used to run on live networks, such as Kusama, Polkadot, Statemine, etc.
This allows for testing cross-chain message passing, verifying outcomes, weights and side-effects.

This tool allows for multi-network declaration via decl_test_relay_chain, decl_test_parachain and decl_test_network.

Handy helper functions within_threshold & weight_within_threshold for events assessment and assert_expected_events macro that helps to check received events with pattern matching and conditional assertion of theirs inner fields. Example.


Add Foreign Assets to Statemint

PR: Add Foreign Assets to Statemint by joepetrowski · Pull Request #2540 · paritytech/cumulus · GitHub

Why is this important?

Following the steps taken in #2133 and with its audit finished, foreign assets are now available in Polkadot’s Asset Hub (Statemint).

Why is this change interesting for builders?

This allows for bridges to represent assets from other networks as well as other parachains to represent their assets.

[xcm] Foreign global consensus parachain LocationToAccountId converter

PR: [xcm] Foreign global consensus parachain LocationToAccountId converter by bkontur · Pull Request #7016 · paritytech/polkadot · GitHub

Why is this change interesting for builders?

As a part of this PR, a converter has been introduced in XCM, which converts a location which is a top-level parachain into a 32-byte AccountId. This AccountId will always be the same for the same parachain index under the same Relay-chain, regardless of the relative security of this Relay-chain compared to the local chain.

This will be used for sovereign accounts of parachain represented on different global consensus. You can find more details in this polkadot forum discussion.

contracts: Make Origin information available

PR: contracts: Make Origin information available by juangirini · Pull Request #13708 · paritytech/substrate · GitHub

Why is this important?
This PR implements a new Origin enum for pallet-contracts with, at the moment, two accepted origins: Signed(T::AccountId) and Root.

ensure_origin has been implemented in Invokables trait, which can be used to to check whether the origin is allow to invoke.

ensure_signed has been removed from the dispatchables call, instantiate and instantiate_with_code, and replaced with Invokables::ensure_origin. Per the PR description, as a result PostDispatchInfo.actual_weight is now Some(x) instead of None, that was before.

How does this impacts the Polkadot builders?

As for now, when the origin is Root there is not any charge or refund of storage deposit.

Your friendly neighborhood Polkadot Release Analysis team,
@alejandro @ayush.mishra @bruno

4 Likes

Thank you guys this is great! Much needed… kinda necessary? Thank you.

Appendix:

Remove the Copy bound on AssetId

PR: Remove the `Copy` bound on `AssetId` by koute · Pull Request #14158 · paritytech/substrate · GitHub
Related: https://github.com/paritytech/polkadot/pull/7236

This PR is removing the Copy trait from the AssetId type due to size optimization in XCM messages. Please be mindful about this change since it will have many implications in pallets relying on traits like the Inspect for example.

  error[E0382]: use of moved value: `asset_id`
     |
  93 |             ensure!(T::Assets::asset_exists(asset_id), Error::<T>::AssetDoesNotExist);
     |                                             -------- value moved here
  ...
  97 |                 !AssetIdMultiLocation::<T>::contains_key(asset_id),
     |                                                          ^^^^^^^^ value used here after move
     |
     = note: move occurs because `asset_id` has type `<<T as pallet::Config>::Assets as frame_support::traits::fungibles::Inspect<<T as frame_system::Config>::AccountId>>::AssetId`, which does not implement the `Copy` trait

As it is mentioned in https://github.com/paritytech/polkadot/pull/7236, now those values have to be clone()d

4 Likes

Appendix for Polkadot Release Analysis v0.9.43:

After the upgrade to v0.9.43, frame_system can no longer be benchmarked due to an issue while running benchmarks with the set_code extrinsic.

Sample output

2023-07-25 13:37:52 assembling new collators for new session 1 at #0
2023-07-25 13:37:52 Starting benchmark: frame_system::remark
2023-07-25 13:37:54 Starting benchmark: frame_system::remark_with_event
2023-07-25 13:37:58 Running  benchmark: frame_system.remark_with_event(1 args) 31/50 1/1
2023-07-25 13:38:02 Starting benchmark: frame_system::set_heap_pages
2023-07-25 13:38:02 Starting benchmark: frame_system::set_code
Error: Input("Benchmark frame_system::set_code failed: ValidationDataNotAvailable")

Cumulus

Cumulus seems to have solved this issue in this PR.

However, this commit does not seem to have been included in the polkadot-v0.9.43 branch. Furthermore, it seems Cumulus did not benchmark frame_system in this version.

2 Likes