diff --git a/404.html b/404.html index 829c42d..9a0c455 100644 --- a/404.html +++ b/404.html @@ -91,7 +91,7 @@ diff --git a/approved/0001-agile-coretime.html b/approved/0001-agile-coretime.html index 5425470..85ba170 100644 --- a/approved/0001-agile-coretime.html +++ b/approved/0001-agile-coretime.html @@ -90,7 +90,7 @@ diff --git a/approved/0005-coretime-interface.html b/approved/0005-coretime-interface.html index d775703..de7eb21 100644 --- a/approved/0005-coretime-interface.html +++ b/approved/0005-coretime-interface.html @@ -90,7 +90,7 @@ diff --git a/approved/0007-system-collator-selection.html b/approved/0007-system-collator-selection.html index 6699cb1..62416e8 100644 --- a/approved/0007-system-collator-selection.html +++ b/approved/0007-system-collator-selection.html @@ -90,7 +90,7 @@ diff --git a/approved/0008-parachain-bootnodes-dht.html b/approved/0008-parachain-bootnodes-dht.html index 206b74f..ff25c20 100644 --- a/approved/0008-parachain-bootnodes-dht.html +++ b/approved/0008-parachain-bootnodes-dht.html @@ -90,7 +90,7 @@ diff --git a/approved/0010-burn-coretime-revenue.html b/approved/0010-burn-coretime-revenue.html index 0ae0529..cd9ed04 100644 --- a/approved/0010-burn-coretime-revenue.html +++ b/approved/0010-burn-coretime-revenue.html @@ -90,7 +90,7 @@ diff --git a/approved/0012-process-for-adding-new-collectives.html b/approved/0012-process-for-adding-new-collectives.html index 72c069d..22dc412 100644 --- a/approved/0012-process-for-adding-new-collectives.html +++ b/approved/0012-process-for-adding-new-collectives.html @@ -90,7 +90,7 @@ diff --git a/approved/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html b/approved/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html index 995b33e..6e63c65 100644 --- a/approved/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html +++ b/approved/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html @@ -90,7 +90,7 @@ diff --git a/approved/0014-improve-locking-mechanism-for-parachains.html b/approved/0014-improve-locking-mechanism-for-parachains.html index 5b8b69a..4dd4870 100644 --- a/approved/0014-improve-locking-mechanism-for-parachains.html +++ b/approved/0014-improve-locking-mechanism-for-parachains.html @@ -90,7 +90,7 @@ diff --git a/approved/0022-adopt-encointer-runtime.html b/approved/0022-adopt-encointer-runtime.html index e1536f9..e1cdb38 100644 --- a/approved/0022-adopt-encointer-runtime.html +++ b/approved/0022-adopt-encointer-runtime.html @@ -90,7 +90,7 @@ diff --git a/approved/0026-sassafras-consensus.html b/approved/0026-sassafras-consensus.html index 3d8facc..7f38383 100644 --- a/approved/0026-sassafras-consensus.html +++ b/approved/0026-sassafras-consensus.html @@ -90,7 +90,7 @@ diff --git a/approved/0032-minimal-relay.html b/approved/0032-minimal-relay.html index a81dfc9..5bf97ef 100644 --- a/approved/0032-minimal-relay.html +++ b/approved/0032-minimal-relay.html @@ -90,7 +90,7 @@ diff --git a/approved/0042-extrinsics-state-version.html b/approved/0042-extrinsics-state-version.html index e70b4d1..29d519f 100644 --- a/approved/0042-extrinsics-state-version.html +++ b/approved/0042-extrinsics-state-version.html @@ -90,7 +90,7 @@ diff --git a/approved/0043-storage-proof-size-hostfunction.html b/approved/0043-storage-proof-size-hostfunction.html index 1ad8975..cdaba6e 100644 --- a/approved/0043-storage-proof-size-hostfunction.html +++ b/approved/0043-storage-proof-size-hostfunction.html @@ -90,7 +90,7 @@ diff --git a/approved/0045-nft-deposits-asset-hub.html b/approved/0045-nft-deposits-asset-hub.html index ad80677..ee3a1e0 100644 --- a/approved/0045-nft-deposits-asset-hub.html +++ b/approved/0045-nft-deposits-asset-hub.html @@ -90,7 +90,7 @@ diff --git a/approved/0047-assignment-of-availability-chunks.html b/approved/0047-assignment-of-availability-chunks.html index 631840b..3b11b39 100644 --- a/approved/0047-assignment-of-availability-chunks.html +++ b/approved/0047-assignment-of-availability-chunks.html @@ -90,7 +90,7 @@ diff --git a/approved/0048-session-keys-runtime-api.html b/approved/0048-session-keys-runtime-api.html index 1db54e4..475de23 100644 --- a/approved/0048-session-keys-runtime-api.html +++ b/approved/0048-session-keys-runtime-api.html @@ -90,7 +90,7 @@ diff --git a/approved/0050-fellowship-salaries.html b/approved/0050-fellowship-salaries.html index 6033f81..fee6da1 100644 --- a/approved/0050-fellowship-salaries.html +++ b/approved/0050-fellowship-salaries.html @@ -90,7 +90,7 @@ diff --git a/approved/0056-one-transaction-per-notification.html b/approved/0056-one-transaction-per-notification.html index b849ef0..0ddb192 100644 --- a/approved/0056-one-transaction-per-notification.html +++ b/approved/0056-one-transaction-per-notification.html @@ -90,7 +90,7 @@ diff --git a/approved/0059-nodes-capabilities-discovery.html b/approved/0059-nodes-capabilities-discovery.html index 7a0f326..f325b4e 100644 --- a/approved/0059-nodes-capabilities-discovery.html +++ b/approved/0059-nodes-capabilities-discovery.html @@ -90,7 +90,7 @@ diff --git a/approved/0078-merkleized-metadata.html b/approved/0078-merkleized-metadata.html index 7d047ad..0b1700a 100644 --- a/approved/0078-merkleized-metadata.html +++ b/approved/0078-merkleized-metadata.html @@ -90,7 +90,7 @@ diff --git a/approved/0084-general-transaction-extrinsic-format.html b/approved/0084-general-transaction-extrinsic-format.html index 2474994..7e1529d 100644 --- a/approved/0084-general-transaction-extrinsic-format.html +++ b/approved/0084-general-transaction-extrinsic-format.html @@ -90,7 +90,7 @@ diff --git a/approved/0091-dht-record-creation-time.html b/approved/0091-dht-record-creation-time.html index ade3d52..62f27c0 100644 --- a/approved/0091-dht-record-creation-time.html +++ b/approved/0091-dht-record-creation-time.html @@ -90,7 +90,7 @@ diff --git a/approved/0097-unbonding_queue.html b/approved/0097-unbonding_queue.html index 6476237..8042c9b 100644 --- a/approved/0097-unbonding_queue.html +++ b/approved/0097-unbonding_queue.html @@ -90,7 +90,7 @@ diff --git a/approved/0099-transaction-extension-version.html b/approved/0099-transaction-extension-version.html index 46d85cf..6a952a5 100644 --- a/approved/0099-transaction-extension-version.html +++ b/approved/0099-transaction-extension-version.html @@ -90,7 +90,7 @@ diff --git a/approved/0100-xcm-multi-type-asset-transfer.html b/approved/0100-xcm-multi-type-asset-transfer.html index f0bd61e..bb4ec7b 100644 --- a/approved/0100-xcm-multi-type-asset-transfer.html +++ b/approved/0100-xcm-multi-type-asset-transfer.html @@ -90,7 +90,7 @@ diff --git a/approved/0101-xcm-transact-remove-max-weight-param.html b/approved/0101-xcm-transact-remove-max-weight-param.html index ae5f6b5..b50c497 100644 --- a/approved/0101-xcm-transact-remove-max-weight-param.html +++ b/approved/0101-xcm-transact-remove-max-weight-param.html @@ -90,7 +90,7 @@ diff --git a/approved/0103-introduce-core-index-commitment.html b/approved/0103-introduce-core-index-commitment.html index 092403c..66d9216 100644 --- a/approved/0103-introduce-core-index-commitment.html +++ b/approved/0103-introduce-core-index-commitment.html @@ -90,7 +90,7 @@ diff --git a/approved/0105-xcm-improved-fee-mechanism.html b/approved/0105-xcm-improved-fee-mechanism.html index f1f2aed..afec7ea 100644 --- a/approved/0105-xcm-improved-fee-mechanism.html +++ b/approved/0105-xcm-improved-fee-mechanism.html @@ -90,7 +90,7 @@ diff --git a/approved/0107-xcm-execution-hints.html b/approved/0107-xcm-execution-hints.html index f112bcf..4b2db96 100644 --- a/approved/0107-xcm-execution-hints.html +++ b/approved/0107-xcm-execution-hints.html @@ -90,7 +90,7 @@ diff --git a/approved/0108-xcm-remove-testnet-ids.html b/approved/0108-xcm-remove-testnet-ids.html index 414de0c..333ca05 100644 --- a/approved/0108-xcm-remove-testnet-ids.html +++ b/approved/0108-xcm-remove-testnet-ids.html @@ -90,7 +90,7 @@ @@ -245,7 +245,7 @@ using NetworkId::ByGenesis.

- @@ -259,7 +259,7 @@ using NetworkId::ByGenesis.

- diff --git a/index.html b/index.html index 03b3db3..9a56fa6 100644 --- a/index.html +++ b/index.html @@ -90,7 +90,7 @@ diff --git a/introduction.html b/introduction.html index 03b3db3..9a56fa6 100644 --- a/introduction.html +++ b/introduction.html @@ -90,7 +90,7 @@ diff --git a/print.html b/print.html index 61986b3..d8d497d 100644 --- a/print.html +++ b/print.html @@ -91,7 +91,7 @@ @@ -386,2720 +386,6 @@ At this point, we compute $\beta\prime_w = \sum_v \beta\prime_{w,v}$ on-chain fo

Synthetic parachain flag

Any rewards protocol could simply be "out voted" by too many slow validators: An increase the number of parachain cores increases more workload, but this creates no-shows if too few validators could handle this workload.

We could add a synthetic parachain flag, only settable by governance, which treats no-shows as positive approval votes for that parachain, but without adding rewards. We should never enable this for real parachains, only for synthetic ones like gluttons. We should not enable the synthetic parachain flag long-term even for gluttonsm, because validators could easily modify their code. Yet, synthetic approval checks might enable pushing the hardware upgrades more agressively over the short-term.

-

(source)

-

Table of Contents

- -

RFC-0004: Remove the host-side runtime memory allocator

-
- - - -
Start Date2023-07-04
DescriptionUpdate the runtime-host interface to no longer make use of a host-side allocator
AuthorsPierre Krieger
-
-

Summary

-

Update the runtime-host interface to no longer make use of a host-side allocator.

-

Motivation

-

The heap allocation of the runtime is currently controlled by the host using a memory allocator on the host side.

-

The API of many host functions consists in allocating a buffer. For example, when calling ext_hashing_twox_256_version_1, the host allocates a 32 bytes buffer using the host allocator, and returns a pointer to this buffer to the runtime. The runtime later has to call ext_allocator_free_version_1 on this pointer in order to free the buffer.

-

Even though no benchmark has been done, it is pretty obvious that this design is very inefficient. To continue with the example of ext_hashing_twox_256_version_1, it would be more efficient to instead write the output hash to a buffer that was allocated by the runtime on its stack and passed by pointer to the function. Allocating a buffer on the stack in the worst case scenario simply consists in decreasing a number, and in the best case scenario is free. Doing so would save many Wasm memory reads and writes by the allocator, and would save a function call to ext_allocator_free_version_1.

-

Furthermore, the existence of the host-side allocator has become questionable over time. It is implemented in a very naive way, and for determinism and backwards compatibility reasons it needs to be implemented exactly identically in every client implementation. Runtimes make substantial use of heap memory allocations, and each allocation needs to go twice through the runtime <-> host boundary (once for allocating and once for freeing). Moving the allocator to the runtime side, while it would increase the size of the runtime, would be a good idea. But before the host-side allocator can be deprecated, all the host functions that make use of it need to be updated to not use it.

-

Stakeholders

-

No attempt was made at convincing stakeholders.

-

Explanation

-

New host functions

-

This section contains a list of new host functions to introduce.

-
(func $ext_storage_read_version_2
-    (param $key i64) (param $value_out i64) (param $offset i32) (result i64))
-(func $ext_default_child_storage_read_version_2
-    (param $child_storage_key i64) (param $key i64) (param $value_out i64)
-    (param $offset i32) (result i64))
-
-

The signature and behaviour of ext_storage_read_version_2 and ext_default_child_storage_read_version_2 is identical to their version 1 counterparts, but the return value has a different meaning. -The new functions directly return the number of bytes that were written in the value_out buffer. If the entry doesn't exist, a value of -1 is returned. Given that the host must never write more bytes than the size of the buffer in value_out, and that the size of this buffer is expressed as a 32 bits number, a 64bits value of -1 is not ambiguous.

-

The runtime execution stops with an error if value_out is outside of the range of the memory of the virtual machine, even if the size of the buffer is 0 or if the amount of data to write would be 0 bytes.

-
(func $ext_storage_next_key_version_2
-    (param $key i64) (param $out i64) (return i32))
-(func $ext_default_child_storage_next_key_version_2
-    (param $child_storage_key i64) (param $key i64) (param $out i64) (return i32))
-
-

The behaviour of these functions is identical to their version 1 counterparts. -Instead of allocating a buffer, writing the next key to it, and returning a pointer to it, the new version of these functions accepts an out parameter containing a pointer-size to the memory location where the host writes the output. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine, even if the function wouldn't write anything to out. -These functions return the size, in bytes, of the next key, or 0 if there is no next key. If the size of the next key is larger than the buffer in out, the bytes of the key that fit the buffer are written to out and any extra byte that doesn't fit is discarded.

-

Some notes:

- -
(func $ext_hashing_keccak_256_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_keccak_512_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_sha2_256_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_blake2_128_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_blake2_256_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_twox_64_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_twox_128_version_2
-    (param $data i64) (param $out i32))
-(func $ext_hashing_twox_256_version_2
-    (param $data i64) (param $out i32))
-(func $ext_trie_blake2_256_root_version_3
-    (param $data i64) (param $version i32) (param $out i32))
-(func $ext_trie_blake2_256_ordered_root_version_3
-    (param $data i64) (param $version i32) (param $out i32))
-(func $ext_trie_keccak_256_root_version_3
-    (param $data i64) (param $version i32) (param $out i32))
-(func $ext_trie_keccak_256_ordered_root_version_3
-    (param $data i64) (param $version i32) (param $out i32))
-(func $ext_default_child_storage_root_version_3
-    (param $child_storage_key i64) (param $out i32))
-(func $ext_crypto_ed25519_generate_version_2
-    (param $key_type_id i32) (param $seed i64) (param $out i32))
-(func $ext_crypto_sr25519_generate_version_2
-    (param $key_type_id i32) (param $seed i64) (param $out i32) (return i32))
-(func $ext_crypto_ecdsa_generate_version_2
-    (param $key_type_id i32) (param $seed i64) (param $out i32) (return i32))
-
-

The behaviour of these functions is identical to their version 1 or version 2 counterparts. Instead of allocating a buffer, writing the output to it, and returning a pointer to it, the new version of these functions accepts an out parameter containing the memory location where the host writes the output. The output is always of a size known at compilation time. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine.

-
(func $ext_default_child_storage_root_version_3
-    (param $child_storage_key i64) (param $out i32))
-(func $ext_storage_root_version_3
-    (param $out i32))
-
-

The behaviour of these functions is identical to their version 1 and version 2 counterparts. Instead of allocating a buffer, writing the output to it, and returning a pointer to it, the new versions of these functions accepts an out parameter containing the memory location where the host writes the output. The output is always of a size known at compilation time. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine.

-

I have taken the liberty to take the version 1 of these functions as a base rather than the version 2, as a PPP deprecating the version 2 of these functions has previously been accepted: https://github.com/w3f/PPPs/pull/6.

-
(func $ext_storage_clear_prefix_version_3
-    (param $prefix i64) (param $limit i64) (param $removed_count_out i32)
-    (return i32))
-(func $ext_default_child_storage_clear_prefix_version_3
-    (param $child_storage_key i64) (param $prefix i64)
-    (param $limit i64)  (param $removed_count_out i32) (return i32))
-(func $ext_default_child_storage_kill_version_4
-    (param $child_storage_key i64) (param $limit i64)
-    (param $removed_count_out i32) (return i32))
-
-

The behaviour of these functions is identical to their version 2 and 3 counterparts. Instead of allocating a buffer, writing the output to it, and returning a pointer to it, the version 3 and 4 of these functions accepts a removed_count_out parameter containing the memory location to a 8 bytes buffer where the host writes the number of keys that were removed in little endian. The runtime execution stops with an error if removed_count_out is outside of the range of the memory of the virtual machine. The functions return 1 to indicate that there are keys remaining, and 0 to indicate that all keys have been removed.

-

Note that there is an alternative proposal to add new host functions with the same names: https://github.com/w3f/PPPs/pull/7. This alternative doesn't conflict with this one except for the version number. One proposal or the other will have to use versions 4 and 5 rather than 3 and 4.

