Polkadot Release Analysis v0.9.43
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
Tooling Section
First beta release of Asset Transfer API is out. Aiming to provide tools for easily transferring assets across common good parachains.
High Impact
BREAKING - Try-runtime: Use proper error types
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?
- 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> {
- 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 theTryRuntimeError
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
Medium Impact
Staking::{bond, set_controller} to set controllers to stash only.
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 becomeset_controller()
. This call simply sets the controller account to the caller’s stash account, if it is not already. -
bond(controller, value, payee)
has becomebond(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
Why is this important?
This PR does the following:
- adds dispatchables
touch_other
andrefund_other
to the assets pallet which allows the asset class’sFreezer
orAdmin
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’sFreezer
via the new dispatchableblock
). UnlikeFrozen
, 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
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
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
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
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
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