|
| 1 | +A place for content that's not been used anywhere. |
| 2 | +Perhaps to scrap, haven't decided yet. |
| 3 | + |
| 4 | +# Transactions |
| 5 | + |
| 6 | +## Where transactions are defined |
| 7 | + |
| 8 | +As discussed in [Runtime development](), the Substrate runtime contains the business logic that defines valid transactions, determines whether the transactions are sent as signed or unsigned, and how transactions change the state of the chain. |
| 9 | + |
| 10 | +Typically, you use pallets to compose the runtime functions and to implement the transactions you want your chain to support. |
| 11 | +After you compile the runtime, users interact with the blockchain to submit requests that are processed as transactions. |
| 12 | +For example, a user might submit a request to transfer funds from one account to another. |
| 13 | +The request becomes a signed transaction that contains the signature for that user account and if there are sufficient funds in the user's account to pay for the transaction, the transaction executes successfully, and the transfer is made. |
| 14 | + |
| 15 | +<!-- Although inherents are very different by nature compared to signed and unsigned transaction types, they are treated like any other transaction from the perspective of the transaction pool. --> |
| 16 | + |
| 17 | +<!-- See how FRAME implements and used these types of transactions: |
| 18 | +- #[pallet::inherent]: |
| 19 | +- #[pallet::validate_unsigned]: |
| 20 | +- dispatch origins: signed, unsigned, none (inherent) --> |
| 21 | + |
| 22 | +A `CheckedExtrinsic` is quite different on the other hand. |
| 23 | +It's format requires: |
| 24 | + |
| 25 | +- a `function` corresponding to the call being made. |
| 26 | +- a `signed` field which carries information on where this extrinsic comes from (`AccountId`) and the number of extrinsics that have come before from the same source (defined by the `CheckedExtrinsic` signed extension). |
| 27 | + |
| 28 | + |
| 29 | +<!-- All signed transactions in a FRAME runtime have the following formatted around the `UncheckExtrinsics` type and |
| 30 | +
|
| 31 | +- tip |
| 32 | +- period |
| 33 | +- current_block |
| 34 | +- era |
| 35 | +- extra |
| 36 | +- raw_payload |
| 37 | +- signature |
| 38 | +- address |
| 39 | +
|
| 40 | +And look like this when decoded: |
| 41 | +
|
| 42 | +```text |
| 43 | +Extra: (CheckNonZeroSender, CheckSpecVersion, CheckTxVersion, CheckGenesis, CheckEra(Era::Mortal(2048, 99)), CheckNonce(0), CheckWeight, ChargeTransactionPayment<0>) |
| 44 | +Additional Signed: (259, 1, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000000, (), (), ()) |
| 45 | +Raw Payload: [6, 0, 255, 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125, 145, 1, 58, 6, 0, 0, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] |
| 46 | +``` |
| 47 | +
|
| 48 | +Notice some other [signed extensions](#signed-extensions) which perform certain checks on the format of the transaction. |
| 49 | + --> |
| 50 | + |
| 51 | +## Validity |
| 52 | + |
| 53 | +The validity of a transaction is verified by checks defined in the runtime. |
| 54 | +Before a transaction is propagated to other nodes, it is "tagged" and checked for whether: |
| 55 | + |
| 56 | +- The signature is valid. |
| 57 | +- The account has enough funds to pay for the associated fees. |
| 58 | +- The transaction index (nonce) is correct. |
| 59 | + |
| 60 | +The transaction pool also regularly checks for transaction validity of existing transactions within the pool. |
| 61 | +Every transaction is defined in the runtime using the [`ValidTransaction`](https://docs.substrate.io/rustdocs/latest/sp_runtime/transaction_validity/struct.ValidTransaction.html) struct. |
| 62 | +A transaction will be dropped from the pool if it is found to be invalid or expired, for example: |
| 63 | + |
| 64 | +- If another transaction contains the same transaction dependencies (see: [`requires`](https://docs.substrate.io/rustdocs/latest/sp_runtime/transaction_validity/struct.ValidTransaction.html#structfield.requires) and [`TransactionTag`](https://docs.substrate.io/rustdocs/latest/sp_runtime/transaction_validity/type.TransactionTag.html)). |
| 65 | +- If the transaction has exceeded the [`TransactionLongevity`](https://docs.substrate.io/rustdocs/latest/sp_runtime/transaction_validity/type.TransactionLongevity.html#), i.e. the amount of blocks it can remain valid for. |
| 66 | + |
| 67 | +Other causes for invalid transactions are listed [here](https://docs.substrate.io/rustdocs/latest/sp_runtime/transaction_validity/enum.InvalidTransaction.html). |
| 68 | + |
| 69 | +The [`TaggedTransactionQueue`](https://docs.substrate.io/rustdocs/latest/sp_transaction_pool/runtime_api/trait.TaggedTransactionQueue.html) runtime API provides a [`validate_transaction`](/rustdocs/latest/sp_transaction_pool/runtime_api/trait.TaggedTransactionQueue.html#method.validate_transaction) method whose job is to verify the correctness of the transaction against the current state (i.e. the signature and nonce). |
| 70 | +The function will be called frequently, potentially multiple times for the same transaction. |
| 71 | +In doing so, it provides the necessary information for the transaction pool to order and prioritize transactions. |
| 72 | +It is also possible for `validate_transaction` to reject a dependent transaction that would pass `execute_block` if it were executed in the correct order. |
| 73 | + |
| 74 | + |
| 75 | +A decoded signed transaction from a JSON-RPC call would look like: |
| 76 | + |
| 77 | +```json |
| 78 | +"method":{ |
| 79 | + "pallet":"balances", |
| 80 | + "method":"transfer" |
| 81 | + }, |
| 82 | + "signature":{ |
| 83 | + "signature":"0x94b63112648e8e692f0076fa1ccab3a04510c269d1392c1df2560503865e144e3afd578f1e37e98063b64b98a77a89a9cdc8ade579dcac0984e78d90646a052001", |
| 84 | + "signer":{ |
| 85 | + "id":"Gr5sBB1EgdmQ7FG3Ud2BdECWQTMDXNgGPfdHMMtDsmT4Dj3" |
| 86 | + } |
| 87 | + }, |
| 88 | + "nonce":"12", |
| 89 | + "args":{ |
| 90 | + "dest":{ |
| 91 | + "id":"J6ksma2jVeHRcRoYPZBkJRzRbckys7oSmgvjKLrVbj1U8bE" |
| 92 | + }, |
| 93 | + "value":"100000000" |
| 94 | + }, |
| 95 | + "tip":"0", |
| 96 | + "hash":"0xfbc5e5de75d64abe5aa3ee9272a3112b3ce53710664f6f2b9416b2ffda8799c2", |
| 97 | + "info":{ |
| 98 | + "weight":"201217000", |
| 99 | + "class":"Normal", |
| 100 | + "partialFee":"2583332634" |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +An inherent would look like: |
| 106 | + |
| 107 | +```json |
| 108 | +"method":{ |
| 109 | + "pallet":"timestamp", |
| 110 | + "method":"set" |
| 111 | + }, |
| 112 | + "signature":null, |
| 113 | + "nonce":null, |
| 114 | + "args":{ |
| 115 | + "now":"1620636072000" |
| 116 | + }, |
| 117 | + "tip":null, |
| 118 | + "hash":"0x8b853f49b6543e4fcbc796ad3574ea5601d2869d80629e080e501da4cb7b74b4", |
| 119 | + "info":{ |
| 120 | + |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | + |
| 126 | +The [`ValidTransaction` struct](/rustdocs/latest/sp_runtime/transaction_validity/struct.ValidTransaction.html) defines two parameters used to determine the ordering of transactions in the pool: `requires` and `provides`. |
| 127 | +Together they create a dependency graph which allows the pool to produce a valid linear ordering of transactions. |
| 128 | + |
| 129 | +Substrate supports multiple `provides` and `requires` tags. |
| 130 | +This enables runtime engineers to create alternate ordering schemes. |
| 131 | + |
| 132 | + |
| 133 | +## FRAME implementation |
| 134 | + |
| 135 | +See how the core mechanisms described in this article are implemented in FRAME: |
| 136 | +- `pallet_transaction_payment_rpc`: RPC interface for the transaction payment pallet. |
| 137 | +- `pallet_transaction_payment`: Transaction Payment Pallet |
| 138 | +- `pallet_transaction_storage`: Transaction storage pallet. Indexes transactions and … |
| 139 | +- `pallet_transaction_payment_rpc_runtime_api`: Runtime API definition for transaction payment pallet. |
| 140 | + |
| 141 | +`Operational` transactions are getting additional priority bump (3/4 * `u64::max()`), because that prevents other transactions from getting in front of them in the pool, but now equal to the `OperationalVirtualTip` amount configurable by a runtime developer. |
| 142 | + |
| 143 | +Notes: |
| 144 | + |
| 145 | +- We need some note in the "welcome" section that says that our docs describe building parachains with Substrate, specifically for runtimes built with FRAME. |
0 commit comments