-
(func $ext_crypto_ed25519_sign_version_2
-    (param $key_type_id i32) (param $key i32) (param $msg i64) (param $out i32) (return i32))
-(func $ext_crypto_sr25519_sign_version_2
-    (param $key_type_id i32) (param $key i32) (param $msg i64) (param $out i32) (return i32))
-func $ext_crypto_ecdsa_sign_version_2
-    (param $key_type_id i32) (param $key i32) (param $msg i64) (param $out i32) (return i32))
-(func $ext_crypto_ecdsa_sign_prehashed_version_2
-    (param $key_type_id i32) (param $key i32) (param $msg i64) (param $out i32) (return i64))
-
-

The behaviour of these functions is identical to their version 1 counterparts. The new versions of these functions accept an out parameter containing the memory location where the host writes the signature. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine, even if the function wouldn't write anything to out. The signatures are always of a size known at compilation time. On success, these functions return 0. If the public key can't be found in the keystore, these functions return 1 and do not write anything to out.

-

Note that the return value is 0 on success and 1 on failure, while the previous version of these functions write 1 on success (as it represents a SCALE-encoded Some) and 0 on failure (as it represents a SCALE-encoded None). Returning 0 on success and non-zero on failure is consistent with common practices in the C programming language and is less surprising than the opposite.

-
(func $ext_crypto_secp256k1_ecdsa_recover_version_3
-    (param $sig i32) (param $msg i32) (param $out i32) (return i64))
-(func $ext_crypto_secp256k1_ecdsa_recover_compressed_version_3
-    (param $sig i32) (param $msg i32) (param $out i32) (return i64))
-
-

The behaviour of these functions is identical to their version 2 counterparts. The new versions of these functions accept an out parameter containing the memory location where the host writes the signature. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine, even if the function wouldn't write anything to out. The signatures are always of a size known at compilation time. On success, these functions return 0. On failure, these functions return a non-zero value and do not write anything to out.

-

The non-zero value written on failure is:

- -

