From c445d1bc195f40f383dc67a0b6ecc8c2e499147c Mon Sep 17 00:00:00 2001 From: Jordan Mack Date: Mon, 12 Sep 2022 00:22:21 -0700 Subject: [PATCH] Merge branch 'revise-since-rfc' of https://github.com/doitian/rfcs into revise-since-rfc. --- .../0017-tx-valid-since.md | 138 ++++++++++-------- rfcs/0017-tx-valid-since/e-i-l-encoding.png | Bin 0 -> 21467 bytes 2 files changed, 77 insertions(+), 61 deletions(-) create mode 100644 rfcs/0017-tx-valid-since/e-i-l-encoding.png diff --git a/rfcs/0017-tx-valid-since/0017-tx-valid-since.md b/rfcs/0017-tx-valid-since/0017-tx-valid-since.md index 1c928be1c..e4271a63a 100644 --- a/rfcs/0017-tx-valid-since/0017-tx-valid-since.md +++ b/rfcs/0017-tx-valid-since/0017-tx-valid-since.md @@ -12,61 +12,73 @@ Created: 2019-03-11 ## Abstract -This RFC suggests adding a consensus rule to restrict committing a transaction before a specified time. The time comes from the block headers in the chain via block number, epoch number with fraction, or block timestamp. +This RFC describes a consensus rule used to prevent a transaction input from being committed before a specified time in the future. ## Summary -The new consensus rule allows the transaction input to specify an optional since precondition. CKB nodes must verify the transactions in the commitment zone of a block that all the input since preconditions are fulfilled. +An optional `since` value can be added to any input within a transaction that specifies a time in the future when it can be committed. The current time must be equal to or greater than the time specified in the `since` value before a CKB node will consider this precondition fulfilled and allow the transaction to be committed. -The since precondition locates a unique block in the past or future on the chain. The precondition is effective before the block, and is fulfilled since the block. +A transaction may be composed of multiple inputs from different parties that are batched together. Therefore a `since` field is located on each input within the transaction to allow every party to set their `since` value individually. If the `since` precondition is not met on any input within the transaction, the entire transaction will be immediately rejected by the CKB node on submission. -There are three metrics to specify the since precondition: +Three metrics can be used to specify how the `since` time is expressed: -1. via block number, -2. epoch number with fraction, -3. or the median timestamp of the preceding 37 blocks. +1. Block Number +2. Epoch Number (with fraction) +3. Timestamp (median of previous 37 blocks) -All of them strictly increase along the block number. +A developer can choose exactly one of these three metrics to use, and this will be used to indicate the format of `since` value. The metric used also used to determine how the threshold value, and the target value will be calculated. The threshold value is the block number, epoch number, or timestamp that must be reached to fulfill the precondition and allow the commit to occur. The target value can be thought of as the current block number, epoch number, or timestamp. -The precondition is absolute or relative. A relative precondition depends on which block has committed the input. +Note: Each one of these metrics will always increase in value over time with each new block added to the chain, meaning it is safe to assume these values will never decrease over time. -In conclusion, the since precondition is a per input threshold value with a specific metric, either absolute or relative to the input commitment block. The precondition prevents a block committing the transaction if the derived metric value from the block has not reached the since precondition threshold yet. +The relative flag must be set to either `absolute` or `relative` with the specified metric. This indicates how the threshold value should be calculated. + +When `absolute` is specified, the threshold value is set to the specified `since` value, which is interpreted by the metric selected. + +When `relative` is specified, the threshold value is calculated by retrieving the base value from the commitment block and and adding the `since` value. The base value is the block number, epoch number, or timestamp depending on the metric selected. The commitment block is the block in which the input was committed. + +After the treshold value and target value have been calculated they can be compared. The precondition is fulfilled only if the target value is equal to or greater than the treshold value. ## Specification ### How to Specify the Since Precondition -The per input field `since` is an unsigned 64-bit integer, which encodes the since precondition.[^1] The value 0 shows that the precondition is absent. Otherwise, the highest 8 bits of the `since` field is the `flags`, and the remaining `56` bits represent the `value`. +Each transaction input has a `since` field. The field itself is an unsigned 64-bit integer (u64) with special encoding for different values.[^1] A u64 value of `0` is used to indicate that the `since` precondition is disabled and will be ignored. If the field value is not `0`, then the highest 8 bits of the `since` field represent configuration `flags` and the remaining `56` bits represent the `value`. [^1]: See [RFC22](../rfcs/0022-transaction-structure/0022-transaction-structure.md) for the full transaction structure. -![](since-encoding.jpg) +![Since Encoding](since-encoding.jpg) -* The highest bit is the relative flag. +* The highest bit is used to specify if the `value` is `absolute` or `relative`. - * `0`: The `value` is absolute - * `1`: The `value` is relative + * `0`: The `value` is `absolute`. + * `1`: The `value` is `relative`. -* The following two bits choose which metric to specify the precondition. It is also the unit of the `value`. +* The next two bits specify the metric which will be used to interpret `value` and to calculate the treshold value and target value. - * `00`: Use block number. - * `01`: Use epoch number with fraction. - * `10`: Use the timestamp median of the previous 37 block headers. - * `11`: Invalid. Transaction should not set the metric flag to `11`. + * `00`: Use the block number. + * `01`: Use the epoch number with fraction. + * `10`: Use the median timestamp of the previous 37 block headers. + * `11`: Invalid. The metric flag should never be set to `11`. -* The next 5 bits are reserved for future extension. They must be all zeros now. +* The next 5 bits are reserved for future extension. They must all be set to zero for now. -How to interpret the `value` part depends on the metric in use. +Interpretation of `value` is dependent on the metric which was specified. -For block number (`00`) and timestamp median (`10`), `value` is a 56-bit unsigned integer. +When the metric flag is set to block number (`00`) or timestamp median (`10`), then `value` is a 56-bit unsigned integer stored in little-endian. -When the metric flag is `01`, `value` represents a rational number `E + I / L`, where +When the metric flag is set to epoch number with fraction (`01`), `value` represents an epoch (E), epoch index (I), and epoch length (L). These three values are encoded into `value` as follows: * `E` has 3 bytes, from the lowest bit 0 to 23. -* `I` has 2 bytes, from the bit 24 to 39. -* `L` has 2 bytes, from the bit 40 to 55. +* `I` has 2 bytes, from bit 24 to 39. +* `L` has 2 bytes, from bit 40 to 55. + +Note: The bit ranges for `E`, `I`, and `L` are using [LSB 0 Bit Numbering](https://en.wikipedia.org/wiki/Bit_numbering#LSB_0_bit_numbering) which counts from right to left. All three values are stored in little-endian. + +The following diagram illustrates how the `E`, `I`, and `L` bit ranges are positioned within the 56-bit `value` portion of the `since` field. + +![EIL Encoding](e-i-l-encoding.png) -Following table shows how to decode different parts of `since` using bit operations right shift (`>>`), left shift (`<<`), and bit and (`&`). +The following table shows how to decode different values contained within `since` using bit operations right shift (`>>`), left shift (`<<`), and bit and (`&`). | Name | Bit Operation | | ---- | ------------- | @@ -81,72 +93,76 @@ Following table shows how to decode different parts of `since` using bit operati There are three major steps to verify the since precondition: -1. Decode: Decode since and verify the format is valid. -2. Compute Threshold: Determine the commitment block and compute the threshold for relative since precondition. -3. Derive and Compare: Derive the target value from the block that is going to commit the transaction. Compare it with the threshold to check whether the precondition is fulfilled. +1. Decode Values: Extract the necessary values which are encoded within the `since` field and verify the format is valid. +2. Compute Threshold Value: Determine the threshold value that will be used for comparison. +3. Derive Target Value and Compare: Derive the target value from the block that is going to commit the transaction. Compare it with the threshold value to check whether the precondition is fulfilled. -Following is the flowchart of the verification process. +The following flowchart illustrates the verification process. -![](since-verification.jpg) +![Since Verification](since-verification.jpg) -#### Step 1. Decode +#### Step 1. Decode Values -> Decode since and verify the format is valid. +> Extract the necessary values which are encoded within the `since` field and verify the format is valid. -If the since field is zero, skip current input since precondition verification. Otherwise, verify that the format is valid: +If the `since` field value is zero, then this indicates that since precondition is not used and verification can be skipped. + +If the `since` field value is not zero, verify that the format is valid: 1. The metric flag should not be `11`. 2. The reserved flags must be all zeros. -3. When the metric flag is epoch number with fraction (`01`), `I` must be less than `L`, or they are both zeros. If the latter is the case, the since value is `E + 0 / 1`. +3. When the metric flag is epoch number with fraction (`01`), `I` must be less than `L`, or they must both be zeros. In the latter case, the `I` and `L` values will be set to `0` and `1` respectively. + +If the format is valid, the process moves on to the next step. + +#### Step 2. Compute Threshold Value -Continue the next two steps when the since field format is valid. +> Determine the threshold value that will be used for comparison. -#### Step 2. Compute Threshold +The relative flag specifies if `absolute` or `relative` should be used to determine the threshold value. -> Determine the commitment block and compute the threshold for relative since precondition. +When `absolute` is specified, the threshold value is set to the 56-bit `value` portion of the `since` field. This is a simple process that copies the value directly without any conversion, and no further steps need to be taken. -The threshold value is the decoded value part of the since field for the absolute precondition. +When `relative` is specified, the threshold value is set to the base value derived from the commitment block plus the (56-bit) `value` portion of the `since` field. -The relative precondition threshold depends on the commitment block of the current transaction input. +##### Commitment Block -The term "commit" comes from the two-step transaction confirmation protocol in [RFC20][]. A block commits a transaction by including it in the commitment zone of the block body. The commitment block of a transaction is the block which has committed the transaction. +A two-step transaction confirmation protocol is used by CKB, and it is defined in [RFC20][]. A transaction is only considered committed when it is included in the commitment zone of a block. The commitment block of a transaction is the block that committed the transaction. [RFC20]: ../0020-ckb-consensus-protocol/0020-ckb-consensus-protocol.md#two-step-transaction-confirmation -In CKB, the transaction input is a reference to an output of another transaction. The commitment block of a transaction input is the commitment block of the transaction producing the referenced output. +A transaction input is a reference to an output of another transaction. The commitment block of a transaction input is the same as the commitment block of the transaction producing the referenced output. -![](commitment-block.jpg) +In the diagram below, `Block B` is the commitment block of `Input 0` of `Transaction X`. -For example, in the diagram above, the block B is the commitment block of input 0 of the transaction X. +![Commitment Block](commitment-block.jpg) -The base value is from the input commitment block. +##### Base Value + +The base value is derived from the input commitment block according to the metric that is specified. 1. If the metric flag is `00` (block number), the base value is the block number of the commitment block. -2. If the metric flag is `01` (epoch number with fraction), the base value is the epoch field in the commitment block header, which is also a rational number. +2. If the metric flag is `01` (epoch number with fraction), the base value is the epoch field in the commitment block header. This shares the same encoding as the aforementioned epoch field which contains the individual values for epoch (E), epoch index (I), and epoch length (L). 3. If the metric flag is `10` (timestamp), the base value is the timestamp field in the commitment block header. -The threshold value of a relative precondition equals to the base value plus the decoded since value. +The threshold value of an `absolute` precondition equals the 56-bit `value` portion of the `since` field. The threshold value of a `relative` precondition equals the base value plus the `value` portion of the `since` field. -The diagram below summarizes the threshold value computation process. +The diagram below visualizes the threshold value computation process. -![](threshold-value.jpg) +![Threshold Value](threshold-value.jpg) -#### Step 3. Derive and Compare +#### Step 3. Derive Target Value and Compare > Derive the target value from the block that is going to commit the transaction. Compare it with the threshold to check whether the precondition is fulfilled. -This section will refer to the block that is going to commit the transaction as the target block. - -The target block of a committed transaction is the block which has committed the transaction. For the pending transactions in the air or the memory pool, the target block is the next to-be-mined block. - -Note that the target value does not depend on the fields in the target block headers to ensure that the target value is determined for both committed and pending transactions. +We will use the term "target block" to refer to the block that commits a transaction. The target block of a committed transaction is the mined block which included the transaction. This is the same as the commitment block. The target block of a pending transaction in the mempool or in transit is the next block that will be mined, but has not been mined yet. -The target value is from the target block preceding blocks that: +The target value is determined by the target block depending on which metric was selected. These are calculated as follows: -1. If the metric flag is `00` (block number), the target value is the parent block number plus 1. -2. If the metric flag is `01` (epoch number with fraction), and the parent block epoch is `E + I / L`, the target value is `E + (I + 1) / L`. +1. If the metric flag is `00` (block number), the target value is the block number of the last mined block, plus 1. +2. If the metric flag is `01` (epoch number with fraction), the target value is the next index of the last mined block. If the last mined block is `500 10/20` (E = 500, I = 10, L = 20), then the target value is `500 11/20` (E = 500, I = 11, L = 20). 3. If the metric flag is `10` (timestamp), the target value is the median of the timestamp field of the 37 blocks preceding the target block. -![](target-value.jpg) +![Target Value](target-value.jpg) -The last step is comparing the threshold value and the target value. The precondition is fulfilled if the target value is larger than or equals to the threshold value. +The final step is to compare the target value to the threshold value. The precondition is fulfilled if the target value is equal to or greater than the threshold value. diff --git a/rfcs/0017-tx-valid-since/e-i-l-encoding.png b/rfcs/0017-tx-valid-since/e-i-l-encoding.png new file mode 100644 index 0000000000000000000000000000000000000000..0f746ee95aba68cd86e55872bceac3ab4f6e211d GIT binary patch literal 21467 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 literal 0 HcmV?d00001