From 5634ae00ebbae621644a121c53bc0ff299a000ed Mon Sep 17 00:00:00 2001 From: linning Date: Wed, 31 Jul 2024 04:05:26 +0800 Subject: [PATCH] Add receipt gap changes Signed-off-by: linning --- docs/decex/bundles_blocks.md | 2 +- docs/decex/interfaces.md | 6 ++++++ docs/decex/overview.md | 6 ++++++ docs/decex/workflow.md | 32 +++++++++++++++++++++++--------- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/docs/decex/bundles_blocks.md b/docs/decex/bundles_blocks.md index b558c10..09818a6 100644 --- a/docs/decex/bundles_blocks.md +++ b/docs/decex/bundles_blocks.md @@ -34,7 +34,7 @@ Operators produce bundles, which add new extrinsics to the execution inbox, and The bundle body is largely an “opaque blob” for consensus nodes. They only check to ensure the total size, weight, and Merkle roots are correct, but they should not need to interpret the semantics of individual transactions. - `extrinsics` -an ordered list of all new extrinsics being proposed by this operator for the next domain block. +an ordered list of all new extrinsics being proposed by this operator for the next domain block. All the extrinsic is verified against the last domain block according to the `ExecutionReceipt` in the bundle header. ### Bundle Limits diff --git a/docs/decex/interfaces.md b/docs/decex/interfaces.md index 124c30b..f2fdccb 100644 --- a/docs/decex/interfaces.md +++ b/docs/decex/interfaces.md @@ -50,6 +50,12 @@ Any staked operator who is elected may produce and submit a new bundle. The bund Challenges an ER committed to in the `BlockTree` of a domain on the consensus chain with proof. This proof could be one of several types, such as invalid state transition or bundle equivocation. Consensus nodes will verify the proof before broadcasting on the network. The next farmer elected to produce a block will include all valid challenges it has received. This will result in pruning the invalid ER, along with all of its children from the `BlockTree`, while de-registering and slashing all accompanying operators in the `Operators` registry and their nominators. +### submit_receipt + +`submit_receipt(domain_id, execution_receipt)` + +This call is used to submit the receipt alone to the consensus chain when there is a gap between the latest domain block (i.e. `HeadDomainNumber`) and the latest receipt on chain (i.e. `HeadReceiptNumber`), which usually happens after a fraud proof is accepted. Similar to `submit_bundle`, `submit_receipt` also contains a proof-of-election and an execution receipt and performs the same check, but it doesn't contain any domain extrinsic thus doesn't derive a new domain block. + ### register_domain_runtime `register_domain_runtime(name, runtime_blob) → runtime_id` diff --git a/docs/decex/overview.md b/docs/decex/overview.md index 444d653..2667b77 100644 --- a/docs/decex/overview.md +++ b/docs/decex/overview.md @@ -85,3 +85,9 @@ last_update: Any node who observes an `ExecutionReceipt` within any bundle for any consensus chain block that differs from what they produced locally has detected fraud. To handle the fraud they will produce a `submit_fraud_proof` extrinsic, which includes a proof. If the proof is valid, it will be included in the consensus chain, which will prune the `ExecutionReceipt` (and all children) from the `BlockTree` and slash all related operators. For more details, see [Slashing Stake](staking.md#slashing-stake) and [Fraud Proofs](fraud_proofs.md). + +11. **Submit Missing Receipt** + + After a fraud proof is accepted, the targetted bad receipt and all its descendant receipts will be pruned, this will create a gap between the latest domain block (i.e. `HeadDomainNumber`) and the latest receipt on chain (i.e. `HeadReceiptNumber`), when this happen the operator will start producing the `submit_receipt` extrinsic to fill up this gap, and after `HeadDomainNumber - HeadReceiptNumber = 1` the operator will resume producing `submit_bundle` extrinsic. + + For more details, see [`submit_receipt`](interfaces.md#submit-receipt) and [Lagging operator protection](workflow.md#lagging-operator-protection). diff --git a/docs/decex/workflow.md b/docs/decex/workflow.md index d23d7f3..591cfb4 100644 --- a/docs/decex/workflow.md +++ b/docs/decex/workflow.md @@ -137,22 +137,26 @@ The operator may only include as many transactions within this range as fit with All consensus nodes will perform the following verification when a new bundle is received over the network. All valid bundles are added to the local extrinsics pool and propagated to all peers on the network. Any invalid bundles are not added to the pool (no fraud proofs for invalid bundles received, only fraud proofs for invalid bundles that are included in a block). -1. Verify the `domain_id` is in the `DomainRegistry`. -2. Verify the `ProofOfElection` for this domain and operator. +1. Ensure `HeadDomainNumber - HeadReceiptNumber = 1` otherwise `submit_receipt` is expected instead of `submit_bundle` +2. Verify the `domain_id` is in the `DomainRegistry`. +3. Verify the `ProofOfElection` for this domain and operator. 1. Ensure the `slot_number` is no older than the slot of the block `current_block_number - BundleLongevity`. 2. Verify the `slot_number` and the `proof_of_time` is correctly computed. 3. Verify the `vrf_signature` based on the operator signing key and the global challenge that is derived from the `slot_number` and the `proof_of_time`. 4. Verify the `vrf_signature` is below the threshold that is derived from the `operator_stake / total_domain_stake` and the `bundle_slot_probability`. -3. Verify the bundle header `signature` for the registered domain operator. -4. Ensure the bundle does not exceed the bundle `max_bundle_weight` and `max_bundle_size` [limits](bundles_blocks.md#bundle-limits) for this domain. -5. Ensure the bundle is well-formed: +4. Verify the bundle header `signature` for the registered domain operator. +5. Ensure the bundle does not exceed the bundle `max_bundle_weight` and `max_bundle_size` [limits](bundles_blocks.md#bundle-limits) for this domain. +6. Ensure the bundle is well-formed: 1. Verify the `execution_trace_root` is correctly computed for the `execution_trace`. 2. Verify the `bundle_extrinsics_root` is correctly computed for all included extrinsics. 3. Verify the `bundle_size` and `estimated_bundle_weight` were correctly computed for the bundle body. -6. Ensure the `ExecutionReceipt` builds on the current `BlockTree` for this domain. - 1. Verify the `consensus_block_hash` exists at the specified `consenus_block_height` on the consensus client. - 2. Based on `parent_domain_receipt_hash`, verify the `parent_domain_block` exists at the specified `parent_domain_height` within the `BlockTree` on the operator client. If the ER is beyond the `BlockTreePruningDepth` it is too old and will simply be ignored. - 3. Verify all `block_extrinsics_roots` exist within the `execution_inbox` of the `parent_domain_block`. +7. Ensure the `ExecutionReceipt` builds on the head of current `BlockTree` for this domain. + 1. Verify `domain_block_number` is equal to: + - `HeadReceiptNumber + 1` if this is the first bundle of the domain in the block + - or `HeadReceiptNumber` since `HeadReceiptNumber` is increased by the previous bundle in the block + 2. Verify the `consensus_block_hash` exists at the specified `consenus_block_height` on the consensus client. + 3. Based on `parent_domain_receipt_hash`, verify the `parent_domain_block` exists at the specified `parent_domain_height` within the `BlockTree` on the operator client. If the ER is beyond the `BlockTreePruningDepth` it is too old and will simply be ignored. + 4. Verify all `block_extrinsics_roots` exist within the `execution_inbox` of the `parent_domain_block`. ### Bundle Equivocation @@ -353,3 +357,13 @@ Since `pallet_domain_sudo` provides an Unsigned extrinsic, if this extrinsic is This inherent extrinsic also affects the `FraudProof::InvalidDomainExtrinsicRoot` if any malicious operator does not include this inherent while importing Domain block. Honest operators will submit above FraudProof variant with all the necessary storage proofs to construct the Domain Extrinsic root. + +## Lagging operator protection + +In a distributed system, it is inevitable that some nodes may be lagging (e.g. due to network partition or slow hardware). This is critical for the operator node because when it produces a bundle, it needs to verify and guarantee all the extrinsic included in the bundle is valid. When the domain node tries to derive a new domain block from the bundles included in the consensus block, it will also verify all the extrinsic against the latest domain block (i.e. the parent domain block of the new block), if there is any invalid extrinsic found the whole bundle will be marked as invalid and the operator who produced this bundle will be slashed. + +For a lagging operator, it is possible that when producing a bundle it verifies the extrinsic against an old domain block, and the extrinsic turns out to be invalid when other domain nodes verify it against the latest domain block, as a result, an honest but lagging operator will be slashed. + +To protect the lagging operator, the consensus node when verifying the bundle will check the bundle contains an execution receipt that is derived from the latest domain block, which means the producer is not lagging, if it is not then the bundle will not be included in the consensus block so the operator won't be slashed. + +The consensus node when performing this check also needs to ensure the execution receipt is extending the previous head receipt, this means if there is a gap between the latest domain block (i.e. `HeadDomainNumber`) and the latest receipt on chain (i.e. `HeadReceiptNumber`), which usually happen after a fraud proof is accepted and bad receipts were pruned, any bundle will be rejected. In this case, the operator needs to produce `submit_receipt` to fill up the gap and after that they can resume producing `submit_bundle`.