These values are equal to the values returned on error by the version 2 (see https://spec.polkadot.network/chap-host-api#defn-ecdsa-verify-error), but incremented by 1 in order to reserve 0 for success.

-
(func $ext_crypto_ed25519_num_public_keys_version_1
-    (param $key_type_id i32) (return i32))
-(func $ext_crypto_ed25519_public_key_version_2
-    (param $key_type_id i32) (param $key_index i32) (param $out i32))
-(func $ext_crypto_sr25519_num_public_keys_version_1
-    (param $key_type_id i32) (return i32))
-(func $ext_crypto_sr25519_public_key_version_2
-    (param $key_type_id i32) (param $key_index i32) (param $out i32))
-(func $ext_crypto_ecdsa_num_public_keys_version_1
-    (param $key_type_id i32) (return i32))
-(func $ext_crypto_ecdsa_public_key_version_2
-    (param $key_type_id i32) (param $key_index i32) (param $out i32))
-
-

The functions superceded the ext_crypto_ed25519_public_key_version_1, ext_crypto_sr25519_public_key_version_1, and ext_crypto_ecdsa_public_key_version_1 host functions.

-

Instead of calling ext_crypto_ed25519_public_key_version_1 in order to obtain the list of all keys at once, the runtime should instead call ext_crypto_ed25519_num_public_keys_version_1 in order to obtain the number of public keys available, then ext_crypto_ed25519_public_key_version_2 repeatedly. -The ext_crypto_ed25519_public_key_version_2 function writes the public key of the given key_index to the memory location designated by out. The key_index must be between 0 (included) and n (excluded), where n is the value returned by ext_crypto_ed25519_num_public_keys_version_1. Execution must trap if n is out of range.

-

The same explanations apply for ext_crypto_sr25519_public_key_version_1 and ext_crypto_ecdsa_public_key_version_1.

-

Host implementers should be aware that the list of public keys (including their ordering) must not change while the runtime is running. This is most likely done by copying the list of all available keys either at the start of the execution or the first time the list is accessed.

-
(func $ext_offchain_http_request_start_version_2
-  (param $method i64) (param $uri i64) (param $meta i64) (result i32))
-
-

The behaviour of this function is identical to its version 1 counterpart. Instead of allocating a buffer, writing the request identifier in it, and returning a pointer to it, the version 2 of this function simply returns the newly-assigned identifier to the HTTP request. On failure, this function returns -1. An identifier of -1 is invalid and is reserved to indicate failure.

-
(func $ext_offchain_http_request_write_body_version_2
-  (param $method i64) (param $uri i64) (param $meta i64) (result i32))
-(func $ext_offchain_http_response_read_body_version_2
-  (param $request_id i32) (param $buffer i64) (param $deadline i64) (result i64))
-
-

The behaviour of these functions is identical to their version 1 counterpart. Instead of allocating a buffer, writing two bytes in it, and returning a pointer to it, the new version of these functions simply indicates what happened:

- -

These values are equal to the values returned on error by the version 1 (see https://spec.polkadot.network/chap-host-api#defn-http-error), but tweaked in order to reserve positive numbers for success.

-

When it comes to ext_offchain_http_response_read_body_version_2, the host implementers must not read too much data at once in order to not create ambiguity in the returned value. Given that the size of the buffer is always inferior or equal to 4 GiB, this is not a problem.

-
(func $ext_offchain_http_response_wait_version_2
-    (param $ids i64) (param $deadline i64) (param $out i32))
-
-

The behaviour of this function is identical to its version 1 counterpart. Instead of allocating a buffer, writing the output to it, and returning a pointer to it, the new version of this function accepts an out parameter containing the memory location where the host writes the output. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine.

-

The encoding of the response code is also modified compared to its version 1 counterpart and each response code now encodes to 4 little endian bytes as described below:

- -

The buffer passed to out must always have a size of 4 * n where n is the number of elements in the ids.

-
(func $ext_offchain_http_response_header_name_version_1
-    (param $request_id i32) (param $header_index i32) (param $out i64) (result i64))
-(func $ext_offchain_http_response_header_value_version_1
-    (param $request_id i32) (param $header_index i32) (param $out i64) (result i64))
-
-

These functions supercede the ext_offchain_http_response_headers_version_1 host function.

-

Contrary to ext_offchain_http_response_headers_version_1, only one header indicated by header_index can be read at a time. Instead of calling ext_offchain_http_response_headers_version_1 once, the runtime should call ext_offchain_http_response_header_name_version_1 and ext_offchain_http_response_header_value_version_1 multiple times with an increasing header_index, until a value of -1 is returned.

-

These functions accept an out parameter containing a pointer-size to the memory location where the header name or value should be written. The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine, even if the function wouldn't write anything to out.

-

These functions return the size, in bytes, of the header name or header value. If request doesn't exist or is in an invalid state (as documented for ext_offchain_http_response_headers_version_1) or the header_index is out of range, a value of -1 is returned. Given that the host must never write more bytes than the size of the buffer in out, and that the size of this buffer is expressed as a 32 bits number, a 64bits value of -1 is not ambiguous.

-

If the buffer in out is too small to fit the entire header name of value, only the bytes that fit are written and the rest are discarded.

-
(func $ext_offchain_submit_transaction_version_2
-    (param $data i64) (return i32))
-(func $ext_offchain_http_request_add_header_version_2
-    (param $request_id i32) (param $name i64) (param $value i64) (result i32))
-
-

Instead of allocating a buffer, writing 1 or 0 in it, and returning a pointer to it, the version 2 of these functions return 0 or 1, where 0 indicates success and 1 indicates failure. The runtime must interpret any non-0 value as failure, but the client must always return 1 in case of failure.

-
(func $ext_offchain_local_storage_read_version_1
-    (param $kind i32) (param $key i64) (param $value_out i64) (param $offset i32) (result i64))
-
-

This function supercedes the ext_offchain_local_storage_get_version_1 host function, and uses an API and logic similar to ext_storage_read_version_2.

-

It reads the offchain local storage key indicated by kind and key starting at the byte indicated by offset, and writes the value to the pointer-size indicated by value_out.

-

The function returns the number of bytes that were written in the value_out buffer. If the entry doesn't exist, a value of -1 is returned. Given that the host must never write more bytes than the size of the buffer in value_out, and that the size of this buffer is expressed as a 32 bits number, a 64bits value of -1 is not ambiguous.

-

The runtime execution stops with an error if value_out is outside of the range of the memory of the virtual machine, even if the size of the buffer is 0 or if the amount of data to write would be 0 bytes.

-
(func $ext_offchain_network_peer_id_version_1
-    (param $out i64))
-
-

This function writes the PeerId of the local node to the memory location indicated by out. A PeerId is always 38 bytes long. -The runtime execution stops with an error if out is outside of the range of the memory of the virtual machine.

-
(func $ext_input_size_version_1
-    (return i64))
-(func $ext_input_read_version_1
-    (param $offset i64) (param $out i64))
-
-

When a runtime function is called, the host uses the allocator to allocate memory within the runtime where to write some input data. These two new host functions provide an alternative way to access the input that doesn't make use of the allocator.

-

The ext_input_size_version_1 host function returns the size in bytes of the input data.

-

The ext_input_read_version_1 host function copies some data from the input data to the memory of the runtime. The offset parameter indicates the offset within the input data where to start copying, and must be inferior or equal to the value returned by ext_input_size_version_1. The out parameter is a pointer-size containing the buffer where to write to. -The runtime execution stops with an error if offset is strictly superior to the size of the input data, or if out is outside of the range of the memory of the virtual machine, even if the amount of data to copy would be 0 bytes.

-

Other changes

-

In addition to the new host functions, this RFC proposes two changes to the runtime-host interface:

- -

All the host functions that are being superceded by new host functions are now considered deprecated and should no longer be used. -The following other host functions are similarly also considered deprecated:

- -

Drawbacks

-

This RFC might be difficult to implement in Substrate due to the internal code design. It is not clear to the author of this RFC how difficult it would be.

-

Prior Art

-

The API of these new functions was heavily inspired by API used by the C programming language.

-

Unresolved Questions

-

The changes in this RFC would need to be benchmarked. This involves implementing the RFC and measuring the speed difference.

-

It is expected that most host functions are faster or equal speed to their deprecated counterparts, with the following exceptions:

- -

Future Possibilities

-

After this RFC, we can remove from the source code of the host the allocator altogether in a future version, by removing support for all the deprecated host functions. -This would remove the possibility to synchronize older blocks, which is probably controversial and requires a some preparations that are out of scope of this RFC.

-

(source)

-

Table of Contents

- -

RFC-0006: Dynamic Pricing for Bulk Coretime Sales

-
- - - - -
Start DateJuly 09, 2023
DescriptionA dynamic pricing model to adapt the regular price for bulk coretime sales
AuthorsTommi Enenkel (Alice und Bob)
LicenseMIT
-
-

Summary

-

This RFC proposes a dynamic pricing model for the sale of Bulk Coretime on the Polkadot UC. The proposed model updates the regular price of cores for each sale period, by taking into account the number of cores sold in the previous sale, as well as a limit of cores and a target number of cores sold. It ensures a minimum price and limits price growth to a maximum price increase factor, while also giving govenance control over the steepness of the price change curve. It allows governance to address challenges arising from changing market conditions and should offer predictable and controlled price adjustments.

-

Accompanying visualizations are provided at [1].

-

Motivation

-

RFC-1 proposes periodic Bulk Coretime Sales as a mechanism to sell continouos regions of blockspace (suggested to be 4 weeks in length). A number of Blockspace Regions (compare RFC-1 & RFC-3) are provided for sale to the Broker-Chain each period and shall be sold in a way that provides value-capture for the Polkadot network. The exact pricing mechanism is out of scope for RFC-1 and shall be provided by this RFC.

-

A dynamic pricing model is needed. A limited number of Regions are offered for sale each period. The model needs to find the price for a period based on supply and demand of the previous period.

-

The model shall give Coretime consumers predictability about upcoming price developments and confidence that Polkadot governance can adapt the pricing model to changing market conditions.

-

Requirements

-
    -
  1. The solution SHOULD provide a dynamic pricing model that increases price with growing demand and reduces price with shrinking demand.
  2. -
  3. The solution SHOULD have a slow rate of change for price if the number of Regions sold is close to a given sales target and increase the rate of change as the number of sales deviates from the target.
  4. -
  5. The solution SHOULD provide the possibility to always have a minimum price per Region.
  6. -
  7. The solution SHOULD provide a maximum factor of price increase should the limit of Regions sold per period be reached.
  8. -
  9. The solution should allow governance to control the steepness of the price function
  10. -
-

Stakeholders

-

The primary stakeholders of this RFC are:

- -

Explanation

-

Overview

-

The dynamic pricing model sets the new price based on supply and demand in the previous period. The model is a function of the number of Regions sold, piecewise-defined by two power functions.

- -

The curve of the function forms a plateau around the target and then falls off to the left and rises up to the right. The shape of the plateau can be controlled via a scale factor for the left side and right side of the function respectively.

-

Parameters

-

From here on, we will also refer to Regions sold as 'cores' to stay congruent with RFC-1.

-
- - - - - - -
NameSuggested ValueDescriptionConstraints
BULK_LIMIT45The maximum number of cores being sold0 < BULK_LIMIT
BULK_TARGET30The target number of cores being sold0 < BULK_TARGET <= BULK_LIMIT
MIN_PRICE1The minimum price a core will always cost.0 < MIN_PRICE
MAX_PRICE_INCREASE_FACTOR2The maximum factor by which the price can change.1 < MAX_PRICE_INCREASE_FACTOR
SCALE_DOWN2The steepness of the left side of the function.0 < SCALE_DOWN
SCALE_UP2The steepness of the right side of the function.0 < SCALE_UP
-
-

Function

-
P(n) = \begin{cases} 
-    (P_{\text{old}} - P_{\text{min}}) \left(1 - \left(\frac{T - n}{T}\right)^d\right) + P_{\text{min}} & \text{if } n \leq T \\
-    ((F - 1) \cdot P_{\text{old}} \cdot \left(\frac{n - T}{L - T}\right)^u) + P_{\text{old}} & \text{if } n > T 
-\end{cases}
-
- -

Left side

-

The left side is a power function that describes an increasing concave downward curvature that approaches old_price. We realize this by using the form $y = a(1 - x^d)$, usually used as a downward sloping curve, but in our case flipped horizontally by letting the argument $x = \frac{T-n}{T}$ decrease with $n$, doubly inversing the curve.

-

This approach is chosen over a decaying exponential because it let's us a better control the shape of the plateau, especially allowing us to get a straight line by setting SCALE_DOWN to $1$.

-

Ride side

-

The right side is a power function of the form $y = a(x^u)$.

-

Pseudo-code

-
NEW_PRICE := IF CORES_SOLD <= BULK_TARGET THEN
-    (OLD_PRICE - MIN_PRICE) * (1 - ((BULK_TARGET - CORES_SOLD)^SCALE_DOWN / BULK_TARGET^SCALE_DOWN)) + MIN_PRICE
-ELSE
-    ((MAX_PRICE_INCREASE_FACTOR - 1) * OLD_PRICE * ((CORES_SOLD - BULK_TARGET)^SCALE_UP / (BULK_LIMIT - BULK_TARGET)^SCALE_UP)) + OLD_PRICE
-END IF
-
-

Properties of the Curve

-

Minimum Price

-

We introduce MIN_PRICE to control the minimum price.

-

The left side of the function shall be allowed to come close to 0 if cores sold approaches 0. The rationale is that if there are actually 0 cores sold, the previous sale price was too high and the price needs to adapt quickly.

-

Price forms a plateau around the target

-

If the number of cores is close to BULK_TARGET, less extreme price changes might be sensible. This ensures that a drop in sold cores or an increase doesn’t lead to immediate price changes, but rather slowly adapts. Only if more extreme changes in the number of sold cores occur, does the price slope increase.

-

We introduce SCALE_DOWN and SCALE_UP to control for the steepness of the left and the right side of the function respectively.

-

Max price increase factor

-

We introduce MAX_PRICE_INCREASE_FACTOR as the factor that controls how much the price may increase from one period to another.

-

Introducing this variable gives governance an additional control lever and avoids the necessity for a future runtime upgrade.

-

Example Configurations

-

Baseline

-

This example proposes the baseline parameters. If not mentioned otherwise, other examples use these values.

-

The minimum price of a core is 1 DOT, the price can double every 4 weeks. Price change around BULK_TARGET is dampened slightly.

-
BULK_TARGET = 30
-BULK_LIMIT = 45
-MIN_PRICE = 1
-MAX_PRICE_INCREASE_FACTOR = 2
-SCALE_DOWN = 2
-SCALE_UP = 2
-OLD_PRICE = 1000
-
-

More aggressive pricing

-

We might want to have a more aggressive price growth, allowing the price to triple every 4 weeks and have a linear increase in price on the right side.

-
BULK_TARGET = 30
-BULK_LIMIT = 45
-MIN_PRICE = 1
-MAX_PRICE_INCREASE_FACTOR = 3
-SCALE_DOWN = 2
-SCALE_UP = 1
-OLD_PRICE = 1000
-
-

Conservative pricing to ensure quick corrections in an affluent market

-

If governance considers the risk that a sudden surge in DOT price might price chains out from bulk coretime markets, it can ensure the model quickly reacts to a quick drop in demand, by setting 0 < SCALE_DOWN < 1 and setting the max price increase factor more conservatively.

-
BULK_TARGET = 30
-BULK_LIMIT = 45
-MIN_PRICE = 1
-MAX_PRICE_INCREASE_FACTOR = 1.5
-SCALE_DOWN = 0.5
-SCALE_UP = 2
-OLD_PRICE = 1000
-
-

Linear pricing

-

By setting the scaling factors to 1 and potentially adapting the max price increase, we can achieve a linear function

-
BULK_TARGET = 30
-BULK_LIMIT = 45
-MIN_PRICE = 1
-MAX_PRICE_INCREASE_FACTOR = 1.5
-SCALE_DOWN = 1
-SCALE_UP = 1
-OLD_PRICE = 1000
-
-

Drawbacks

-

None at present.

-

Prior Art and References

-

This pricing model is based on the requirements from the basic linear solution proposed in RFC-1, which is a simple dynamic pricing model and only used as proof. The present model adds additional considerations to make the model more adaptable under real conditions.

-

Future Possibilities

-

This RFC, if accepted, shall be implemented in conjunction with RFC-1.

-

References

- -

(source)

-

Table of Contents

- -

RFC-0009: Improved light client requests networking protocol

-
- - - -
Start Date2023-07-19
DescriptionModify the networking storage read requests to solve some problems with the existing one
AuthorsPierre Krieger
-
-

Summary

-

Improve the networking messages that query storage items from the remote, in order to reduce the bandwidth usage and number of round trips of light clients.

-

Motivation

-

Clients on the Polkadot peer-to-peer network can be divided into two categories: full nodes and light clients. So-called full nodes are nodes that store the content of the chain locally on their disk, while light clients are nodes that don't. In order to access for example the balance of an account, a full node can do a disk read, while a light client needs to send a network message to a full node and wait for the full node to reply with the desired value. This reply is in the form of a Merkle proof, which makes it possible for the light client to verify the exactness of the value.

-

Unfortunately, this network protocol is suffering from some issues:

- -

Once Polkadot and Kusama will have transitioned to state_version = 1, which modifies the format of the trie entries, it will be possible to generate Merkle proofs that contain only the hashes of values in the storage. Thanks to this, it is already possible to prove the existence of a key without sending its entire value (only its hash), or to prove that a value has changed or not between two blocks (by sending just their hashes). -Thus, the only reason why aforementioned issues exist is because the existing networking messages don't give the possibility for the querier to query this. This is what this proposal aims at fixing.

-

Stakeholders

-

This is the continuation of https://github.com/w3f/PPPs/pull/10, which itself is the continuation of https://github.com/w3f/PPPs/pull/5.

-

Explanation

-

The protobuf schema of the networking protocol can be found here: https://github.com/paritytech/substrate/blob/5b6519a7ff4a2d3cc424d78bc4830688f3b184c0/client/network/light/src/schema/light.v1.proto

-

The proposal is to modify this protocol in this way:

-
@@ -11,6 +11,7 @@ message Request {
-                RemoteReadRequest remote_read_request = 2;
-                RemoteReadChildRequest remote_read_child_request = 4;
-                // Note: ids 3 and 5 were used in the past. It would be preferable to not re-use them.
-+               RemoteReadRequestV2 remote_read_request_v2 = 6;
-        }
- }
- 
-@@ -48,6 +49,21 @@ message RemoteReadRequest {
-        repeated bytes keys = 3;
- }
- 
-+message RemoteReadRequestV2 {
-+       required bytes block = 1;
-+       optional ChildTrieInfo child_trie_info = 2;  // Read from the main trie if missing.
-+       repeated Key keys = 3;
-+       optional bytes onlyKeysAfter = 4;
-+       optional bool onlyKeysAfterIgnoreLastNibble = 5;
-+}
-+
-+message ChildTrieInfo {
-+       enum ChildTrieNamespace {
-+               DEFAULT = 1;
-+       }
-+
-+       required bytes hash = 1;
-+       required ChildTrieNamespace namespace = 2;
-+}
-+
- // Remote read response.
- message RemoteReadResponse {
-        // Read proof. If missing, indicates that the remote couldn't answer, for example because
-@@ -65,3 +81,8 @@ message RemoteReadChildRequest {
-        // Storage keys.
-        repeated bytes keys = 6;
- }
-+
-+message Key {
-+       required bytes key = 1;
-+       optional bool skipValue = 2; // Defaults to `false` if missing
-+       optional bool includeDescendants = 3; // Defaults to `false` if missing
-+}
-
-

Note that the field names aren't very important as they are not sent over the wire. They can be changed at any time without any consequence. I would invite people to not discuss these field names as they are implementation details.

-

This diff adds a new type of request (RemoteReadRequestV2).

-

The new child_trie_info field in the request makes it possible to specify which trie is concerned by the request. The current networking protocol uses two different structs (RemoteReadRequest and RemoteReadChildRequest) for main trie and child trie queries, while this new request would make it possible to query either. This change doesn't fix any of the issues mentioned in the previous section, but is a side change that has been done for simplicity. -An alternative could have been to specify the child_trie_info for each individual Key. However this would make it necessary to send the child trie hash many times over the network, which leads to a waste of bandwidth, and in my opinion makes things more complicated for no actual gain. If a querier would like to access more than one trie at the same time, it is always possible to send one query per trie.

-

If skipValue is true for a Key, then the value associated with this key isn't important to the querier, and the replier is encouraged to replace the value with its hash provided that the storage item has a state_version equal to 1. If the storage value has a state_version equal to 0, then the optimization isn't possible and the replier should behave as if skipValue was false.

-

If includeDescendants is true for a Key, then the replier must also include in the proof all keys that are descendant of the given key (in other words, its children, children of children, children of children of children, etc.). It must do so even if key itself doesn't have any storage value associated to it. The values of all of these descendants are replaced with their hashes if skipValue is true, similarly to key itself.

-

The optional onlyKeysAfter and onlyKeysAfterIgnoreLastNibble fields can provide a lower bound for the keys contained in the proof. The responder must not include in its proof any node whose key is strictly inferior to the value in onlyKeysAfter. If onlyKeysAfterIgnoreLastNibble is provided, then the last 4 bits for onlyKeysAfter must be ignored. This makes it possible to represent a trie branch node that doesn't have an even number of nibbles. If no onlyKeysAfter is provided, it is equivalent to being empty, meaning that the response must start with the root node of the trie.

-

If onlyKeysAfterIgnoreLastNibble is missing, it is equivalent to false. If onlyKeysAfterIgnoreLastNibble is true and onlyKeysAfter is missing or empty, then the request is invalid.

-

For the purpose of this networking protocol, it should be considered as if the main trie contained an entry for each default child trie whose key is concat(":child_storage:default:", child_trie_hash) and whose value is equal to the trie root hash of that default child trie. This behavior is consistent with what the host functions observe when querying the storage. This behavior is present in the existing networking protocol, in other words this proposal doesn't change anything to the situation, but it is worth mentioning. -Also note that child tries aren't considered as descendants of the main trie when it comes to the includeDescendants flag. In other words, if the request concerns the main trie, no content coming from child tries is ever sent back.

-

This protocol keeps the same maximum response size limit as currently exists (16 MiB). It is not possible for the querier to know in advance whether its query will lead to a reply that exceeds the maximum size. If the reply is too large, the replier should send back only a limited number (but at least one) of requested items in the proof. The querier should then send additional requests for the rest of the items. A response containing none of the requested items is invalid.

-

The server is allowed to silently discard some keys of the request if it judges that the number of requested keys is too high. This is in line with the fact that the server might truncate the response.

-

Drawbacks

-

This proposal doesn't handle one specific situation: what if a proof containing a single specific item would exceed the response size limit? For example, if the response size limit was 1 MiB, querying the runtime code (which is typically 1.0 to 1.5 MiB) would be impossible as it's impossible to generate a proof less than 1 MiB. The response size limit is currently 16 MiB, meaning that no single storage item must exceed 16 MiB.

-

Unfortunately, because it's impossible to verify a Merkle proof before having received it entirely, parsing the proof in a streaming way is also not possible.

-

A way to solve this issue would be to Merkle-ize large storage items, so that a proof could include only a portion of a large storage item. Since this would require a change to the trie format, it is not realistically feasible in a short time frame.

-

Testing, Security, and Privacy

-

The main security consideration concerns the size of replies and the resources necessary to generate them. It is for example easily possible to ask for all keys and values of the chain, which would take a very long time to generate. Since responses to this networking protocol have a maximum size, the replier should truncate proofs that would lead to the response being too large. Note that it is already possible to send a query that would lead to a very large reply with the existing network protocol. The only thing that this proposal changes is that it would make it less complicated to perform such an attack.

-

Implementers of the replier side should be careful to detect early on when a reply would exceed the maximum reply size, rather than inconditionally generate a reply, as this could take a very large amount of CPU, disk I/O, and memory. Existing implementations might currently be accidentally protected from such an attack thanks to the fact that requests have a maximum size, and thus that the list of keys in the query was bounded. After this proposal, this accidental protection would no longer exist.

-

Malicious server nodes might truncate Merkle proofs even when they don't strictly need to, and it is not possible for the client to (easily) detect this situation. However, malicious server nodes can already do undesirable things such as throttle down their upload bandwidth or simply not respond. There is no need to handle unnecessarily truncated Merkle proofs any differently than a server simply not answering the request.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

It is unclear to the author of the RFC what the performance implications are. Servers are supposed to have limits to the amount of resources they use to respond to requests, and as such the worst that can happen is that light client requests become a bit slower than they currently are.

-

Ergonomics

-

Irrelevant.

-

Compatibility

-

The prior networking protocol is maintained for now. The older version of this protocol could get removed in a long time.

-

Prior Art and References

-

None. This RFC is a clean-up of an existing mechanism.

-

Unresolved Questions

-

None

- -

The current networking protocol could be deprecated in a long time. Additionally, the current "state requests" protocol (used for warp syncing) could also be deprecated in favor of this one.

-

(source)

-

Table of Contents

- -

RFC-0015: Market Design Revisit

-
- - - -
Start Date05.08.2023
DescriptionThis RFC refines the previously proposed mechanisms involving the various Coretime markets and presents an integrated framework for harmonious interaction between all markets.
AuthorsJonas Gehrlein
-
-

Summary

-

This document is a proposal for restructuring the bulk markets in the Polkadot UC's coretime allocation system to improve efficiency and fairness. The proposal suggests separating the BULK_PERIOD into MARKET_PERIOD and RENEWAL_PERIOD, allowing for a market-driven price discovery through a clearing price Dutch auction during the MARKET_PERIOD followed by renewal offers at the MARKET_PRICE during the RENEWAL_PERIOD. The new system ensures synchronicity between renewal and market prices, fairness among all current tenants, and efficient price discovery, while preserving price caps to provide security for current tenants. It seeks to start a discussion about the possibility of long-term leases.

-

Motivation

-

While the initial RFC-1 has provided a robust framework for Coretime allocation within the Polkadot UC, this proposal builds upon its strengths and uses many provided building blocks to address some areas that could be further improved.

-

In particular, this proposal introduces the following changes:

- -

The premise of this proposal is to reduce complexity by introducing a common price (that develops releative to capacity consumption of Polkadot UC), while still allowing for market forces to add efficiency. Longterm lease owners still receive priority IF they can pay (close to) the market price. This prevents a situation where the renewal price significantly diverges from renewal prices which allows for core captures. While maximum price increase certainty might seem contradictory to efficient price discovery, the proposed model aims to balance these elements, utilizing market forces to determine the price and allocate cores effectively within certain bounds. It must be stated, that potential price increases remain predictable (in the worst-case) but could be higher than in the originally proposed design. The argument remains, however, that we need to allow market forces to affect all prices for an efficient Coretime pricing and allocation.

-

Ultimately, this the framework proposed here adheres to all requirements stated in RFC-1.

-

Stakeholders

-

Primary stakeholder sets are:

- -

Explanation

-

Bulk Markets

-

The BULK_PERIOD has been restructured into two primary segments: the MARKET_PERIOD and RENEWAL_PERIOD, along with an auxiliary SETTLEMENT_PERIOD. This latter period doesn't necessitate any actions from the coretime system chain, but it facilitates a more efficient allocation of coretime in secondary markets. A significant departure from the original proposal lies in the timing of renewals, which now occur post-market phase. This adjustment aims to harmonize renewal prices with their market counterparts, ensuring a more consistent and equitable pricing model.

-

Market Period (14 days)

-

During the market period, core sales are conducted through a well-established clearing price Dutch auction that features a RESERVE_PRICE. The price initiates at a premium, designated as PRICE_PREMIUM (for instance, 30%) and descends linearly to the RESERVE_PRICE throughout the duration of the MARKET_PERIOD. Each bidder is expected to submit both their desired price and the quantity (that is, the amount of Coretime) they wish to purchase. To secure these acquisitions, bidders must make a deposit equivalent to their bid multiplied by the chosen quantity, in DOT.

-

The market achieves resolution once all quantities have been sold, or the RESERVE_PRICE has been reached. This situation leads to determining the MARKET_PRICE either by the lowest bid that was successful in clearing the entire market or by the RESERVE_PRICE. This mechanism yields a uniform price, shaped by market forces (refer to the following discussion for an explanation of its benefits). In other words, all buyers pay the same price (per unit of Coretime). Further down the benefits of this variant of a Dutch auction is discussed.

-

Note: In cases where some cores remain unsold in the market, all buyers are obligated to pay the RESERVE_PRICE.

-

Renewal Period (7 days)

-

As the RENEWAL_PERIOD commences, all current tenants are granted the opportunity to renew their cores at a slight discount of MARKET_PRICE * RENEWAL_DISCOUNT (for instance, 10%). This provision affords marginal benefits to existing tenants, balancing out the non-transferability aspect of renewals.

-

At the end of the period, all available cores are allocated to the current tenants who have opted for renewal and the participants who placed bids during the market period. If the demand for cores exceeds supply, the cores left unclaimed from renewals may be awarded to bidders who placed their bids early in the auction, thereby subtly incentivizing early participation. If the supply exceeds the demand, all unsold cores are transferred to the Instantanous Market.

-

Reserve Price Adjustment

-

After all cores are allocated, the RESERVE_PRICE is adjusted following the process described in RFC-1 and serves as baseline price in the next BULK_PERIOD.

-

Note: The particular price curve is outside the scope of the proposal. The MARKET_PRICE (as a function of RESERVE_PRICE), however, is able to capture higher demand very well while being capped downwards. That means, the curve that adjusts the RESERVE_PRICE should be more sensitive to undercapacity.

-

Price Predictability

-

Tasks that are in the "renewal-pipeline" can determine the upper bound for the price they will pay in any future period. The main driver of any price increase over time is the adjustment of the RESERVE_PRICE, that occurs at the end of each BULK_PERIOD after determining the capacity fillment of Polkadot UC. To calculate the maximum price in some future period, a task could assume maximum capacity in all upcoming periods and track the resulting price increase of RESERVE_PRICE. In the final period, that price can get a maximum premium of PRICE_PREMIUM and after deducting a potential RENEWAL_DISCOUNT, the maximum price can be determined.

-

Settlement Period (7 days)

-

During the settlement period, participants have ample time to trade Coretime on secondary markets before the onset of the next BULK_PERIOD. This allows for trading with full Coretime availability. Trading transferrable Coretime naturally continues during each BULK_PERIOD, albeit with cores already in use.

-

Benefits of this system

- -

Discussion: Clearing Price Dutch Auctions

-

Having all bidders pay the market clearing price offers some benefits and disadvantages.

- -

Further Discussion Points

- -

Drawbacks

-

There are trade-offs that arise from this proposal, compared to the initial model. The most notable one is that here, I prioritize requirement 6 over requirement 2. The price, in the very "worst-case" (meaning a huge explosion in demand for coretime) could lead to a much larger increase of prices in Coretime. From an economic perspective, this (rare edgecase) would also mean that we'd vastly underprice Coretime in the original model, leading to highly inefficient allocations.

-

Prior Art and References

-

This RFC builds extensively on the available ideas put forward in RFC-1.

-

Additionally, I want to express a special thanks to Samuel Haefner and Shahar Dobzinski for fruitful discussions and helping me structure my thoughts.

-

Unresolved Questions

-

The technical feasability needs to be assessed.

-

(source)

-

Table of Contents

- -

RFC-34: XCM Absolute Location Account Derivation

-
- - - -
Start Date05 October 2023
DescriptionXCM Absolute Location Account Derivation
AuthorsGabriel Facco de Arruda
-
-

Summary

-

This RFC proposes changes that enable the use of absolute locations in AccountId derivations, which allows protocols built using XCM to have static account derivations in any runtime, regardless of its position in the family hierarchy.

-

Motivation

-

These changes would allow protocol builders to leverage absolute locations to maintain the exact same derived account address across all networks in the ecosystem, thus enhancing user experience.

-

One such protocol, that is the original motivation for this proposal, is InvArch's Saturn Multisig, which gives users a unifying multisig and DAO experience across all XCM connected chains.

-

Stakeholders

- -

Explanation

-

This proposal aims to make it possible to derive accounts for absolute locations, enabling protocols that require the ability to maintain the same derived account in any runtime. This is done by deriving accounts from the hash of described absolute locations, which are static across different destinations.

-

The same location can be represented in relative form and absolute form like so:

-
#![allow(unused)]
-fn main() {
-// Relative location (from own perspective)
-{
-    parents: 0,
-    interior: Here
-}
-
-// Relative location (from perspective of parent)
-{
-    parents: 0,
-    interior: [Parachain(1000)]
-}
-
-// Relative location (from perspective of sibling)
-{
-    parents: 1,
-    interior: [Parachain(1000)]
-}
-
-// Absolute location
-[GlobalConsensus(Kusama), Parachain(1000)]
-}
-

Using DescribeFamily, the above relative locations would be described like so:

-
#![allow(unused)]
-fn main() {
-// Relative location (from own perspective)
-// Not possible.
-
-// Relative location (from perspective of parent)
-(b"ChildChain", Compact::<u32>::from(*index)).encode()
-
-// Relative location (from perspective of sibling)
-(b"SiblingChain", Compact::<u32>::from(*index)).encode()
-
-}
-

The proposed description for absolute location would follow the same pattern, like so:

-
#![allow(unused)]
-fn main() {
-(
-    b"GlobalConsensus",
-    network_id,
-    b"Parachain",
-    Compact::<u32>::from(para_id),
-    tail
-).encode()
-}
-

This proposal requires the modification of two XCM types defined in the xcm-builder crate: The WithComputedOrigin barrier and the DescribeFamily MultiLocation descriptor.

-

WithComputedOrigin

-

The WtihComputedOrigin barrier serves as a wrapper around other barriers, consuming origin modification instructions and applying them to the message origin before passing to the inner barriers. One of the origin modifying instructions is UniversalOrigin, which serves the purpose of signaling that the origin should be a Universal Origin that represents the location as an absolute path prefixed by the GlobalConsensus junction.

-

In it's current state the barrier transforms locations with the UniversalOrigin instruction into relative locations, so the proposed changes aim to make it return absolute locations instead.

-

DescribeFamily

-

The DescribeFamily location descriptor is part of the HashedDescription MultiLocation hashing system and exists to describe locations in an easy format for encoding and hashing, so that an AccountId can be derived from this MultiLocation.

-

This implementation contains a match statement that does not match against absolute locations, so changes to it involve matching against absolute locations and providing appropriate descriptions for hashing.

-

Drawbacks

-

No drawbacks have been identified with this proposal.

-

Testing, Security, and Privacy

-

Tests can be done using simple unit tests, as this is not a change to XCM itself but rather to types defined in xcm-builder.

-

Security considerations should be taken with the implementation to make sure no unwanted behavior is introduced.

-

This proposal does not introduce any privacy considerations.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

Depending on the final implementation, this proposal should not introduce much overhead to performance.

-

Ergonomics

-

The ergonomics of this proposal depend on the final implementation details.

-

Compatibility

-

Backwards compatibility should remain unchanged, although that depend on the final implementation.

-

Prior Art and References

- -

Unresolved Questions

-

Implementation details and overall code is still up to discussion.

-

(source)

-

Table of Contents

- -

RFC-0035: Conviction Voting Delegation Modifications

-
- - - -
October 10, 2023
Conviction Voting Delegation Modifications
ChaosDAO
-
-

Summary

-

This RFC proposes to make modifications to voting power delegations as part of the Conviction Voting pallet. The changes being proposed include:

-
    -
  1. Allow a Delegator to vote independently of their Delegate if they so desire.
  2. -
  3. Allow nested delegations – for example Charlie delegates to Bob who delegates to Alice – when Alice votes then both Bob and Charlie vote alongside Alice (in the current implementation Charlie will not vote when Alice votes).
  4. -
  5. Make a change so that when a delegate votes abstain their delegated votes also vote abstain.
  6. -
  7. Allow a Delegator to delegate/ undelegate their votes for all tracks with a single call.
  8. -
-

Motivation

-

It has become clear since the launch of OpenGov that there are a few common tropes which pop up time and time again:

-
    -
  1. The frequency of referenda is often too high for network participants to have sufficient time to review, comprehend, and ultimately vote on each individual referendum. This means that these network participants end up being inactive in on-chain governance.
  2. -
  3. There are active network participants who are reviewing every referendum and are providing feedback in an attempt to help make the network thrive – but often time these participants do not control enough voting power to influence the network with their positive efforts.
  4. -
  5. Delegating votes for all tracks currently requires long batched calls which result in high fees for the Delegator - resulting in a reluctance from many to delegate their votes.
  6. -
-

We believe (based on feedback from token holders with a larger stake in the network) that if there were some changes made to delegation mechanics, these larger stake holders would be more likely to delegate their voting power to active network participants – thus greatly increasing the support turnout.

-

Stakeholders

-

The primary stakeholders of this RFC are:

- -

Explanation

-

This RFC proposes to make 4 changes to the convictionVoting pallet logic in order to improve the user experience of those delegating their voting power to another account.

-
    -
  1. -

    Allow a Delegator to vote independently of their Delegate if they so desire – this would empower network participants to more actively delegate their voting power to active voters, removing the tedious steps of having to undelegate across an entire track every time they do not agree with their delegate's voting direction for a particular referendum.

    -
  2. -
  3. -

    Allow nested delegations – for example Charlie delegates to Bob who delegates to Alice – when Alice votes then both Bob and Charlie vote alongside Alice (in the current runtime Charlie will not vote when Alice votes) – This would allow network participants who control multiple (possibly derived) accounts to be able to delegate all of their voting power to a single account under their control, which would in turn delegate to a more active voting participant. Then if the delegator wishes to vote independently of their delegate they can control all of their voting power from a single account, which again removes the pain point of having to issue multiple undelegate extrinsics in the event that they disagree with their delegate.

    -
  4. -
  5. -

    Have delegated votes follow their delegates abstain votes – there are times where delegates may vote abstain on a particular referendum and adding this functionality will increase the support of a particular referendum. It has a secondary benefit of meaning that Validators who are delegating their voting power do not lose points in the 1KV program in the event that their delegate votes abstain (another pain point which may be preventing those network participants from delegating).

    -
  6. -
  7. -

    Allow a Delegator to delegate/ undelegate their votes for all tracks with a single call - in order to delegate votes across all tracks, a user must batch 15 calls - resulting in high costs for delegation. A single call for delegate_all/ undelegate_all would reduce the complexity and therefore costs of delegations considerably for prospective Delegators.

    -
  8. -
-

Drawbacks

-

We do not foresee any drawbacks by implementing these changes. If anything we believe that this should help to increase overall voter turnout (via the means of delegation) which we see as a net positive.

-

Testing, Security, and Privacy

-

We feel that the Polkadot Technical Fellowship would be the most competent collective to identify the testing requirements for the ideas presented in this RFC.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

This change may add extra chain storage requirements on Polkadot, especially with respect to nested delegations.

-

Ergonomics & Compatibility

-

The change to add nested delegations may affect governance interfaces such as Nova Wallet who will have to apply changes to their indexers to support nested delegations. It may also affect the Polkadot Delegation Dashboard as well as Polkassembly & SubSquare.

-

We want to highlight the importance for ecosystem builders to create a mechanism for indexers and wallets to be able to understand that changes have occurred such as increasing the pallet version, etc.

-

Prior Art and References

-

N/A

-

Unresolved Questions

-

N/A

- -

Additionally we would like to re-open the conversation about the potential for there to be free delegations. This was discussed by Dr Gavin Wood at Sub0 2022 and we feel like this would go a great way towards increasing the amount of network participants that are delegating: https://youtu.be/hSoSA6laK3Q?t=526

-

Overall, we strongly feel that delegations are a great way to increase voter turnout, and the ideas presented in this RFC would hopefully help in that aspect.

-

(source)

-

Table of Contents

- -

RFC-0044: Rent based registration model

-
- - - -
Start Date6 November 2023
DescriptionA new rent based parachain registration model
AuthorsSergej Sakac
-
-

Summary

-

This RFC proposes a new model for a sustainable on-demand parachain registration, involving a smaller initial deposit and periodic rent payments. The new model considers that on-demand chains may be unregistered and later re-registered. The proposed solution also ensures a quick startup for on-demand chains on Polkadot in such cases.

-

Motivation

-

With the support of on-demand parachains on Polkadot, there is a need to explore a new, more cost-effective model for registering validation code. In the current model, the parachain manager is responsible for reserving a unique ParaId and covering the cost of storing the validation code of the parachain. These costs can escalate, particularly if the validation code is large. We need a better, sustainable model for registering on-demand parachains on Polkadot to help smaller teams deploy more easily.

-

This RFC suggests a new payment model to create a more financially viable approach to on-demand parachain registration. In this model, a lower initial deposit is required, followed by recurring payments upon parachain registration.

-

This new model will coexist with the existing one-time deposit payment model, offering teams seeking to deploy on-demand parachains on Polkadot a more cost-effective alternative.

-

Requirements

-
    -
  1. The solution SHOULD NOT affect the current model for registering validation code.
  2. -
  3. The solution SHOULD offer an easily configurable way for governance to adjust the initial deposit and recurring rent cost.
  4. -
  5. The solution SHOULD provide an incentive to prune validation code for which rent is not paid.
  6. -
  7. The solution SHOULD allow anyone to re-register validation code under the same ParaId without the need for redundant pre-checking if it was already verified before.
  8. -
  9. The solution MUST be compatible with the Agile Coretime model, as described in RFC#0001
  10. -
  11. The solution MUST allow anyone to pay the rent.
  12. -
  13. The solution MUST prevent the removal of validation code if it could still be required for disputes or approval checking.
  14. -
-

Stakeholders

- -

Explanation

-

This RFC proposes a set of changes that will enable the new rent based approach to registering and storing validation code on-chain. -The new model, compared to the current one, will require periodic rent payments. The parachain won't be pruned automatically if the rent is not paid, but by permitting anyone to prune the parachain and rewarding the caller, there will be an incentive for the removal of the validation code.

-

On-demand parachains should still be able to utilize the current one-time payment model. However, given the size of the deposit required, it's highly likely that most on-demand parachains will opt for the new rent-based model.

-

Importantly, this solution doesn't require any storage migrations in the current system nor does it introduce any breaking changes. The following provides a detailed description of this solution.

-

Registering an on-demand parachain

-

In the current implementation of the registrar pallet, there are two constants that specify the necessary deposit for parachains to register and store their validation code:

-
#![allow(unused)]
-fn main() {
-trait Config {
-	// -- snip --
-
-	/// The deposit required for reserving a `ParaId`.
-	#[pallet::constant]
-	type ParaDeposit: Get<BalanceOf<Self>>;
-
-	/// The deposit to be paid per byte stored on chain.
-	#[pallet::constant]
-	type DataDepositPerByte: Get<BalanceOf<Self>>;
-}
-}
-

This RFC proposes the addition of three new constants that will determine the payment amount and the frequency of the recurring rent payment:

-
#![allow(unused)]
-fn main() {
-trait Config {
-	// -- snip --
-
-	/// Defines how frequently the rent needs to be paid.
-	///
-	/// The duration is set in sessions instead of block numbers.
-	#[pallet::constant]
-	type RentDuration: Get<SessionIndex>;
-
-	/// The initial deposit amount for registering validation code.
-	///
-	/// This is defined as a proportion of the deposit that would be required in the regular
-	/// model.
-	#[pallet::constant]
-	type RentalDepositProportion: Get<Perbill>;
-
-	/// The recurring rental cost defined as a proportion of the initial rental registration deposit.
-	#[pallet::constant]
-	type RentalRecurringProportion: Get<Perbill>;
-}
-}
-

Users will be able to reserve a ParaId and register their validation code for a proportion of the regular deposit required. However, they must also make additional rent payments at intervals of T::RentDuration.

-

For registering using the new rental system we will have to make modifications to the paras-registrar pallet. We should expose two new extrinsics for this:

-
#![allow(unused)]
-fn main() {
-mod pallet {
-	// -- snip --
-
-	pub fn register_rental(
-		origin: OriginFor<T>,
-		id: ParaId,
-		genesis_head: HeadData,
-		validation_code: ValidationCode,
-	) -> DispatchResult { /* ... */ }
-
-	pub fn pay_rent(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
-		/* ... */ 
-	}
-}
-}
-

A call to register_rental will require the reservation of only a percentage of the deposit that would otherwise be required to register the validation code when using the regular model. -As described later in the Quick para re-registering section below, we will also store the code hash of each parachain to enable faster re-registration after a parachain has been pruned. For this reason the total initial deposit amount is increased to account for that.

-
#![allow(unused)]
-fn main() {
-// The logic for calculating the initial deposit for parachain registered with the 
-// new rent-based model:
-
-let validation_code_deposit = per_byte_fee.saturating_mul((validation_code.0.len() as u32).into());
-
-let head_deposit = per_byte_fee.saturating_mul((genesis_head.0.len() as u32).into())
-let hash_deposit = per_byte_fee.saturating_mul(HASH_SIZE);
-
-let deposit = T::RentalDepositProportion::get().mul_ceil(validation_code_deposit)
-	.saturating_add(T::ParaDeposit::get())
-	.saturating_add(head_deposit)
-	.saturating_add(hash_deposit)
-}
-

Once the ParaId is reserved and the validation code is registered the rent must be periodically paid to ensure the on-demand parachain doesn't get removed from the state. The pay_rent extrinsic should be callable by anyone, removing the need for the parachain to depend on the parachain manager for rent payments.

-

On-demand parachain pruning

-

If the rent is not paid, anyone has the option to prune the on-demand parachain and claim a portion of the initial deposit reserved for storing the validation code. This type of 'light' pruning only removes the validation code, while the head data and validation code hash are retained. The validation code hash is stored to allow anyone to register it again as well as to enable quicker re-registration by skipping the pre-checking process.

-

The moment the rent is no longer paid, the parachain won't be able to purchase on-demand access, meaning no new blocks are allowed. This stage is called the "hibernation" stage, during which all the parachain-related data is still stored on-chain, but new blocks are not permitted. The reason for this is to ensure that the validation code is available in case it is needed in the dispute or approval checking subsystems. Waiting for one entire session will be enough to ensure it is safe to deregister the parachain.

-

This means that anyone can prune the parachain only once the "hibernation" stage is over, which lasts for an entire session after the moment that the rent is not paid.

-

The pruning described here is a light form of pruning, since it only removes the validation code. As with all parachains, the parachain or para manager can use the deregister extrinsic to remove all associated state.

-

Ensuring rent is paid

-

The paras pallet will be loosely coupled with the para-registrar pallet. This approach enables all the pallets tightly coupled with the paras pallet to have access to the rent status information.

-

Once the validation code is stored without having its rent paid the assigner_on_demand pallet will ensure that an order for that parachain cannot be placed. This is easily achievable given that the assigner_on_demand pallet is tightly coupled with the paras pallet.

-

On-demand para re-registration

-

If the rent isn't paid on time, and the parachain gets pruned, the new model should provide a quick way to re-register the same validation code under the same ParaId. This can be achieved by skipping the pre-checking process, as the validation code hash will be stored on-chain, allowing us to easily verify that the uploaded code remains unchanged.

-
#![allow(unused)]
-fn main() {
-/// Stores the validation code hash for parachains that successfully completed the 
-/// pre-checking process.
-///
-/// This is stored to enable faster on-demand para re-registration in case its pvf has been earlier
-/// registered and checked.
-///
-/// NOTE: During a runtime upgrade where the pre-checking rules change this storage map should be
-/// cleared appropriately.
-#[pallet::storage]
-pub(super) type CheckedCodeHash<T: Config> =
-	StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
-}
-

To enable parachain re-registration, we should introduce a new extrinsic in the paras-registrar pallet that allows this. The logic of this extrinsic will be same as regular registration, with the distinction that it can be called by anyone, and the required deposit will be smaller since it only has to cover for the storage of the validation code.

-

Drawbacks

-

This RFC does not alter the process of reserving a ParaId, and therefore, it does not propose reducing it, even though such a reduction could be beneficial.

-

Even though this RFC doesn't delve into the specifics of the configuration values for parachain registration but rather focuses on the mechanism, configuring it carelessly could lead to potential problems.

-

Since the validation code hash and head data are not removed when the parachain is pruned but only when the deregister extrinsic is called, the T::DataDepositPerByte must be set to a higher value to create a strong enough incentive for removing it from the state.

-

Testing, Security, and Privacy

-

The implementation of this RFC will be tested on Rococo first.

-

Proper research should be conducted on setting the configuration values of the new system since these values can have great impact on the network.

-

An audit is required to ensure the implementation's correctness.

-

The proposal introduces no new privacy concerns.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

This RFC should not introduce any performance impact.

-

Ergonomics

-

This RFC does not affect the current parachains, nor the parachains that intend to use the one-time payment model for parachain registration.

-

Compatibility

-

This RFC does not break compatibility.

-

Prior Art and References

-

Prior discussion on this topic: https://github.com/paritytech/polkadot-sdk/issues/1796

-

Unresolved Questions

-

None at this time.

- -

As noted in this GitHub issue, we want to raise the per-byte cost of on-chain data storage. However, a substantial increase in this cost would make it highly impractical for on-demand parachains to register on Polkadot. -This RFC offers an alternative solution for on-demand parachains, ensuring that the per-byte cost increase doesn't overly burden the registration process.

-

(source)

-

Table of Contents

- -

RFC-0054: Remove the concept of "heap pages" from the client

-
- - - -
Start Date2023-11-24
DescriptionRemove the concept of heap pages from the client and move it to the runtime.
AuthorsPierre Krieger
-
-

Summary

-

Rather than enforce a limit to the total memory consumption on the client side by loading the value at :heappages, enforce that limit on the runtime side.

-

Motivation

-

From the early days of Substrate up until recently, the runtime was present in two forms: the wasm runtime (wasm bytecode passed through an interpreter) and the native runtime (native code directly run by the client).

-

Since the wasm runtime has a lower amount of available memory (4 GiB maximum) compared to the native runtime, and in order to ensure sure that the wasm and native runtimes always produce the same outcome, it was necessary to clamp the amount of memory available to both runtimes to the same value.

-

In order to achieve this, a special storage key (a "well-known" key) :heappages was introduced and represents the number of "wasm pages" (one page equals 64kiB) of memory that are available to the memory allocator of the runtimes. If this storage key is absent, it defaults to 2048, which is 128 MiB.

-

The native runtime has since then been disappeared, but the concept of "heap pages" still exists. This RFC proposes a simplification to the design of Polkadot by removing the concept of "heap pages" as is currently known, and proposes alternative ways to achieve the goal of limiting the amount of memory available.

-

Stakeholders

-

Client implementers and low-level runtime developers.

-

Explanation

-

This RFC proposes the following changes to the client:

- -

With these changes, the memory available to the runtime is now only bounded by the available memory space (4 GiB), and optionally by the maximum amount of memory specified in the Wasm binary (see https://webassembly.github.io/spec/core/bikeshed/#memories%E2%91%A0). In Rust, the latter can be controlled during compilation with the flag -Clink-arg=--max-memory=....

-

Since the client-side change is strictly more tolerant than before, we can perform the change immediately after the runtime has been updated, and without having to worry about backwards compatibility.

-

This RFC proposes three alternative paths (different chains might choose to follow different paths):

- -

Each parachain can choose the option that they prefer, but the author of this RFC strongly suggests either option C or B.

-

Drawbacks

-

In case of path A, there is one situation where the behaviour pre-RFC is not equivalent to the one post-RFC: when a host function that performs an allocation (for example ext_storage_get) is called, without this RFC this allocation might fail due to reaching the maximum heap pages, while after this RFC this will always succeed. -This is most likely not a problem, as storage values aren't supposed to be larger than a few megabytes at the very maximum.

-

In the unfortunate event where the runtime runs out of memory, path B would make it more difficult to relax the memory limit, as we would need to re-upload the entire Wasm, compared to updating only :heappages in path A or before this RFC. -In the case where the runtime runs out of memory only in the specific event where the Wasm runtime is modified, this could brick the chain. However, this situation is no different than the thousands of other ways that a bug in the runtime can brick a chain, and there's no reason to be particularily worried about this situation in particular.

-

Testing, Security, and Privacy

-

This RFC would reduce the chance of a consensus issue between clients. -The :heappages are a rather obscure feature, and it is not clear what happens in some corner cases such as the value being too large (error? clamp?) or malformed. This RFC would completely erase these questions.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

In case of path A, it is unclear how performances would be affected. Path A consists in moving client-side operations to the runtime without changing these operations, and as such performance differences are expected to be minimal. Overall, we're talking about one addition/subtraction per malloc and per free, so this is more than likely completely negligible.

-

In case of path B and C, the performance gain would be a net positive, as this RFC strictly removes things.

-

Ergonomics

-

This RFC would isolate the client and runtime more from each other, making it a bit easier to reason about the client or the runtime in isolation.

-

Compatibility

-

Not a breaking change. The runtime-side changes can be applied immediately (without even having to wait for changes in the client), then as soon as the runtime is updated, the client can be updated without any transition period. One can even consider updating the client before the runtime, as it corresponds to path C.

-

Prior Art and References

-

None.

-

Unresolved Questions

-

None.

- -

This RFC follows the same path as https://github.com/polkadot-fellows/RFCs/pull/4 by scoping everything related to memory allocations to the runtime.

-

(source)

-

Table of Contents

- -

RFC-0070: X Track for @kusamanetwork

-
- - - -
Start DateJanuary 29, 2024
DescriptionAdd a governance track to facilitate posts on the @kusamanetwork's X account
AuthorAdam Clay Steeber
-
-

Summary

-

This RFC proposes adding a trivial governance track on Kusama to facilitate X (formerly known as Twitter) posts on the @kusamanetwork account. The technical aspect -of implementing this in the runtime is very inconsequential and straight-forward, though it might get more technical if the Fellowship wants to regulate this track -with a non-existent permission set. If this is implemented it would need to be followed up with:

-
    -
  1. the establishment of specifications for proposing X posts via this track, and
  2. -
  3. the development of tools/processes to ensure that the content contained in referenda enacted in this track would be automatically posted on X.
  4. -
-

Motivation

-

The overall motivation for this RFC is to decentralize the management of the Kusama brand/communication channel to KSM holders. This is necessary in my opinion primarily -because of the inactivity of the account in recent history, with posts spanning weeks or months apart. I am currently unaware of who/what entity manages the Kusama -X account, but if they are affiliated with Parity or W3F this proposed solution could also offload some of the legal ramifications of making (or not making) -announcements to the public regarding Kusama. While centralized control of the X account would still be present, it could become totally moot if this RFC is implemented -and the community becomes totally autonomous in the management of Kusama's X posts.

-

This solution does not cover every single communication front for Kusama, but it does cover one of the largest. It also establishes a precedent for other communication channels -that could be offloaded to openGov, provided this proof-of-concept is successful.

-

Finally, this RFC is the epitome of experimentation that Kusama is ideal for. This proposal may spark newfound excitement for Kusama and help us realize Kusama's potential -for pushing boundaries and trying new unconventional ideas.

-

Stakeholders

-

This idea has not been formalized by any individual (or group of) KSM holder(s). To my knowledge the socialization of this idea is contained -entirely in my recent X post here, but it is possible that an idea like this one has been discussed in -other places. It appears to me that the ecosystem would welcome a change like this which is why I am taking action to formalize the discussion.

-

Explanation

-

The implementation of this idea can be broken down into 3 primary phases:

-

Phase 1 - Track configurations

-

First, we begin with this RFC to ensure all feedback can be discussed and implemented in the proposal. After the Fellowship and the community come to a reasonable -agreement on the changes necessary to make this happen, the Fellowship can merge changes into Kusama's runtime to include this new track with appropriate track configurations. -As a starting point, I recommend the following track configurations:

-
const APP_X_POST: Curve = Curve::make_linear(7, 28, percent(50), percent(100));
-const SUP_X_POST: Curve = Curve::make_reciprocal(?, ?, percent(?), percent(?), percent(?));
-
-// I don't know how to configure the make_reciprocal variables to get what I imagine for support,
-// but I recommend starting at 50% support and sharply decreasing such that 1% is sufficient quarterway
-// through the decision period and hitting 0% at the end of the decision period, or something like that.
-
-	(
-		69,
-		pallet_referenda::TrackInfo {
-			name: "x_post",
-			max_deciding: 50,
-			decision_deposit: 1 * UNIT,
-			prepare_period: 10 * MINUTES,
-			decision_period: 4 * DAYS,
-			confirm_period: 10 * MINUTES,
-			min_enactment_period: 1 * MINUTES,
-			min_approval: APP_X_POST,
-			min_support: SUP_X_POST,
-		},
-	),
-
-

I also recommend restricting permissions of this track to only submitting remarks or batches of remarks - that's all we'll need for its purpose. I'm not sure how -easy that is to configure, but it is important since we don't want such an agile track to be able to make highly consequential calls.

-

Phase 2 - Establish Specs for X Post Track Referenda

-

It is important that we establish the specifications of referenda that will be submitted in this track to ensure that whatever automation tool is built can easily -make posts once a referendum is enacted. As stated above, we really only need a system.remark (or batch of remarks) to indicate the contents of a proposed X post. -The most straight-forward way to do this is to require remarks to adhere to X's requirements for making posts via their API.

-

For example, if I wanted to propose a post that contained the text "Hello World!" I would propose a referendum in the X post track that contains the following call data: -0x0000607b2274657874223a202248656c6c6f20576f726c6421227d (i.e. system.remark('{"text": "Hello World!"}')).

-

At first, we could support text posts only to prove the concept. Later on we could expand this spec to add support for media, likes, retweets, replies, polls, and -whatever other X features we want.

-

Phase 3 - Release, Tooling, & Documentation

-

Once we agree on track configurations and specs for referenda in this track, the Fellowship can move forward with merging these changes into Kusama's runtime and -include them in its next release. We could also move forward with developing the necessary tools that would listen for enacted referenda to post automatically on X. -This would require coordination with whoever controls the X account; they would either need to run the tools themselves or add a third party as an authorized user to -run the tools to make posts on the account's behalf. This is a bottleneck for decentralization, but as long as the tools are run by the X account manager or by a trusted third party -it should be fine. I'm open to more decentralized solutions, but those always come at a cost of complexity.

-

For the tools themselves, we could open a bounty on Kusama for developers/teams to bid on. We could also just ask the community to step up with a Treasury proposal -to have anyone fund the build. Or, the Fellowship could make the release of these changes contingent on their endorsement of developers/teams to build these tools. Lots of options! -For the record, me and my team could develop all the necessary tools, but all because I'm proposing these changes doesn't entitle me to funds to build the tools needed -to implement them. Here's what would be needed:

- -

After everything is complete, we can update the Kusama wiki to include documentation on the X post specifications and include links to the tools/UI.

-

Drawbacks

-

The main drawback to this change is that it requires a lot of off-chain coordination. It's easy enough to include the track on Kusama but it's a totally different -challenge to make it function as intended. The tools need to be built and the auth tokens need to be managed. It would certainly add an administrative burden to whoever -manages the X account since they would either need to run the tools themselves or manage auth tokens.

-

This change also introduces on-going costs to the Treasury since it would need to compensate people to support the tools necessary to facilitate this idea. The ultimate -question is whether these on-going costs would be worth the ability for KSM holders to make posts on Kusama's X account.

-

There's also the risk of misconfiguring the track to make referenda too easy to pass, potentially allowing a malicious actor to get content posted on X that violates X's ToS. -If that happens, we risk getting Kusama banned on X!

-

This change might also be outside the scope of the Fellowship/openGov. Perhaps the best solution for the X account is to have the Treasury pay for a professional -agency to manage posts. It wouldn't be decentralized but it would probably be more effective in terms of creating good content.

-

Finally, this solution is merely pseudo-decentralization since the X account manager would still have ultimate control of the account. It's decentralized insofar as -the auth tokens are given to people actually running the tools; a house of cards is required to facilitate X posts via this track. Not ideal.

-

Testing, Security, and Privacy

-

There's major precedent for configuring tracks on openGov given the amount of power tracks have, so it shouldn't be hard to come up with a sound configuration. -That's why I recommend restricting permissions of this track to remarks and batches of remarks, or something equally inconsequential.

-

Building the tools for this implementation is really straight-forward and could be audited by Fellowship members, and the community at large, on Github.

-

The largest security concern would be the management of Kusama's X account's auth tokens. We would need to ensure that they aren't compromised.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

If a track on Kusama promises users that compliant referenda enacted therein would be posted on Kusama's X account, users would expect that track to perform as promised. -If the house of cards tumbles down and a compliant referendum doesn't actually get anything posted, users might think that Kusama is broken or unreliable. This -could be damaging to Kusama's image and cause people to question the soundness of other features on Kusama.

-

As mentioned in the drawbacks, the performance of this feature would depend on off-chain coordinations. We can reduce the administrative burden of these coordinations -by funding third parties with the Treasury to deal with it, but then we're relying on trusting these parties.

-

Ergonomics

-

By adding a new track to Kusama, governance platforms like Polkassembly or Nova Wallet would need to include it on their applications. This shouldn't be too -much of a burden or overhead since they've already built the infrastructure for other openGov tracks.

-

Compatibility

-

This change wouldn't break any compatibility as far as I know.

-

References

-

One reference to a similar feature requiring on-chain/off-chain coordination would be the Kappa-Sigma-Mu Society. Nothing on-chain necessarily enforces the rules -or facilitates bids, challenges, defenses, etc. However, the Society has managed to maintain itself with integrity to its rules. So I don't think this is totally -out of Kusama's scope. But it will require some off-chain effort to maintain.

-

Unresolved Questions

- -

(source)

-

Table of Contents

- -

RFC-0073: Decision Deposit Referendum Track

-
- - - -
Start Date12 February 2024
DescriptionAdd a referendum track which can place the decision deposit on any other track
AuthorsJelliedOwl
-
-

Summary

-

The current size of the decision deposit on some tracks is too high for many proposers. As a result, those needing to use it have to find someone else willing to put up the deposit for them - and a number of legitimate attempts to use the root track have timed out. This track would provide a more affordable (though slower) route for these holders to use the root track.

-

Motivation

-

There have been recent attempts to use the Kusama root track which have timed out with no decision deposit placed. Usually, these referenda have been related to parachain registration related issues.

-

Explanation

-

Propose to address this by adding a new referendum track [22] Referendum Deposit which can place the decision deposit on another referendum. This would require the following changes:

- -

Referendum track parameters - Polkadot

- -

Referendum track parameters - Kusama

- -

Drawbacks

-

This track would provide a route to starting a root referendum with a much-reduced slashable deposit. This might be undesirable but, assuming the decision deposit cost for this track is still high enough, slashing would still act as a disincentive.

-

An alternative to this might be to reduce the decision deposit size some of the more expensive tracks. However, part of the purpose of the high deposit - at least on the root track - is to prevent spamming the limited queue with junk referenda.

-

Testing, Security, and Privacy

-

Will need additional tests case for the modified pallet and runtime. No security or privacy issues.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

No significant performance impact.

-

Ergonomics

-

Only changes related to adding the track. Existing functionality is unchanged.

-

Compatibility

-

No compatibility issues.

-

Prior Art and References

- -

Unresolved Questions

-

Feedback on whether my proposed implementation of this is the best way to address the issue - including which calls the track should be allowed to make. Are the track parameters correct or should be use something different? Alternative would be welcome.

-

(source)

-

Table of Contents

- -

RFC-0074: Stateful Multisig Pallet

-
- - - -
Start Date15 February 2024
DescriptionAdd Enhanced Multisig Pallet to System chains
AuthorsAbdelrahman Soliman (Boda)
-
-

Summary

-

A pallet to facilitate enhanced multisig accounts. The main enhancement is that we store a multisig account in the state with related info (signers, threshold,..etc). The module affords enhanced control over administrative operations such as adding/removing signers, changing the threshold, account deletion, canceling an existing proposal. Each signer can approve/reject a proposal while still exists. The proposal is not intended for migrating or getting rid of existing multisig. It's to allow both options to coexist.

-

For the rest of the RFC We use the following terms:

- -

Motivation

-

Problem

-

Entities in the Polkadot ecosystem need to have a way to manage their funds and other operations in a secure and efficient way. Multisig accounts are a common way to achieve this. Entities by definition change over time, members of the entity may change, threshold requirements may change, and the multisig account may need to be deleted. For even more enhanced hierarchical control, the multisig account may need to be controlled by other multisig accounts.

-

Current native solutions for multisig operations are less optimal, performance-wise (as we'll explain later in the RFC), and lack fine-grained control over the multisig account.

-

Stateless Multisig

-

We refer to current multisig pallet in polkadot-sdk because the multisig account is only derived and not stored in the state. Although deriving the account is determinsitc as it relies on exact users (sorted) and thershold to derive it. This does not allow for control over the multisig account. It's also tightly coupled to exact users and threshold. This makes it hard for an organization to manage existing accounts and to change the threshold or add/remove signers.

-

We believe as well that the stateless multisig is not efficient in terms of block footprint as we'll show in the performance section.

-

Pure Proxy

-

Pure proxy can achieve having a stored and determinstic multisig account from different users but it's unneeded complexity as a way around the limitations of the current multisig pallet. It doesn't also have the same fine grained control over the multisig account.

-

Other points mentioned by @tbaut

- -

Requirements

-

Basic requirements for the Stateful Multisig are:

- -

Use Cases

- -

and much more...

-

Stakeholders

- -

Explanation

-

I've created the stateful multisig pallet during my studies in Polkadot Blockchain Academy under supervision from @shawntabrizi and @ank4n. After that, I've enhanced it to be fully functional and this is a draft PR#3300 in polkadot-sdk. I'll list all the details and design decisions in the following sections. Note that the PR is not 1-1 exactly to the current RFC as the RFC is a more polished version of the PR after updating based on the feedback and discussions.

-

Let's start with a sequence diagram to illustrate the main operations of the Stateful Multisig.

-

multisig operations

-

Notes on above diagram:

- -

State Transition Functions

-

having the following enum to store the call or the hash:

-
#![allow(unused)]
-fn main() {
-enum CallOrHash<T: Config> {
-	Call(<T as Config>::RuntimeCall),
-	Hash(T::Hash),
-}
-}
- -
#![allow(unused)]
-fn main() {
-		/// Creates a new multisig account and attach signers with a threshold to it.
-		///
-		/// The dispatch origin for this call must be _Signed_. It is expected to be a nomral AccountId and not a
-		/// Multisig AccountId.
-		///
-		/// T::BaseCreationDeposit + T::PerSignerDeposit * signers.len() will be held from the caller's account.
-		///
-		/// # Arguments
-		///
-		/// - `signers`: Initial set of accounts to add to the multisig. These may be updated later via `add_signer`
-		/// and `remove_signer`.
-		/// - `threshold`: The threshold number of accounts required to approve an action. Must be greater than 0 and
-		/// less than or equal to the total number of signers.
-		///
-		/// # Errors
-		///
-		/// * `TooManySignatories` - The number of signatories exceeds the maximum allowed.
-		/// * `InvalidThreshold` - The threshold is greater than the total number of signers.
-		pub fn create_multisig(
-			origin: OriginFor<T>,
-			signers: BoundedBTreeSet<T::AccountId, T::MaxSignatories>,
-			threshold: u32,
-		) -> DispatchResult 
-}
- -
#![allow(unused)]
-fn main() {
-		/// Starts a new proposal for a dispatchable call for a multisig account.
-		/// The caller must be one of the signers of the multisig account.
-		/// T::ProposalDeposit will be held from the caller's account.
-		///
-		/// # Arguments
-		///
-		/// * `multisig_account` - The multisig account ID.
-		/// * `call_or_hash` - The enum having the call or the hash of the call to be approved and executed later.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `UnAuthorizedSigner` - The caller is not an signer of the multisig account.
-		/// * `TooManySignatories` - The number of signatories exceeds the maximum allowed. (shouldn't really happen as it's the first approval)
-		pub fn start_proposal(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Approves a proposal for a dispatchable call for a multisig account.
-		/// The caller must be one of the signers of the multisig account.
-		///
-		/// If a signer did approve -> reject -> approve, the proposal will be approved.
-		/// If a signer did approve -> reject, the proposal will be rejected.
-		///
-		/// # Arguments
-		///
-		/// * `multisig_account` - The multisig account ID.
-		/// * `call_or_hash` - The enum having the call or the hash of the call to be approved.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `UnAuthorizedSigner` - The caller is not an signer of the multisig account.
-		/// * `TooManySignatories` - The number of signatories exceeds the maximum allowed.
-		/// This shouldn't really happen as it's an approval, not an addition of a new signer.
-		pub fn approve(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Rejects a proposal for a multisig account.
-		/// The caller must be one of the signers of the multisig account.
-		///
-		/// Between approving and rejecting, last call wins.
-		/// If a signer did approve -> reject -> approve, the proposal will be approved.
-		/// If a signer did approve -> reject, the proposal will be rejected.
-		///
-		/// # Arguments
-		///
-		/// * `multisig_account` - The multisig account ID.
-		/// * `call_or_hash` - The enum having the call or the hash of the call to be rejected.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `UnAuthorizedSigner` - The caller is not an signer of the multisig account.
-		/// * `SignerNotFound` - The caller has not approved the proposal.
-		#[pallet::call_index(3)]
-		#[pallet::weight(Weight::default())]
-		pub fn reject(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Executes a proposal for a dispatchable call for a multisig account.
-		/// Poropsal needs to be approved by enough signers (exceeds or equal multisig threshold) before it can be executed.
-		/// The caller must be one of the signers of the multisig account.
-		///
-		/// This function does an extra check to make sure that all approvers still exist in the multisig account.
-		/// That is to make sure that the multisig account is not compromised by removing an signer during an active proposal.
-		///
-		/// Once finished, the withheld deposit will be returned to the proposal creator.
-		///
-		/// # Arguments
-		///
-		/// * `multisig_account` - The multisig account ID.
-		/// * `call_or_hash` - We should have gotten the RuntimeCall (preimage) and stored it in the proposal by the time the extrinsic is called.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `UnAuthorizedSigner` - The caller is not an signer of the multisig account.
-		/// * `NotEnoughApprovers` - approvers don't exceed the threshold.
-		/// * `ProposalNotFound` -  The proposal does not exist.
-		/// * `CallPreImageNotFound` -  The proposal doesn't have the preimage of the call in the state.
-		pub fn execute_proposal(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Cancels an existing proposal for a multisig account.
-		/// Poropsal needs to be rejected by enough signers (exceeds or equal multisig threshold) before it can be executed.
-		/// The caller must be one of the signers of the multisig account.
-		///
-		/// This function does an extra check to make sure that all rejectors still exist in the multisig account.
-		/// That is to make sure that the multisig account is not compromised by removing an signer during an active proposal.
-		///
-		/// Once finished, the withheld deposit will be returned to the proposal creator./
-		///
-		/// # Arguments
-		///
-		/// * `origin` - The origin multisig account who wants to cancel the proposal.
-		/// * `call_or_hash` - The call or hash of the call to be canceled.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `ProposalNotFound` - The proposal does not exist.
-		pub fn cancel_proposal(
-		origin: OriginFor<T>, 
-		multisig_account: T::AccountId, 
-		call_or_hash: CallOrHash) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Cancels an existing proposal for a multisig account Only if the proposal doesn't have approvers other than
-		/// the proposer.
-		///
-		///	This function needs to be called from a the proposer of the proposal as the origin.
-		///
-		/// The withheld deposit will be returned to the proposal creator.
-		///
-		/// # Arguments
-		///
-		/// * `multisig_account` - The multisig account ID.
-		/// * `call_or_hash` - The hash of the call to be canceled.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `ProposalNotFound` - The proposal does not exist.
-		pub fn cancel_own_proposal(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Cleanup proposals of a multisig account. This function will iterate over a max limit per extrinsic to ensure
-		/// we don't have unbounded iteration over the proposals.
-		///
-		/// The withheld deposit will be returned to the proposal creator.
-		///
-		/// # Arguments
-		///
-		/// * `multisig_account` - The multisig account ID.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `ProposalNotFound` - The proposal does not exist.
-		pub fn cleanup_proposals(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-		) -> DispatchResult
-}
-

Note: Next functions need to be called from the multisig account itself. Deposits are reserved from the multisig account as well.

- -
#![allow(unused)]
-fn main() {
-		/// Adds a new signer to the multisig account.
-		/// This function needs to be called from a Multisig account as the origin.
-		/// Otherwise it will fail with MultisigNotFound error.
-		///
-		/// T::PerSignerDeposit will be held from the multisig account.
-		///
-		/// # Arguments
-		///
-		/// * `origin` - The origin multisig account who wants to add a new signer to the multisig account.
-		/// * `new_signer` - The AccountId of the new signer to be added.
-		/// * `new_threshold` - The new threshold for the multisig account after adding the new signer.
-		///
-		/// # Errors
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `InvalidThreshold` - The threshold is greater than the total number of signers or is zero.
-		/// * `TooManySignatories` - The number of signatories exceeds the maximum allowed.
-		pub fn add_signer(
-			origin: OriginFor<T>,
-			new_signer: T::AccountId,
-			new_threshold: u32,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Removes an  signer from the multisig account.
-		/// This function needs to be called from a Multisig account as the origin.
-		/// Otherwise it will fail with MultisigNotFound error.
-		/// If only one signer exists and is removed, the multisig account and any pending proposals for this account will be deleted from the state.
-		///
-		/// # Arguments
-		///
-		/// * `origin` - The origin multisig account who wants to remove an signer from the multisig account.
-		/// * `signer_to_remove` - The AccountId of the signer to be removed.
-		/// * `new_threshold` - The new threshold for the multisig account after removing the signer. Accepts zero if
-		/// the signer is the only one left.kkk
-		///
-		/// # Errors
-		///
-		/// This function can return the following errors:
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `InvalidThreshold` - The new threshold is greater than the total number of signers or is zero.
-		/// * `UnAuthorizedSigner` - The caller is not an signer of the multisig account.
-		pub fn remove_signer(
-			origin: OriginFor<T>,
-			signer_to_remove: T::AccountId,
-			new_threshold: u32,
-		) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Sets a new threshold for a multisig account.
-		///	This function needs to be called from a Multisig account as the origin.
-		/// Otherwise it will fail with MultisigNotFound error.
-		///
-		/// # Arguments
-		///
-		/// * `origin` - The origin multisig account who wants to set the new threshold.
-		/// * `new_threshold` - The new threshold to be set.
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		/// * `InvalidThreshold` - The new threshold is greater than the total number of signers or is zero.
-		set_threshold(origin: OriginFor<T>, new_threshold: u32) -> DispatchResult
-}
- -
#![allow(unused)]
-fn main() {
-		/// Deletes a multisig account and all related proposals.
-		///
-		///	This function needs to be called from a Multisig account as the origin.
-		/// Otherwise it will fail with MultisigNotFound error.
-		///
-		/// # Arguments
-		///
-		/// * `origin` - The origin multisig account who wants to cancel the proposal.
-		///
-		/// # Errors
-		///
-		/// * `MultisigNotFound` - The multisig account does not exist.
-		pub fn delete_account(origin: OriginFor<T>) -> DispatchResult
-}
-

Storage/State

- -
#![allow(unused)]
-fn main() {
-#[pallet::storage]
-  pub type MultisigAccount<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, MultisigAccountDetails<T>>;
-
-/// The set of open multisig proposals. A proposal is uniquely identified by the multisig account and the call hash.
-/// (maybe a nonce as well in the future)
-#[pallet::storage]
-pub type PendingProposals<T: Config> = StorageDoubleMap<
-    _,
-    Twox64Concat,
-    T::AccountId, // Multisig Account
-    Blake2_128Concat,
-    T::Hash, // Call Hash
-    MultisigProposal<T>,
->;
-}
-

As for the values:

-
#![allow(unused)]
-fn main() {
-pub struct MultisigAccountDetails<T: Config> {
-	/// The signers of the multisig account. This is a BoundedBTreeSet to ensure faster operations (add, remove).
-	/// As well as lookups and faster set operations to ensure approvers is always a subset from signers. (e.g. in case of removal of an signer during an active proposal)
-	pub signers: BoundedBTreeSet<T::AccountId, T::MaxSignatories>,
-	/// The threshold of approvers required for the multisig account to be able to execute a call.
-	pub threshold: u32,
-	pub deposit: BalanceOf<T>,
-}
-}
-
#![allow(unused)]
-fn main() {
-pub struct MultisigProposal<T: Config> {
-    /// Proposal creator.
-    pub creator: T::AccountId,
-    pub creation_deposit: BalanceOf<T>,
-    /// The extrinsic when the multisig operation was opened.
-    pub when: Timepoint<BlockNumberFor<T>>,
-    /// The approvers achieved so far, including the depositor.
-    /// The approvers are stored in a BoundedBTreeSet to ensure faster lookup and operations (approve, reject).
-    /// It's also bounded to ensure that the size don't go over the required limit by the Runtime.
-    pub approvers: BoundedBTreeSet<T::AccountId, T::MaxSignatories>,
-    /// The rejectors for the proposal so far.
-    /// The rejectors are stored in a BoundedBTreeSet to ensure faster lookup and operations (approve, reject).
-    /// It's also bounded to ensure that the size don't go over the required limit by the Runtime.
-    pub rejectors: BoundedBTreeSet<T::AccountId, T::MaxSignatories>,
-    /// The block number until which this multisig operation is valid. None means no expiry.
-    pub expire_after: Option<BlockNumberFor<T>>,
-}
-}
-

For optimization we're using BoundedBTreeSet to allow for efficient lookups and removals. Especially in the case of approvers, we need to be able to remove an approver from the list when they reject their approval. (which we do lazily when execute_proposal is called).

-

There's an extra storage map for the deposits of the multisig accounts per signer added. This is to ensure that we can release the deposits when the multisig removes them even if the constant deposit per signer changed in the runtime later on.

-

Considerations & Edge cases

-

Removing an signer from the multisig account during an active proposal

-

We need to ensure that the approvers are always a subset from signers. This is also partially why we're using BoundedBTreeSet for signers and approvers. Once execute proposal is called we ensure that the proposal is still valid and the approvers are still a subset from current signers.

-

Multisig account deletion and cleaning up existing proposals

-

Once the last signer of a multisig account is removed or the multisig approved the account deletion we delete the multisig accound from the state and keep the proposals until someone calls cleanup_proposals multiple times which iterates over a max limit per extrinsic. This is to ensure we don't have unbounded iteration over the proposals. Users are already incentivized to call cleanup_proposals to get their deposits back.

-

Multisig account deletion and existing deposits

-

We currently just delete the account without checking for deposits (Would like to hear your thoughts here). We can either

- -

Approving a proposal after the threshold is changed

-

We always use latest threshold and don't store each proposal with different threshold. This allows the following:

- -

Drawbacks

- -

Testing, Security, and Privacy

-

Standard audit/review requirements apply.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

Doing back of the envelop calculation to proof that the stateful multisig is more efficient than the stateless multisig given it's smaller footprint size on blocks.

-

Quick review over the extrinsics for both as it affects the block size:

-

Stateless Multisig: -Both as_multi and approve_as_multi has a similar parameters:

-
#![allow(unused)]
-fn main() {
-origin: OriginFor<T>,
-threshold: u16,
-other_signatories: Vec<T::AccountId>,
-maybe_timepoint: Option<Timepoint<BlockNumberFor<T>>>,
-call_hash: [u8; 32],
-max_weight: Weight,
-}
-

Stateful Multisig: -We have the following extrinsics:

-
#![allow(unused)]
-fn main() {
-pub fn start_proposal(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		)
-}
-
#![allow(unused)]
-fn main() {
-pub fn approve(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		)
-}
-
#![allow(unused)]
-fn main() {
-pub fn execute_proposal(
-			origin: OriginFor<T>,
-			multisig_account: T::AccountId,
-			call_or_hash: CallOrHash,
-		)
-}
-

The main takeway is that we don't need to pass the threshold and other signatories in the extrinsics. This is because we already have the threshold and signatories in the state (only once).

-

So now for the caclulations, given the following:

- -

The table calculates if each of the K multisig accounts has one proposal and it gets approved by the 2N/3 and then executed. How much did the total Blocks and States sizes increased by the end of the day.

-

Note: We're not calculating the cost of proposal as both in statefull and stateless multisig they're almost the same and gets cleaned up from the state once the proposal is executed or canceled.

-

Stateless effect on blocksizes = 2/3KN^2 (as each user of the 2/3 users will need to call approve_as_multi with all the other signatories(N) in extrinsic body)

-

Stateful effect on blocksizes = K * N (as each user will need to call approve with the multisig account only in extrinsic body)

-

Stateless effect on statesizes = Nil (as the multisig account is not stored in the state)

-

Stateful effect on statesizes = K*N (as each multisig account (K) will be stored with all the signers (K) in the state)

-
- - -
PalletBlock SizeState Size
Stateless2/3KN^2Nil
StatefulK*NK*N
-
-

Simplified table removing K from the equation: -| Pallet | Block Size | State Size | -|----------------|:-------------:|-----------:| -| Stateless | N^2 | Nil | -| Stateful | N | N |

-

So even though the stateful multisig has a larger state size, it's still more efficient in terms of block size and total footprint on the blockchain.

-

Ergonomics

-

The Stateful Multisig will have better ergonomics for managing multisig accounts for both developers and end-users.

-

Compatibility

-

This RFC is compatible with the existing implementation and can be handled via upgrades and migration. It's not intended to replace the existing multisig pallet.

-

Prior Art and References

-

multisig pallet in polkadot-sdk

-

Unresolved Questions

- - - -

(source)

-

Table of Contents

- -

RFC-0077: Increase maximum length of identity PGP fingerprint values from 20 bytes

-
- - - -
Start Date20 Feb 2024
DescriptionIncrease the maximum length of identity PGP fingerprint values from 20 bytes
AuthorsLuke Schoen
-
-

Summary

-

This proposes to increase the maximum length of PGP Fingerprint values from a 20 bytes/chars limit to a 40 bytes/chars limit.

-

Motivation

-

Background

-

Pretty Good Privacy (PGP) Fingerprints are shorter versions of their corresponding Public Key that may be printed on a business card.

-

They may be used by someone to validate the correct corresponding Public Key.

-

It should be possible to add PGP Fingerprints to Polkadot on-chain identities.

-

GNU Privacy Guard (GPG) is compliant with PGP and the two acronyms are used interchangeably.

-

Problem

-

If you want to set a Polkadot on-chain identity, users may provide a PGP Fingerprint value in the "pgpFingerprint" field, which may be longer than 20 bytes/chars (e.g. PGP Fingerprints are 40 bytes/chars long), however that field can only store a maximum length of 20 bytes/chars of information.

-

Possible disadvantages of the current 20 bytes/chars limitation:

- -

Solution Requirements

-

The maximum length of identity PGP Fingerprint values should be increased from the current 20 bytes/chars limit at least a 40 bytes/chars limit to support PGP Fingerprints and GPG Fingerprints.

-

Stakeholders

- -

Explanation

-

If a user tries to setting an on-chain identity by creating an extrinsic using Polkadot.js with identity > setIdentity(info), then if they try to provide their 40 character long PGP Fingerprint or GPG Fingerprint, which is longer than the maximum length of 20 bytes/chars [u8;20], then they will encounter this error:

-
createType(Call):: Call: failed decoding identity.setIdentity:: Struct: failed on args: {...}:: Struct: failed on pgpFingerprint: Option<[u8;20]>:: Expected input with 20 bytes (160 bits), found 40 bytes
-
-

Increasing maximum length of identity PGP Fingerprint values from the current 20 bytes/chars limit to at least a 40 bytes/chars limit would overcome these errors and support PGP Fingerprints and GPG Fingerprints, satisfying the solution requirements.

-

Drawbacks

-

No drawbacks have been identified.

-

Testing, Security, and Privacy

-

Implementations would be tested for adherance by checking that 40 bytes/chars PGP Fingerprints are supported.

-

No effect on security or privacy has been identified than already exists.

-

No implementation pitfalls have been identified.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

It would be an optimization, since the associated exposed interfaces to developers and end-users could start being used.

-

To minimize additional overhead the proposal suggests a 40 bytes/chars limit since that would at least provide support for PGP Fingerprints, satisfying the solution requirements.

-

Ergonomics

-

No potential ergonomic optimizations have been identified.

-

Compatibility

-

Updates to Polkadot.js Apps, API and its documentation and those referring to it may be required.

-

Prior Art and References

-

No prior articles or references.

-

Unresolved Questions

-

No further questions at this stage.

- -

Relates to RFC entitled "Increase maximum length of identity raw data values from 32 bytes".

-

(source)

-

Table of Contents

- -

RFC-0088: Add slashable locked deposit, purchaser reputation, and reserved cores for on-chain identities to broker pallet

-
- - - -
Start Date25 Apr 2024
DescriptionAdd slashable locked deposit, purchaser reputation, and reserved cores for on-chain identities to broker pallet
AuthorsLuke Schoen
-
-

Summary

-

This proposes to require a slashable deposit in the broker pallet when initially purchasing or renewing Bulk Coretime or Instantaneous Coretime cores.

-

Additionally, it proposes to record a reputational status based on the behavior of the purchaser, as it relates to their use of Kusama Coretime cores that they purchase, and to possibly reserve a proportion of the cores for prospective purchasers that have an on-chain identity.

-

Motivation

-

Background

-

There are sales of Kusama Coretime cores that are scheduled to occur later this month by Coretime Marketplace Lastic.xyz initially in limited quantities, and potentially also by RegionX in future that is subject to their Polkadot referendum #582. This poses a risk in that some Kusama Coretime core purchasers may buy Kusama Coretime cores when they have no intention of actually placing a workload on them or leasing them out, which would prevent those that wish to purchase and actually use Kusama Coretime cores from being able to use any at cores at all.

-

Problem

-

The types of purchasers may include:

- -

Chaoatic repurcussions could include the following:

- -

Solution Requirements

-
    -
  1. -

    On-chain identity. It may be possible to circumvent bots and scalpers to an extent by requiring a proportion of Kusama Coretime purchasers to have an on-chain identity. As such, a possible solution could be to allow the configuration of a threshold in the Broker pallet that reserves a proportion of the cores for accounts that have an on-chain identity, that reverts to a waiting list of anonymous account purchasers if the reserved proportion of cores remain unsold.

    -
  2. -
  3. -

    Slashable deposit. A viable solution could be to require a slashable deposit to be locked prior to the purchase or renewal of a core, similar to how decision deposits are used in OpenGov to prevent spam, but where if you buy a Kusama Coretime core you could be challenged by one of more collectives of fishermen to provide proof against certain criteria of how you used it, and if you fail to provide adequate evidence in response to that scrutiny, then you would lose a proportion of that deposit and face restrictions on purchasing or renewing cores in future that may also be configured on-chain.

    -
  4. -
  5. -

    Reputation. To disincentivise certain behaviours, a reputational status indicator could be used to record the historic behavior of the purchaser and whether on-chain judgement has determined they have adequately rectified that behaviour, as it relates to their usage of Kusama Coretime cores that they purchase.

    -
  6. -
-

Stakeholders

- -

Drawbacks

-

Performance

-

The slashable deposit if set too high, may result in an economic impact, where less Kusama Coretime core sales are purchased.

-

Testing, Security, and Privacy

-

Lack of a slashable deposit in the Broker pallet is a security concern, since it exposes Kusama Coretime sales to potential abuse.

-

Reserving a proportion of Kusama Coretime sales cores for those with on-chain identities should not be to the exclusion of accounts that wish to remain anonymous or cause cores to be wasted unnecessarily. As such, if cores that are reserved for on-chain identities remain unsold then they should be released to anonymous accounts that are on a waiting list.

-

No implementation pitfalls have been identified.

-

Performance, Ergonomics, and Compatibility

-

Performance

-

It should improve performance as it reduces the potential for state bloat since there is less risk of undesirable Kusama Coretime sales activity that would be apparent with no requirement for a slashable deposit or there being no reputational risk to purchasers that waste or misuse Kusama Coretime cores.

-

The solution proposes to minimize the risk of some Kusama Coretime cores not even being used or leased to perform any tasks at all.

-

It will be important to monitor and manage the slashable deposits, purchaser reputations, and utilization of the proportion of cores that are reserved for accounts with an on-chain identity.

-

Ergonomics

-

The mechanism for setting a slashable deposit amount, should avoid undue complexity for users.

-

Compatibility

-

Updates to Polkadot.js Apps, API and its documentation and those referring to it may be required.

-

Prior Art and References

-

Prior Art

-

No prior articles.

-

Unresolved Questions

-

None

- -

None

-

(source)

-

Table of Contents

- -

RFC-0089: Flexible Inflation

-
- - - -
Start DateMay 6 2024
DescriptionRevise the inflation logic in the runtime such that it can be parameterized and tweaked in an easier and more transparent way.
AuthorsKian Paimani
-
-

Summary

-

This RFC proposes a new pallet_inflation to be added to the Polkadot runtime, which improves -inflation machinery of the Polkadot relay chain in a number of ways:

-
    -
  1. More transparent and easier to understand inflation logic
  2. -
  3. Easier parameterization through governance
  4. -
  5. Decoupled from the staking logic, should inflation and staking happen in two disjoint consensus -systems, as proposed -RFC32.
  6. -
-

Motivation

-

The existing inflation logic in the relay chain suffers from a number of drawbacks:

- -

This RFC, as iterated above, proposes a new pallet_inflation that addresses all of the named -problems. However, this RFC does not propose any changes to the actual inflation rate, but -rather provide a new technical substrate (pun intended), upon which token holders can decide on the -future of the DOT token's inflation in a more clear and transparent way.

-

We argue that one reason why the inflation rate of Polkadot has not significantly change in ~4 years -has been the complicated process of updating it. We hope that with the tools provided in this RFC, -stakeholders can experiment with the inflation rate in a more ergonomic way. Finally, this -experimentation can be considered useful as a final step toward fixing the economics of DOT in JAM, -as proposed in the JAM graypaper.

-

Within the scope of this RFC, we suggest deploying the new inflation pallet in a backwards -compatible way, such that the inflation model does not change in practice, and leave the actual -changes to the token holders and researchers and further governance proposals.

-
-

While mainly intended for Polkadot, the system proposed in this RFC is general enough such that it -can be interpreted as a "general inflation system pallet", and can be used in newly onboarding -parachain.

-
-

Stakeholders

-

This RFC is relevant to the following stakeholders, listed from high to low impact:

- -

Explanation

-

Existing Order

-

First, let's further elaborate on the existing order. The current inflation logic is deeply nested -in pallet_staking, and pallet_staking::Config::EraPayout interface. Through this trait, the -staking pallet is informed how many new tokens should possibly be minted. This amount is divided -into two parts:

- -

As it stands now the implementation of EraPayout which specifies the two amounts above lives in -the respective runtime, and uses the original proposed inflation rate proposed by W3F for Polkadot. -Read more about this model here.

-

At present, the inflation always happens at the end of an era, which is a concept know by the -staking system. The duration of an era is recorded in pallet_staking as milliseconds (as recorded -by the standard pallet_timestamp), is passed to EraPayout as an input, as is measured against -the full year to determine how much should be inflated.

-

New Order

-
-

The naming used in this section is tentative, based on a WIP implementation, and subject to change -before finalization of this RFC.

-
-

The new order splits the process for inflation into two steps:

-
    -
  1. Sourcing the inflation amount: This step merely specifies by how much the chain intends to -inflate its token. This amount is not minted right away, and is instead passed over to the next -step for distribution.
  2. -
  3. Distributing the aforementioned amount: A sequence of functions that decide what needs to be -done with the sourced inflation amount. This process is expected to transfer the inflation -amount to any account that should receive it. This implies that the staking system should, -similar to treasury, have a key-less account that will act as a temporary pot for the inflation -amount.
  4. -
-

In very abstract terms, an example of the above process can be:

- -

A proper configuration of this pallet should use pallet_parameters where possible to allow for any -of the actual values used to specify Sourcing and Distribution to be changed via on-chain -governance. Please see the example configurations section for more -details.

-

In the new model, inflation can happen at any point in time. Since now a new pallet is dedicated to -inflation, and it can internally store the timestamp of the last inflation point, and always inflate -the correct amount. This means that while the duration of a staking era is 1 day, the inflation -process can happen eg. every hour. The opposite is also possible, although more complicated: The -staking/treasury system can possibly receive their corresponding income on a weekly basis, while the -era duration is still 1 day. That being said, we don't recommend using this flexibility as it brings -no clear advantage, and is only extra complexity. We recommend the inflation to still happen shortly -before the end of the staking era. This means that if the inflation sourcing or distribution is -a function of the staking rate, it can reliably use the staking rate of the last era.

-

Finally, as noted above, this RFC implies a new accounting system for staking to keep track of its -staking reward. In short, the new process is as follows: pallet_inflation will mint the staking -portion of inflation directly into a key-less account controlled by pallet_staking. At the end of -each era, pallet_staking will inspect this account, and move whatever amount is paid out into it -to another key-less account associated with the era number. The actual payouts, initiated by stakers, -will transfer from this era account into the corresponding stakers' account.

-
-

Interestingly, this means that any account can possibly contribute to staking rewards by -transferring DOTs to the key-less parent account controlled by the staking system.

-
-

Proposed Implementation

-

A candidate implementation of this RFC can be found in -this -branch of the polkadot-sdk repository. Please note the changes to:

-
    -
  1. substrate/frame/inflation to see the new pallet.
  2. -
  3. substrate/frame/staking to see the integration with the staking pallet.
  4. -
  5. substrate/bin/runtime to see how the pallet can be configured into a runtime.
  6. -
-

Example Configurations

-

The following are working examples from the above implementation candidate, highlighting some of the -outcomes that can be achieved.

-

First, to parameterize the existing proposed implementation to replicate what Polkadot does today, -assuming we incorporate the fixed 2% treasury income, the outcome would be:

-
#![allow(unused)]
-fn main() {
-parameter_types! {
-	pub Distribution: Vec<pallet_inflation::DistributionStep<Runtime>> = vec![
-		// 2% goes to treasury, no questions asked.
-		Box::new(pay::<Runtime, TreasuryAccount, dynamic_params::staking::FixedTreasuryIncome>),
-		// from whatever is left, staking gets all the rest, based on the staking rate.
-		Box::new(polkadot_staking_income::<
-			Runtime,
-			dynamic_params::staking::IdealStakingRate,
-			dynamic_params::staking::Falloff,
-			StakingIncomeAccount
-		>),
-		// Burn anything that is left.
-		Box::new(burn::<Runtime, All>),
-	];
-}
-
-impl pallet_inflation::Config for Runtime {
-	/// Fixed 10% annual inflation.
-	type InflationSource =
-		pallet_inflation::FixedRatioAnnualInflation<Runtime, dynamic_params::staking::MaxInflation>;
-	type Distribution = Distribution;
-}
-}
-

In this snippet, we use a number of components provided by pallet_inflation, namely pay, -polkadot_staking_income, burn and FixedRatioAnnualInflation. Yet, crucially, these components -are fed parameters that are all backed by an instance of the pallet_parameters, namely everything -prefixed by dynamic_params.

-

The above is a purely inflationary system. If one wants to change the inflation to -dis-inflationary, another pre-made component of pallet_inflation can be used:

-
impl pallet_inflation::Config for Runtime {
--	/// Fixed 10% annual inflation.
--	type InflationSource =
--		pallet_inflation::FixedRatioAnnualInflation<Runtime, dynamic_params::staking::MaxInflation>;
-+	type InflationSource = pallet_inflation::FixedAnnualInflation<
-+		Runtime,
-+		dynamic_params::staking::FixedAnnualInflationAmount,
-+	>;
-}
-
-

Whereby FixedAnnualInflationAmount is the fixed absolute value (as opposed to ratio) by -which the chain inflates annually, for example 100m DOTs.

-

Drawbacks

-

The following drawbacks are noted:

-
    -
  1. The solution provided here is possibly an over-engineering, if we want to achieve the goal of -making the existing formula parameterize-able. In that case, we can merely add an instance of the -pallet_parameters to the runtime and make the existing formula's ratios be provided by -governance-controlled parameters. Although, this shortsighted but simpler solution fails to -decouple the staking and inflation logic. This will be an issue depending on whether staking -lives in AssetHub, or its independent parachain.
  2. -
  3. Some of the interfaces proposed in the draft implementation still leak the implementation detail -of the inflation amount being reliant on eg. the staking-rate. We acknowledge this as a drawback, -but given that many PoS inflationary systems rely on the staking rate, we believe it is a -reasonable compromise. Such parameters can be ignored if the implementation does not need them.
  4. -
-

Testing, Security, and Privacy

-

The new pallet_inflation, among its integration into pallet_staking must be thoroughly audited -and reviewed by fellows. We also emphasize on simulating the actual inflation logic using the real -polkadot state with Chopsticks and try-runtime.

-

Performance, Ergonomics, and Compatibility

-

The proposed system in this RFC implies a handful of extra storage reads and writes "per inflation -cycle", but given that a reasonable instance of this pallet would probably decide to inflation eg. -once per day, the performance impact is negligible.

-

The drawback section above noted some ergonomic concerns.

-

The "New Order" section above notes the compatibility notes with the existing staking -and inflation system.

-

Prior Art and References

- -

Unresolved Questions

- - - -

(source)

-

Table of Contents

- -

RFC-0001: Secondary Market for Regions

-
- - - -
Start Date2024-06-09
DescriptionImplement a secondary market for region listings and sales
AuthorsAurora Poppyseed, Philip Lucsok
-
-

Summary

-

This RFC proposes the addition of a secondary market feature to either the broker pallet or as a separate pallet maintained by Lastic, enabling users to list and purchase regions. This includes creating, purchasing, and removing listings, as well as emitting relevant events and handling associated errors.

-

Motivation

-

Currently, the broker pallet lacks functionality for a secondary market, which limits users' ability to freely trade regions. This RFC aims to introduce a secure and straightforward mechanism for users to list regions they own for sale and allow other users to purchase these regions.

-

While integrating this functionality directly into the broker pallet is one option, another viable approach is to implement it as a separate pallet maintained by Lastic. This separate pallet would have access to the broker pallet and add minimal functionality necessary to support the secondary market.

-

Adding smart contracts to the Coretime chain could also address this need; however, this process is expected to be lengthy and complex. We cannot afford to wait for this extended timeline to enable basic secondary market functionality. By proposing either integration into the broker pallet or the creation of a dedicated pallet, we can quickly enhance the flexibility and utility of the broker pallet, making it more user-friendly and valuable.

-

Stakeholders

-

Primary stakeholders include:

- -

Explanation

-

This RFC introduces the following key features:

-
    -
  1. -

    Storage Changes:

    - -
  2. -
  3. -

    New Dispatchable Functions:

    - -
  4. -
  5. -

    Events:

    - -
  6. -
  7. -

    Error Handling:

    - -
  8. -
  9. -

    Testing:

    - -
  10. -
-

Drawbacks

-

The main drawback of adding the additional complexity directly to the broker pallet is the potential increase in maintenance overhead. Therefore, we propose adding additional functionality as a separate pallet on the Coretime chain. To take the pressure off from implementing these features, implementation along with unit tests would be taken care of by Lastic (Aurora Makovac, Philip Lucsok).

-

There are potential risks of security vulnerabilities in the new market functionalities, such as unauthorized region transfers or incorrect balance adjustments. Therefore, extensive security measures would have to be implemented.

-

Testing, Security, and Privacy

-

Testing

- -

Security

- -

Privacy

- -

Performance, Ergonomics, and Compatibility

-

Performance

- -

Ergonomics

- -

Compatibility

- -

Prior Art and References

- -

Unresolved Questions

- - - -

(source)

-

Table of Contents

- -

RFC-0002: Smart Contracts on the Coretime Chain

-
- - - -
Start Date2024-06-09
DescriptionImplement smart contracts on the Coretime chain
AuthorsAurora Poppyseed, Phil Lucksok
-
-

Summary

-

This RFC proposes the integration of smart contracts on the Coretime chain to enhance flexibility and enable complex decentralized applications, including secondary market functionalities.

-

Motivation

-

Currently, the Coretime chain lacks the capability to support smart contracts, which limits the range of decentralized applications that can be developed and deployed. By enabling smart contracts, the Coretime chain can facilitate more sophisticated functionalities such as automated region trading, dynamic pricing mechanisms, and other decentralized applications that require programmable logic. This will enhance the utility of the Coretime chain, attract more developers, and create more opportunities for innovation.

-

Additionally, while there is a proposal (#885) to allow EVM-compatible contracts on Polkadot’s Asset Hub, the implementation of smart contracts directly on the Coretime chain will provide synchronous interactions and avoid the complexities of asynchronous operations via XCM.

-

Stakeholders

-

Primary stakeholders include:

- -

Explanation

-

This RFC introduces the following key components:

-
    -
  1. -

    Smart Contract Support:

    - -
  2. -
  3. -

    Storage and Execution:

    - -
  4. -
  5. -

    Integration with Existing Pallets:

    - -
  6. -
  7. -

    Security and Auditing:

    - -
  8. -
-

Drawbacks

-

There are several drawbacks to consider:

- -

Testing, Security, and Privacy

-

Testing

- -

Security

- -

Privacy

- -

Performance, Ergonomics, and Compatibility

-

Performance

- -

Ergonomics

- -

Compatibility

- -

Prior Art and References

- -

Unresolved Questions

- - - -

By enabling smart contracts on the Coretime chain, we can significantly expand its capabilities and attract a wider range of developers and users, fostering innovation and growth in the ecosystem.

(source)

Table of Contents

Given that these mistakes are likely, it is necessary to provide a solution to either prevent them or enable access to a pure account on a target chain.

-

Stakeholders

+

Stakeholders

Runtime Users, Runtime Devs, wallets, cross-chain dApps.

-

Explanation

+

Explanation

One possible solution is to allow a proxy to create or replicate a pure proxy relationship for the same pure account on a target chain. For example, Alice, as the proxy of the pure1 pure account on parachain A, should be able to set a proxy for the same pure1 account on parachain B.

To minimise security risks, the parachain B should grant the parachain A the least amount of permission necessary for the replication. First, Parachain A claims to Parachain B that the operation is commanded by the pure account, and thus by its proxy, and second, provides proof that the account is keyless.

The replication process will be facilitated by XCM, with the first claim made using the DescendOrigin instruction. The replication call on parachain A would require a signed origin by the pure account and construct an XCM program for parachain B, where it first descends the origin, resulting in the ParachainA/AccountId32(pure1) origin location on the receiving side.

@@ -3617,7 +903,7 @@ mod pallet_proxy_replica { } } -

Drawbacks

+

Drawbacks

There are two disadvantages to this approach:

-

Prior Art and References

+

Prior Art and References

Robert Habermeier initially wrote on the subject of Polkadot blockspace-centric in the article Polkadot Blockspace over Blockchains. While not going into details, the article served as an early reframing piece for moving beyond one-slot-per-chain models and building out secondary market infrastructure for resource allocation.

(source)

Table of Contents

@@ -4787,12 +2073,12 @@ InstaPoolHistory: (empty) AuthorsGavin Wood, Robert Habermeier -

Summary

+

Summary

In the Agile Coretime model of the Polkadot Ubiquitous Computer, as proposed in RFC-1 and RFC-3, it is necessary for the allocating parachain (envisioned to be one or more pallets on a specialised Brokerage System Chain) to communicate the core assignments to the Relay-chain, which is responsible for ensuring those assignments are properly enacted.

This is a proposal for the interface which will exist around the Relay-chain in order to communicate this information and instructions.

-

Motivation

+

Motivation

The background motivation for this interface is splitting out coretime allocation functions and secondary markets from the Relay-chain onto System parachains. A well-understood and general interface is necessary for ensuring the Relay-chain receives coretime allocation instructions from one or more System chains without introducing dependencies on the implementation details of either side.

-

Requirements

+

Requirements

  • The interface MUST allow the Relay-chain to be scheduled on a low-latency basis.
  • Individual cores MUST be schedulable, both in full to a single task (a ParaId or the Instantaneous Coretime Pool) or to many unique tasks in differing ratios.
  • @@ -4802,7 +2088,7 @@ InstaPoolHistory: (empty)
  • The interface MUST allow for the allocating chain to instruct changes to the number of cores which it is able to allocate.
  • The interface MUST allow for the allocating chain to be notified of changes to the number of cores which are able to be allocated by the allocating chain.
-

Stakeholders

+

Stakeholders

Primary stakeholder sets are:

  • Developers of the Relay-chain core-management logic.
  • @@ -4810,7 +2096,7 @@ InstaPoolHistory: (empty)

Socialization:

This content of this RFC was discussed in the Polkdot Fellows channel.

-

Explanation

+

Explanation

The interface has two sections: The messages which the Relay-chain is able to receive from the allocating parachain (the UMP message types), and messages which the Relay-chain is able to send to the allocating parachain (the DMP message types). These messages are expected to be able to be implemented in a well-known pallet and called with the XCM Transact instruction.

Future work may include these messages being introduced into the XCM standard.

UMP Message Types

@@ -4885,17 +2171,17 @@ assert_eq!(targets.iter().map(|x| x.1).sum(), 57600);

Realistic Limits of the Usage

For request_revenue_info, a successful request should be possible if when is no less than the Relay-chain block number on arrival of the message less 100,000.

For assign_core, a successful request should be possible if begin is no less than the Relay-chain block number on arrival of the message plus 10 and workload contains no more than 100 items.

-

Performance, Ergonomics and Compatibility

+

Performance, Ergonomics and Compatibility

No specific considerations.

-

Testing, Security and Privacy

+

Testing, Security and Privacy

Standard Polkadot testing and security auditing applies.

The proposal introduces no new privacy concerns.

- +

RFC-1 proposes a means of determining allocation of Coretime using this interface.

RFC-3 proposes a means of implementing the high-level allocations within the Relay-chain.

Drawbacks, Alternatives and Unknowns

None at present.

-

Prior Art and References

+

Prior Art and References

None.

(source)

Table of Contents

@@ -4941,13 +2227,13 @@ assert_eq!(targets.iter().map(|x| x.1).sum(), 57600); AuthorsJoe Petrowski -

Summary

+

Summary

As core functionality moves from the Relay Chain into system chains, so increases the reliance on the liveness of these chains for the use of the network. It is not economically scalable, nor necessary from a game-theoretic perspective, to pay collators large rewards. This RFC proposes a mechanism -- part technical and part social -- for ensuring reliable collator sets that are resilient to attemps to stop any subsytem of the Polkadot protocol.

-

Motivation

+

Motivation

In order to guarantee access to Polkadot's system, the collators on its system chains must propose blocks (provide liveness) and allow all transactions to eventually be included. That is, some collators may censor transactions, but there must exist one collator in the set who will include a @@ -4974,7 +2260,7 @@ coordinated attempts to stop a single chain from halting or to censor a particul transactions.

In the case that users do not trust this set, this RFC also proposes that each chain always have available collator positions that can be acquired by anyone by placing a bond.

-

Requirements

+

Requirements

  • System MUST have at least one valid collator for every chain.
  • System MUST allow anyone to become a collator, provided they reserve/hold enough DOT.
  • @@ -4983,12 +2269,12 @@ to censor any subset of transactions.
  • Collators selected by governance SHOULD have a reasonable expectation that the Treasury will reimburse their operating costs.
-

Stakeholders

+

Stakeholders

  • Infrastructure providers (people who run validator/collator nodes)
  • Polkadot Treasury
-

Explanation

+

Explanation

This protocol builds on the existing Collator Selection pallet and its notion of Invulnerables. Invulnerables are collators (identified by their AccountIds) who @@ -5024,27 +2310,27 @@ approximately:

  • of which 15 are Invulnerable, and
  • five are elected by bond.
  • -

    Drawbacks

    +

    Drawbacks

    The primary drawback is a reliance on governance for continued treasury funding of infrastructure costs for Invulnerable collators.

    -

    Testing, Security, and Privacy

    +

    Testing, Security, and Privacy

    The vast majority of cases can be covered by unit testing. Integration test should ensure that the Collator Selection UpdateOrigin, which has permission to modify the Invulnerables and desired number of Candidates, can handle updates over XCM from the system's governance location.

    -

    Performance, Ergonomics, and Compatibility

    +

    Performance, Ergonomics, and Compatibility

    This proposal has very little impact on most users of Polkadot, and should improve the performance of system chains by reducing the number of missed blocks.

    -

    Performance

    +

    Performance

    As chains have strict PoV size limits, care must be taken in the PoV impact of the session manager. Appropriate benchmarking and tests should ensure that conservative limits are placed on the number of Invulnerables and Candidates.

    -

    Ergonomics

    +

    Ergonomics

    The primary group affected is Candidate collators, who, after implementation of this RFC, will need to compete in a bond-based election rather than a race to claim a Candidate spot.

    -

    Compatibility

    +

    Compatibility

    This RFC is compatible with the existing implementation and can be handled via upgrades and migration.

    -

    Prior Art and References

    +

    Prior Art and References

    Written Discussions

    • GitHub: Collator Selection Roadmap
    • @@ -5059,9 +2345,9 @@ migration.

    • SR Labs Auditors
    • Current collators including Paranodes, Stake Plus, Turboflakes, Peter Mensik, SIK, and many more.
    -

    Unresolved Questions

    +

    Unresolved Questions

    None at this time.

    - +

    There may exist in the future system chains for which this model of collator selection is not appropriate. These chains should be evaluated on a case-by-case basis.

    (source)

    @@ -5100,10 +2386,10 @@ appropriate. These chains should be evaluated on a case-by-case basis.

    AuthorsPierre Krieger -

    Summary

    +

    Summary

    The full nodes of the Polkadot peer-to-peer network maintain a distributed hash table (DHT), which is currently used for full nodes discovery and validators discovery purposes.

    This RFC proposes to extend this DHT to be used to discover full nodes of the parachains of Polkadot.

    -

    Motivation

    +

    Motivation

    The maintenance of bootnodes has long been an annoyance for everyone.

    When a bootnode is newly-deployed or removed, every chain specification must be updated in order to take the update into account. This has lead to various non-optimal solutions, such as pulling chain specifications from GitHub repositories. When it comes to RPC nodes, UX developers often have trouble finding up-to-date addresses of parachain RPC nodes. With the ongoing migration from RPC nodes to light clients, similar problems would happen with chain specifications as well.

    @@ -5112,9 +2398,9 @@ When it comes to RPC nodes, UX developers often have trouble finding up-to-date

    Because the list of bootnodes in chain specifications is so annoying to modify, the consequence is that the number of bootnodes is rather low (typically between 2 and 15). In order to better resist downtimes and DoS attacks, a better solution would be to use every node of a certain chain as potential bootnode, rather than special-casing some specific nodes.

    While this RFC doesn't solve these problems for relay chains, it aims at solving it for parachains by storing the list of all the full nodes of a parachain on the relay chain DHT.

    Assuming that this RFC is implemented, and that light clients are used, deploying a parachain wouldn't require more work than registering it onto the relay chain and starting the collators. There wouldn't be any need for special infrastructure nodes anymore.

    -

    Stakeholders

    +

    Stakeholders

    This RFC has been opened on my own initiative because I think that this is a good technical solution to a usability problem that many people are encountering and that they don't realize can be solved.

    -

    Explanation

    +

    Explanation

    The content of this RFC only applies for parachains and parachain nodes that are "Substrate-compatible". It is in no way mandatory for parachains to comply to this RFC.

    Note that "Substrate-compatible" is very loosely defined as "implements the same mechanisms and networking protocols as Substrate". The author of this RFC believes that "Substrate-compatible" should be very precisely specified, but there is controversy on this topic.

    While a lot of this RFC concerns the implementation of parachain nodes, it makes use of the resources of the Polkadot chain, and as such it is important to describe them in the Polkadot specification.

    @@ -5151,10 +2437,10 @@ message Response {

    The maximum size of a response is set to an arbitrary 16kiB. The responding side should make sure to conform to this limit. Given that fork_id is typically very small and that the only variable-length field is addrs, this is easily achieved by limiting the number of addresses.

    Implementers should be aware that addrs might be very large, and are encouraged to limit the number of addrs to an implementation-defined value.

    -

    Drawbacks

    +

    Drawbacks

    The peer_id and addrs fields are in theory not strictly needed, as the PeerId and addresses could be always equal to the PeerId and addresses of the node being registered as the provider and serving the response. However, the Cumulus implementation currently uses two different networking stacks, one of the parachain and one for the relay chain, using two separate PeerIds and addresses, and as such the PeerId and addresses of the other networking stack must be indicated. Asking them to use only one networking stack wouldn't feasible in a realistic time frame.

    The values of the genesis_hash and fork_id fields cannot be verified by the requester and are expected to be unused at the moment. Instead, a client that desires connecting to a parachain is expected to obtain the genesis hash and fork ID of the parachain from the parachain chain specification. These fields are included in the networking protocol nonetheless in case an acceptable solution is found in the future, and in order to allow use cases such as discovering parachains in a not-strictly-trusted way.

    -

    Testing, Security, and Privacy

    +

    Testing, Security, and Privacy

    Because not all nodes want to be used as bootnodes, implementers are encouraged to provide a way to disable this mechanism. However, it is very much encouraged to leave this mechanism on by default for all parachain nodes.

    This mechanism doesn't add or remove any security by itself, as it relies on existing mechanisms. However, if the principle of chain specification bootnodes is entirely replaced with the mechanism described in this RFC (which is the objective), then it becomes important whether the mechanism in this RFC can be abused in order to make a parachain unreachable.

    @@ -5163,22 +2449,22 @@ Furthermore, when a large number of providers (here, a provider is a bootnode) a

    For this reason, an attacker can abuse this mechanism by randomly generating libp2p PeerIds until they find the 20 entries closest to the key representing the target parachain. They are then in control of the parachain bootnodes. Because the key changes periodically and isn't predictable, and assuming that the Polkadot DHT is sufficiently large, it is not realistic for an attack like this to be maintained in the long term.

    Furthermore, parachain clients are expected to cache a list of known good nodes on their disk. If the mechanism described in this RFC went down, it would only prevent new nodes from accessing the parachain, while clients that have connected before would not be affected.

    -

    Performance, Ergonomics, and Compatibility

    -

    Performance

    +

    Performance, Ergonomics, and Compatibility

    +

    Performance

    The DHT mechanism generally has a low overhead, especially given that publishing providers is done only every 24 hours.

    Doing a Kademlia iterative query then sending a provider record shouldn't take more than around 50 kiB in total of bandwidth for the parachain bootnode.

    Assuming 1000 parachain full nodes, the 20 Polkadot full nodes corresponding to a specific parachain will each receive a sudden spike of a few megabytes of networking traffic when the key rotates. Again, this is relatively negligible. If this becomes a problem, one can add a random delay before a parachain full node registers itself to be the provider of the key corresponding to BabeApi_next_epoch.

    Maybe the biggest uncertainty is the traffic that the 20 Polkadot full nodes will receive from light clients that desire knowing the bootnodes of a parachain. Light clients are generally encouraged to cache the peers that they use between restarts, so they should only query these 20 Polkadot full nodes at their first initialization. If this every becomes a problem, this value of 20 is an arbitrary constant that can be increased for more redundancy.

    -

    Ergonomics

    +

    Ergonomics

    Irrelevant.

    -

    Compatibility

    +

    Compatibility

    Irrelevant.

    -

    Prior Art and References

    +

    Prior Art and References

    None.

    -

    Unresolved Questions

    +

    Unresolved Questions

    While it fundamentally doesn't change much to this RFC, using BabeApi_currentEpoch and BabeApi_nextEpoch might be inappropriate. I'm not familiar enough with good practices within the runtime to have an opinion here. Should it be an entirely new pallet?

    - +

    It is possible that in the future a client could connect to a parachain without having to rely on a trusted parachain specification.

    (source)

    Table of Contents

    @@ -5199,13 +2485,13 @@ If this every becomes a problem, this value of 20 is an arbitrary constant that AuthorsJonas Gehrlein -

    Summary

    +

    Summary

    The Polkadot UC will generate revenue from the sale of available Coretime. The question then arises: how should we handle these revenues? Broadly, there are two reasonable paths – burning the revenue and thereby removing it from total issuance or divert it to the Treasury. This Request for Comment (RFC) presents arguments favoring burning as the preferred mechanism for handling revenues from Coretime sales.

    -

    Motivation

    +

    Motivation

    How to handle the revenue accrued from Coretime sales is an important economic question that influences the value of DOT and should be properly discussed before deciding for either of the options. Now is the best time to start this discussion.

    -

    Stakeholders

    +

    Stakeholders

    Polkadot DOT token holders.

    -

    Explanation

    +

    Explanation

    This RFC discusses potential benefits of burning the revenue accrued from Coretime sales instead of diverting them to Treasury. Here are the following arguments for it.

    It's in the interest of the Polkadot community to have a consistent and predictable Treasury income, because volatility in the inflow can be damaging, especially in situations when it is insufficient. As such, this RFC operates under the presumption of a steady and sustainable Treasury income flow, which is crucial for the Polkadot community's stability. The assurance of a predictable Treasury income, as outlined in a prior discussion here, or through other equally effective measures, serves as a baseline assumption for this argument.

    Consequently, we need not concern ourselves with this particular issue here. This naturally begs the question - why should we introduce additional volatility to the Treasury by aligning it with the variable Coretime sales? It's worth noting that Coretime revenues often exhibit an inverse relationship with periods when Treasury spending should ideally be ramped up. During periods of low Coretime utilization (indicated by lower revenue), Treasury should spend more on projects and endeavours to increase the demand for Coretime. This pattern underscores that Coretime sales, by their very nature, are an inconsistent and unpredictable source of funding for the Treasury. Given the importance of maintaining a steady and predictable inflow, it's unnecessary to rely on another volatile mechanism. Some might argue that we could have both: a steady inflow (from inflation) and some added bonus from Coretime sales, but burning the revenue would offer further benefits as described below.

    @@ -5248,13 +2534,13 @@ If this every becomes a problem, this value of 20 is an arbitrary constant that AuthorsJoe Petrowski -

    Summary

    +

    Summary

    Since the introduction of the Collectives parachain, many groups have expressed interest in forming new -- or migrating existing groups into -- on-chain collectives. While adding a new collective is relatively simple from a technical standpoint, the Fellowship will need to merge new pallets into the Collectives parachain for each new collective. This RFC proposes a means for the network to ratify a new collective, thus instructing the Fellowship to instate it in the runtime.

    -

    Motivation

    +

    Motivation

    Many groups have expressed interest in representing collectives on-chain. Some of these include: