From 84628d01a58c6b53c8e27668c666fd7043b0e083 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 3 Jul 2022 11:02:07 +0200 Subject: [PATCH 1/4] add signed ext --- .../6.4-Signed_Extensions_slides.md | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md diff --git a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md new file mode 100644 index 000000000..42b8c942f --- /dev/null +++ b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md @@ -0,0 +1,260 @@ +## Signed Extensions + +Lecture X, Module 6 + +Instructor: Kian / Shawn + +Topics: Signed Extensions, Transaction Priority. + +---v + +- In this lecture you will learn above one of the most advance FRAME concepts, *Signed Extensions*. +They allow for a multitude of custom features to be added to FRAME transactions. + +--- + +## History + +- Signed Extensions originally where added to implement tipping in a reasonable way. + +> Originally, your dumb instructor (@kianenigma) had the idea of hard-coding it into the +> `UncheckedExtrinsic`, until @gavofyork jumped in with the idea of signed extensions. + +TODO: Image of PR + +---v + +- In essence, they are a generic way to **extend** the transaction. Moreover, if they have +additional payload, it is signed, therefore *`SignedExtension`*. + +--- + +## Anatomy + +A signed extension can be either combination of the following things: + +1. Some additional data that is attached to the transaction. + - The tip! +2. Some hooks that are executed before and after the transaction is executed. + - Before each transaction is executed, it must pay its fee upfront. +3. Some additional validation logic that is used to validate the transaction. + - +- Some additional data that must be present in the signed payload of each transaction + - Spec version is part of all transaction! + +--- + +## Let's Peek at the Trait + +NOTE: just a breeze over the trait. + +--- + +## Tuple of Signed Extension + +- Is also a signed extension itself! + +> Look at the tuple implementation. + +- Main takeaways: + - `type AdditionalSigned = (SE1::AdditionalSigned, SE2::AdditionalSigned)`, + - `type Pre = (SE1::Pre, SE2::Pre)`, + - all of hooks: + - Executes each individually, combines results + +NOTE: +TODO: we need a lecture in module 4 around `impl_for_tuples`. +TODO: how `TransactionValidity` is `combined_with` is super important here, but probably something +to cover more in 4.3 and recap here. + +--- + +## Usage In The Runtime + +- Each runtime has a bunch of signed extensions. They can be grouped as a tuple + +```rust +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + pallet_asset_tx_payment::ChargeAssetTxPayment, +); +``` + +---v + +> Recall that a tuple of `SignedExtension` is itself a `SignedExtension`. + +> We will get to this later as well, but recall that SignedExtensions are not a *FRAME/Pallet* +> concept per se. FRAME just implements them. This also implies that everything regarding signed +> extensions is applied to **all transactions**, throughout the runtime. + + +- This type is passed to the `UncheckedExtrinsic` and `CheckedExtrinsic`. Let's go into each and see +what each do with these extensions! + +--- + +## `UncheckedExtrinsic`: Decoding. + +- The first important detail is that when `UncheckedExtrinsic` is being decoded, if it has a + signature, then it decodes the signed extension as well. + + For example: + + ```rust + struct Foo(u32, u32); + impl SignedExtension for Foo { .. } + ``` + + implies that two `u32`s are added to the end of the signature field of **all transactions**. + + +--- + +## `UncheckedExtrinsic`: Checking. + +- Taken from `fn check`: + +```rust +// SignedPayload::new +pub fn new(call: Call, extra: Extra) -> Result { + // asks all signed extensions to give their additional signed data.. + let additional_signed = extra.additional_signed()?; + // this essentially means: what needs to be signed in the signature of the transaction is: + // 1. call + // 2. signed extension data itself + // 3. any additional signed data. + let raw_payload = (call, extra, additional_signed); + Ok(Self(raw_payload)) +} + +// UncheckedExtrinsic::check +fn check(self, lookup: &Lookup) -> Result { + Ok(match self.signature { + Some((signed, signature, extra)) => { + let signed = lookup.lookup(signed)?; + // this is the payload that we expect to be signed, as explained above. + let raw_payload = SignedPayload::new(self.function, extra)?; + // encode the signed payload, and check it against the signature. + if !raw_payload.using_encoded(|payload| signature.verify(payload, &signed)) { + return Err(InvalidTransaction::BadProof.into()) + } + + // the extra is passed again to `CheckedExtrinsic`, see in the next section. + let (function, extra, _) = raw_payload.deconstruct(); + CheckedExtrinsic { signed: Some((signed, extra)), function } + }, + // we don't care about signed extensions at all. + None => CheckedExtrinsic { signed: None, function: self.function }, + }) +} +``` + +--- + +## `UncheckedExtrinsic` + +- in `fn validate` of `Applyable`, we use `validate` of signed extensions + - Also for unsigned + - Historical: `ValidateUnsigned` and `SignedExtension` have an overlap, someday the former + might become deprecated. TODO: find the github issue about this. +- in `fn apply` of `Applyable`, we + - `pre_dispatch` or `pre_dispatch_unsigned` accordingly. + - `post_dispatch` accordingly + - TODO: `type Pre` and passing data to post-dispatch needs its own section. + +--- + +## Recap: Transaction Queue Validation + +- `fn validate` of `Applyable` is actually used in --you guessed it-- Executive for transaction validation. + +> walk over the `fn validate_transaction` in executive, which is used directly in the runtime API. + +- See how it is doing the minimum amount of validation, NOT dispatching anything. + +> Transaction queue is not part of the consensus system. Validation of transaction are *free*. Doing +> too much work in validation of transactions is essentially opening a door to be DOS-ed. + + +--- + + +## Putting It All Together: `ChargeTransactionPayment` + +- Let's now walk over this + +--- + +## Notable Signed Extensions + +- These are some of the default signed extensions that come in FRAME +- See if you can predict how they are made! + +---v + +### `check_genesis` + +Wants to make sure you are signing against the right chain. + +Put the genesis hash in `additional_signed`. + + + +`check_spec_version` and `check_tx_version` work very similarly. + + + +---v + +### `check_non_zero_sender` + + - interesting story: any account can sign on behalf of the `0x00` account. + - discovered by XLC + - TODO: link to examples being signed with this, and the first one. + + - uses `pre_dispatch` and `validate` to ensure the signing account is not `0x00`. + +---v + +### `check_nonce` + - `pre_dispatch`: check nonce and actually update it. + - `validate`: check the nonce, DO NOT WRITE ANYTHING, set `provides` and `requires`. + + - remember that: + - `validate` is only for lightweight checks, no read/write. + - anything you write to storage is reverted anyhow. TODO: fact check this statement + +---v + +### `check_weight` + +- Check there is enough weight in `validate`. +- Check there is enough weight, and update the consumed weight in `pre_dispatch`. +- Updated consumed weight in `post_dispatch`. + +--- + +## Big Picture: Pipeline of Extension + +- Signed extensions (or at least the `pre_dispatch` and `validate` part) remind me of the extension + system of `express.js`, if any of you know what that is + +TODO: figure + +--- + +## Exercises + +- Walk over the notable signed extensions above and riddle each other about how they work. +- SignedExtensions are an important part of the transaction encoding. Try and encode a correct + transaction against a template runtime in any language that you want, using only a scale-codec + library. +- SignedExtensions that logs something on each transaction +- SignedExtension that keeps a counter of all transactions +- SignedExtensions that keeps a counter of all successful/failed transactions +- SignedExtension that tries to refund the transaction + From 655aba0905282f081477222dc6234b69f589bdce Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 3 Jul 2022 11:38:34 +0200 Subject: [PATCH 2/4] add some notes --- .../6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md index 42b8c942f..43b1f649c 100644 --- a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md +++ b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md @@ -256,5 +256,6 @@ TODO: figure - SignedExtensions that logs something on each transaction - SignedExtension that keeps a counter of all transactions - SignedExtensions that keeps a counter of all successful/failed transactions -- SignedExtension that tries to refund the transaction +- SignedExtension that tries to refund the transaction from each account as long as they submit less + than 1tx/day. From 6b14d398b99d681f50d4b498b579462519739db3 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 6 Jul 2022 13:57:05 +0100 Subject: [PATCH 3/4] rephrase validate --- .../6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md index 43b1f649c..ff504098a 100644 --- a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md +++ b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md @@ -19,8 +19,8 @@ They allow for a multitude of custom features to be added to FRAME transactions. > Originally, your dumb instructor (@kianenigma) had the idea of hard-coding it into the > `UncheckedExtrinsic`, until @gavofyork jumped in with the idea of signed extensions. - -TODO: Image of PR +> [Tipped Transaction Type. by kianenigma · Pull Request #2930 · paritytech/substrate](https://github.com/paritytech/substrate/pull/2930/files) +> [Extensible transactions (and tips) by gavofyork · Pull Request #3102 · paritytech/substrate](https://github.com/paritytech/substrate/pull/3102/files) ---v @@ -37,8 +37,9 @@ A signed extension can be either combination of the following things: - The tip! 2. Some hooks that are executed before and after the transaction is executed. - Before each transaction is executed, it must pay its fee upfront. -3. Some additional validation logic that is used to validate the transaction. - - +3. Some additional validation logic that is used to validate the transaction, and give feedback to + the pool. + - Set priority of transaction priority based on some metric! - Some additional data that must be present in the signed payload of each transaction - Spec version is part of all transaction! From 8d17e981e3dbf889b9dd58bfaede9ca08f98a8a6 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 6 Jul 2022 13:58:39 +0100 Subject: [PATCH 4/4] Update syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md Co-authored-by: Sacha Lansky --- .../6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md index ff504098a..8ae5dc9d3 100644 --- a/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md +++ b/syllabus/6-FRAME/6.4-Exotic_Stuff/6.4-Signed_Extensions_slides.md @@ -171,7 +171,7 @@ fn check(self, lookup: &Lookup) -> Result walk over the `fn validate_transaction` in executive, which is used directly in the runtime API.