-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extrinsic v5 definition and specification #124
base: main
Are you sure you want to change the base?
Changes from 4 commits
380bdbb
01bc758
f2f4f19
dd9e353
e13f615
0ac87df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,155 @@ | ||||||
# RFC-0124: Extrinsic version 5 | ||||||
|
||||||
| | | | ||||||
| --------------- | ------------------------------------------------------------------------------------------- | | ||||||
| **Start Date** | 18 October 2024 | | ||||||
| **Description** | Definition and specification of version 5 extrinsics | | ||||||
| **Authors** | George Pisaltu | | ||||||
|
||||||
## Summary | ||||||
|
||||||
This RFC proposes the definition of version 5 extrinsics along with changes to the specification and encoding from version 4. | ||||||
|
||||||
## Motivation | ||||||
|
||||||
[RFC84](https://github.com/polkadot-fellows/RFCs/blob/main/text/0084-general-transaction-extrinsic-format.md) introduced the specification of `General` transactions, a new type of extrinsic besides the `Signed` and `Unsigned` variants available previously in version 4. Additionally, [RFC99](https://github.com/polkadot-fellows/RFCs/blob/main/text/0099-transaction-extension-version.md) introduced versioning of transaction extensions through an extra byte in the extrinsic encoding. Both of these changes require an extrinsic format version bump as both the semantics around extensions as well as the actual encoding of extrinsics need to change to accommodate these new features. | ||||||
|
||||||
## Stakeholders | ||||||
|
||||||
- Runtime users | ||||||
- Runtime devs | ||||||
- Wallet devs | ||||||
|
||||||
## Explanation | ||||||
|
||||||
### Changes to extrinsic authorization | ||||||
|
||||||
The introduction of `General` transactions allows the authorization of any and all origins through | ||||||
extensions. This means that, with the appropriate extension, `General` transactions are capable of | ||||||
replicating the same behavior present day v4 `Signed` transactions. Specifically for Polkadot | ||||||
chains, an example implementation for such an extension is | ||||||
[`VerifySignature`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/verify-signature), | ||||||
introduced in the Transaction Extension | ||||||
[PR3685](https://github.com/paritytech/polkadot-sdk/pull/3685). Other extensions can be inserted | ||||||
into the extension pipeline to authorize different custom origins. Therefore, a `Signed` extrinsic | ||||||
variant is redundant to a `General` one strictly in terms of functionality available to users and | ||||||
would eventually need to be deprecated and removed. | ||||||
|
||||||
### Encoding format for version 5 | ||||||
|
||||||
As with version 4, the encoded v5 extrinsics will still be an array of SCALE encoded bytes, starting | ||||||
with the encoded length of the following bytes. The leading byte will determine the version and type | ||||||
of extrinsic, as specified by | ||||||
[RFC84](https://github.com/polkadot-fellows/RFCs/blob/main/text/0084-general-transaction-extrinsic-format.md), | ||||||
with the addition that the `Signed` variant will not be supported for v5 extrinsics, for reasons | ||||||
mentioned above. | ||||||
georgepisaltu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
NOTE: For `Bare` extrinsics, the following bytes will just be the encoded call and nothing else. | ||||||
|
||||||
For `General` transactions, as stated in | ||||||
[RFC99](https://github.com/polkadot-fellows/RFCs/blob/main/text/0099-transaction-extension-version.md), | ||||||
an extension version byte must be added in the next extrinsic version. This byte should allow | ||||||
georgepisaltu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
runtimes to expose more than one set of extensions which can be used for a transaction. As far as | ||||||
the v5 extrinsic encoding is concerned, this extension byte should be encoded immediately after the | ||||||
leading encoding byte. The extension version byte should be included in payloads to be signed by all | ||||||
extensions configured by runtime devs to ensure a user's extension version choice cannot be altered | ||||||
by third parties. | ||||||
|
||||||
After the extension version byte, the extensions will be encoded next, followed by the call itself. | ||||||
|
||||||
A quick visualization of the encoding: | ||||||
|
||||||
- `Bare` extrinsics: `(extrinsic_encoded_len, 0b0000_0101, call)` | ||||||
- `General` transactions: `(extrinsic_encoded_len, , 0b0100_0101, extension_version_byte, extension, call)` | ||||||
georgepisaltu marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought the component is called
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The extension itself is usually a tuple of multiple extensions, generally referred to as the extension pipeline. Technically it's only one extension, the |
||||||
|
||||||
### Signatures on Polkadot in General transactions | ||||||
|
||||||
As stated before, [PR3685](https://github.com/paritytech/polkadot-sdk/pull/3685) comes with a | ||||||
Transaction Extension which replicates the current `Signed` transactions in v5 extrinsics, namely | ||||||
[`VerifySignature`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/verify-signature). | ||||||
This extension leverages the new inherited implication functionality introduced in | ||||||
`TransactionExtension` and creates a payload to be signed using the data of all extensions after | ||||||
itself in the extension pipeline. In order to run a transaction with a signed origin, a user must | ||||||
create the transaction with an instance of the extension which provides a signature. Alternatively, | ||||||
if users want to use some other origin, they should create the transaction with this particular | ||||||
extension disabled. More on this behavior in the extension documentation. This extension can be | ||||||
configured to accept a `MultiSignature`, which makes it compatible with all signature types | ||||||
currently used in Polkadot. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as before, this should not explain HOW There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The goal of it is to explain how to use the new v5 format to achieve provide the same functionality as signed transactions. I then use the example in I don't think it's wrong to have links to That said, if others consider the examples are not useful, I will remove them. |
||||||
|
||||||
To generate the payload to be signed: | ||||||
|
||||||
1. The extension version byte, call, extension and extension implicit should be encoded; | ||||||
2. The result of the encoding should then be hashed using the `BLAKE2_256` hasher; | ||||||
3. The result of the hash should then be signed with the signature type specified in the extension definition. | ||||||
|
||||||
```rust | ||||||
// Step 1: encode the bytes | ||||||
let encoded = (extension_version_byte, call, transaction_extension, transaction_extension_implicit).encode(); | ||||||
// Step 2: hash them | ||||||
let payload = blake2_256(&encoded[..]); | ||||||
// Step 3: sign the payload | ||||||
let signature = keyring.sign(&payload[..]); | ||||||
``` | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will most likely depend on which origin and kind of signature is used. For instance, ZK circuits might have different levels of proofs and might not be signing the whole payload. This should go to another RFC, which defines every particular There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is just an example on how to achieve However, there should be only one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, but anyways this should go on a different RFC. I agree that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the example is useful, and since it's also explicitly labeled as an example I see no reason to remove it |
||||||
|
||||||
### Summary of changes in version 5 | ||||||
|
||||||
In order to minimize the number of changes to the extrinsic format version and also to help all | ||||||
consumers downstream in the transition period between these extrinsic versions, we should: | ||||||
|
||||||
- Remove the `Signed` variant starting with v5 extrinsics | ||||||
- Add the `General` variant starting with v5 extrinsics | ||||||
- Enable runtimes to support both v4 and v5 extrinsics | ||||||
|
||||||
## Drawbacks | ||||||
|
||||||
The metadata will have to accommodate two distinct extrinsic format versions at a given point in | ||||||
time in order to provide the new functionality in a non-breaking way for users and tooling. | ||||||
Comment on lines
+120
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not a drawback IMO. Metadata v15 should show v4 and metadata v16 and ahead have a vector of extrinsic versions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is something extra to support in the metadata for both the runtime and users, is this not a drawback? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is both a drawback and an improvement - the new metadata support is an improvement, but having to do this enhancement to the metadata is a drawback to this RFC 😛 maybe add another line explicitly calling out that adding this metadata enhancement is ultimately a good thing that should be useful for potential future scenarios too There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the explanation. |
||||||
|
||||||
## Testing, Security, and Privacy | ||||||
|
||||||
There is no impact on testing, security or privacy. | ||||||
|
||||||
## Performance, Ergonomics, and Compatibility | ||||||
|
||||||
This change makes the authorization through signatures configurable by runtime devs in version 5 | ||||||
extrinsics, as opposed to version 4 where the signing payload algorithm and signatures were | ||||||
hardcoded. This moves the responsibility of ensuring proper authentication through | ||||||
`TransactionExtension` to the runtime devs, but a sensible default which closely resembles the | ||||||
present day behavior will be provided in `VerifySignature`. | ||||||
Comment on lines
+133
to
+137
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not true. Signature schemes and addresses were configurable by runtime devs through rust generics. For example, Moonbeam uses only ECDSA signatures with EVM-like addresses. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your statement about configurable signature schemes is true. However, I still consider my statement to be true because:
All of this static logic is now moved to extensions. The extensions receive the inherited implication, the generation of which is still hardcoded and handled in this RFC, but is not in any way mandatory to be used in any signing scheme. I'd agree though that the phrasing isn't clear, but I'm not sure how to improve it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the phrasing is fine as it is. The point is to highlight the increase in configurability, which it does. |
||||||
|
||||||
### Performance | ||||||
|
||||||
There is no performance impact. | ||||||
|
||||||
### Ergonomics | ||||||
|
||||||
Tooling will have to adapt to be able to tell which authorization scheme is used by a particular | ||||||
transaction by decoding the extension and checking which particular `TransactionExtension` in the pipeline is enabled to do the origin authorization. Previously, this was done by simply checking whether the transaction is signed or unsigned, as there was only one method of authentication. | ||||||
georgepisaltu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
### Compatibility | ||||||
|
||||||
As long as extrinsic version 4 is still exposed in the metadata when version 5 will be introduced, | ||||||
the changes will not break existing infrastructure. This should give enough time for tooling to | ||||||
support version 5 and to remove version 4 in the future. | ||||||
|
||||||
## Prior Art and References | ||||||
|
||||||
This is a result of the work in [Extrinsic | ||||||
Horizon](https://github.com/paritytech/polkadot-sdk/issues/2415) and | ||||||
[RFC99](https://github.com/polkadot-fellows/RFCs/blob/main/text/0099-transaction-extension-version.md). | ||||||
|
||||||
## Unresolved Questions | ||||||
|
||||||
There is no clear way to expose two different extrinsic versions in the current metadata framework. | ||||||
A non-exhaustive list of options discussed so far: | ||||||
|
||||||
1. Change the `ExtrinsicMetadata` trait to specify a list of versions instead of a single version. | ||||||
2. Use the custom fields in the metadata to specify the details of the version 5. | ||||||
3. Create a new trait similar to `ExtrinsicMetadata`, but for future versions of the extrinsic | ||||||
format and add it to the metadata. | ||||||
georgepisaltu marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
## Future Directions and Related Material | ||||||
|
||||||
Following this change, extrinsic version 5 will be introduced as part of the [Extrinsic | ||||||
Horizon](https://github.com/paritytech/polkadot-sdk/issues/2415) effort, which will shape future | ||||||
work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides some wording suggestions, I don't think we should introduce links to
polkadot-sdk
repo. The idea of authorization through transaction extensions is already clear without the example IMO.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in the explanation section and I think it adds valuable context to the discussion. I appreciate that you're familiar with the idea of authorization through transaction extensions, but I think it's still a novel topic and the example is useful. However, if others disagree, I will remove it.