Fraud Proofs
Every domain operator executes the domain block (as described), derived deterministically from the consensus block, and submits this computational result to the consensus chain as an execution receipt within the next bundle this operator produces, thereby committing to the execution result. By default, the computation result is optimistically assumed correct until challenged by a fraud proof during the challenge period of BlockTreePruningDepth
blocks. All domain nodes scrutinize the submitted execution results, and upon detecting any discrepancies, they challenge the execution by submitting a fraud proof to the consensus chain as an unsigned extrinsic.
A fraud proof either explicitly includes all necessary data and the state of the domain required for the verification process or via a runtime storage proof. This way, a fraud can be executed by a node on the consensus chain, which has access to the MMR roots for historical state, but not the full domain state. If the node who detected fraud is also a registered operator of this domain, they can submit a new execution receipt to the consensus chain with their next bundle, which will override the fraudulent one in the block tree once the fraud proof is accepted by the consensus chain.
Any domain node (a node that has an up-to-date state of domain A) can submit fraud proofs for domain A. Whether the node is acting honestly or not in this particular instance is determined by the validity of the fraud proof. The node does not have to stake or run operator (produce bundles) to report fraud.
Fraud proofs are verified on the client side, first in the transaction pool and then on importing the block.
Broadly, fraud proofs can be categorized into those caused by invalid execution receipt fields and those caused by invalid state transitions.
Structure
A fraud proof contains the following fields:
domain_id
: domain identifier of the domain this fraud proof targetsbad_receipt_hash
: hash of the claimed invalid execution receiptmaybe_mmr_proof
: MMR proof for the consensus state root of the consensus block from which the Execution Receipt is derived, used to verify the storage proof. Only the Invalid Extrinsics Root, Incorrect List of Inboxed Bundles fraud proofs are using the MMR proof during verification, for other fraud proofs it is set toNone
.maybe_domain_runtime_code_proof
: domain runtime code storage proof and MMR proof for the parent block. May be set toNone
if the specific fraud proof variant doesn't require domain runtime code for verification or the required domain runtime code is available from the current runtime state. This field is usually required if the domain runtime code was upgraded during the challenge period.proof
: storage proof for specific variant of the fraud proof.
We currently handle the following variants of fraud proofs:
Execution Receipt invalid due to incorrect fields:
- Invalid Block Fees - incorrect fees information
- Invalid Transfers - incorrect bookkeeping of transferred or burnt coins on domain
- Invalid Extrinsics Root - incorrect set or order of extrinsics executed in this ER
- Invalid Domain Block Hash - incorrect domain block header hash
- Incorrect List of Inboxed Bundles - some valid bundles were listed as invalid, or missing, and/or some executed bundles were invalid due to extrinsics in their body being invalid, in order of
InvalidBundleType
.
Incorrect state transition:
Invalid Bundle
An invalid bundle is a bundle that exhibits misbehavior either in its extrinsic content or the execution receipt. An invalid bundle may or may not go into the consensus block. If the consensus node can identify the invalidity of a bundle without requiring the transaction data, such bundles will be promptly detected and rejected by the consensus node. As a result, they will not be included in the consensus block. On the other hand, there may be other invalid bundles that the consensus node cannot identify without processing the complete transaction data. In such cases, these invalid bundles will be included in the consensus block and handled by the operators.
Operators will be responsible for filtering out the invalid bundles included in the consensus block. A bundle can be invalid due to one or several extrinsics in its body being invalid, for the following reasons in this order (InvalidBundleType
):
UndecodableTx(extrinsic_index)
OutOfRangeTx(extrinsic_index)
InherentExtrinsic(extrinsic_index)
IllegalTx(extrinsic_index)
InvalidBundleWeight
An operator executing a domain block will signal such invalid bundles with their InvalidBundleType
in the execution receipt ER::inboxed_bundles
field. Once the ER is confirmed, the authors of invalid bundles will be slashed.
Once operators have signaled all invalid bundles, the remaining data for computation is considered clean, following conventional Fraud Proof principles. To prove the integrity of clean data later, auxiliary data is added to the receipt, including crucial information like inboxed_bundles
, domain_block_extrinsics_root
, and domain_block_hash
. The transactions within the remaining bundles are compiled into the final extrinsic list of the domain block, which is subsequently executed. Any misbehavior from this execution would fall under an invalid state transition category.
Invalid Receipt
An invalid execution receipt (ER) of a domain block may exhibit misbehavior either in its executed extrinsic content or auxiliary information fields. The execution receipt for the previous block are submitted by the operator together with their next bundle as a way to make operators commit to their ERs. For the complete list of ER fields see Execution Receipt
When an honest operator detects an incorrect field in ER produced by another operator, they submit a fraud proof. If such proof is valid, the fraudulent operator is slashed off their stake immediately.
Consensus Nodes
The consensus node will verify as much as possible on receiving a bundle as described here.Once the bundles are well-formed, the consensus node can include them in the block. Verifying other reasons for invalid bundles exceeds the ability of the consensus node and is deterred to operators.
Operators
After the operator receives a new consensus block, they validate the bundles relevant to their domain included in that block. They check the bundle for cases where a dishonest operator may have attempted to manipulate it by adding extrinsics that are not supposed to be included or removing them.
A class of fraudulent behaviors to be caught by honest operators within bundles are the discrepancies in the various domain state-related Execution Receipt (ER
) fields (domain_block_extrinsics_root
, execution_trace
, etc.).
Invalid Block Fees
A dishonest operator may include incorrect info on fees extracted from the executed block, causing an incorrect ER::block_fees
field.
Detect if the external ER has a different block_fees
field, if so the operator will need to construct a fraud proof that includes the correct block_fees
field and data that prove the integrity of this correct block_fees
.
Prover provides:
domain_id
: the id of the domain this fraud proof targetedbad_receipt_hash
: the targeted invalid ERmaybe_domain_runtime_code_proof
: for the runtime code if it is not still present in the state.storage_proof
: the storage proof of theBlockFees
storage item from the domain chain that attests correctblock_fees
value.
Verifier checks:
- Verify
bad_receipt_hash
exists - Get the domain runtime code that used to derive the target receipt: if the runtime code is still present in the state then get it from the state, otherwise from the
maybe_domain_runtime_code_proof
storage proof with MMR proof. - Get the storage key for
BlockFees
from the runtime code and decode the value from thestorage_proof
. - Verify that storage proofs included a value for
block_fees != bad_receipt_hash::block_fees
. - If both are same ⇒ Ignore the fraud proof.
Invalid Transfers
A dishonest operator may include incorrect info on transfers sent or received in extrinsics of the executed block, causing an incorrect ER::transfers
field.
Detect if the external ER has a different transfers
field, if so the operator will need to construct a fraud proof that includes the correct transfers
field and data that prove the integrity of this correct transfers
.
Prover provides:
domain_id
: the id of the domain this fraud proof targetedbad_receipt_hash
: the targeted invalid ERmaybe_domain_runtime_code_proof
: for the runtime code if it is not still present in the state.storage_proof
: the storage proof of theTransfers
storage item from the domain chain that attests correcttransfers
value.
Verifier checks:
- Verify
bad_receipt_hash
exists. - Get the domain runtime code that used to derive the target receipt: if the runtime code is still present in the state then get it from the state, otherwise from the
maybe_domain_runtime_code_proof
storage proof with MMR proof. - Get the storage key for
Transfers
from the runtime code and decode the value from thestorage_proof
. - Verify that storage proofs included a value for
transfers.transfers_in != bad_receipt_hash::transfers.transfers_in
ortransfers.transfers_out != bad_receipt_hash::transfers.transfers_out
. - If both are same ⇒ Ignore the fraud proof.
Invalid Extrinsics Root
When building a domain block, a dishonest operator may incorrectly change the extrinsics ordering compiled from the bundles or include an incorrect timestamp or runtime code upgrade inherents, causing an incorrect ER::domain_block_extrinsics_root
field. This field represents the Merkle root of the final compiled extrinsic list, obtained from the bundles and specifically used to construct the domain block
- Ordering transactions requires a known set of extrinsics, which, in turn, depends on identifying valid bundles. As such, this type of fraud proof depends on the Incorrect List of Inboxed Bundles, which should be reported first.
- Once we have a set of valid bundles from the host function, an honest operator can identify a mismatch in the
domain_block_extrinsics_root
, they can generate a fraud proof by providing all the bundles present in the corresponding consensus block.
Upon receiving the proof, the consensus node can rerun the shuffle algorithm to reconstruct the final extrinsic list and obtain the correct domain_block_extrinsics_root
value.
Prover provides:
domain_id
: ID of the domain this fraud proof targets.bad_receipt_hash
: the targeted invalid ER.mmr_proof
: MMR proof for the consensus block from which the receipt is derived.maybe_domain_runtime_code_proof
: for the runtime code if it is not still present in the state.valid_bundle_digests
: list of lists of extrinsics(index, (signer,hash))
from all bundles.block_randomness_proof
: storage proof of theBlockRandomness
storage item from the consensus chain that attests correctblock_randomness
value.domain_inherent_extrinsic_data_proof
: storage proofs of the inherent extrinsics (timestamp, runtime upgrade, cost of storage, etc.) that were present in the block.
Verifier checks:
- Verify a
bad_receipt
withbad_receipt_hash
exists - Verify
mmr_proof
and obtain the corresponding state root for the consensus block number in the receipt. - Get the domain runtime code that used to derive the target receipt: if the runtime code is still present in the state then get it from the state, otherwise from the
maybe_domain_runtime_code_proof
storage proof with MMR proof. - Verify
domain_inherent_extrinsic_data_proof
andblock_randomness_proof
storage proofs. - Obtain from the
block_randomness_proof
storage proof theblock_randomness
forconsensus_block_hash
inbad_receipt
. - Obtain from the
domain_inherent_extrinsic_data_proof
storage proof any inherent extrinsics: timestamp, domain allowlist update (if applicable), consensus chain byte fee, runtime upgradeset_code
(if applicable). The inherents are not part of any bundle and are ingested directly into the domain block from the consensus chain. - Check that
valid_bundle_digests
correspond to the bundle digests in the targeted ER - Shuffle the extrinsics collected from
valid_bundle_digests
, timestamp and runtime upgrade extrinsics usingblock_randomness
as a seed - Compare if the root of the resulting ordered tree is different from
bad_receipt.domain_block_extrinsics_root
⇒ Accept the fraud proof and punish the producer ofbad_receipt
. - If the root is same ⇒ Ignore the fraud proof.
Invalid Domain Block Hash
Detect if the external ER has a different ER::domain_block_hash
field, if so, the operator will need to construct a fraud proof that includes all components necessary to construct the domain block header and data that prove the integrity of these components:
domain_id
: the id of the domain this fraud proof targetedbad_receipt_hash
, the targeted invalid ER hashdigest_storage_proof
, the storage proof of thepallet_system::Digest
storage item of the domain chain
This fraud proof depends on Invalid Extrinsics Root and Invalid State Transition proof being produced first and any fraud proofs for the parent domain block execution receipt.
Verifier checks:
- Verify the
bad_receipt
withbad_receipt_hash
exists. - Verify that
maybe_domain_runtime_code_proof
isNone
as this fraud proof variant does not require domain runtime code. - Verify
bad_receipt.parent_domain_block_receipt_hash
corresponds to an existingparent_receipt
- Verify the
digest
storage proof withER::final_state_root
- Construct the
derived_domain_block_hash
from(bad_receipt.domain_block_number, bad_receipt.domain_block_extrinsic_root, bad_receipt.final_state_root, parent_receipt.domain_block_hash, digest)
by reconstructing a new header and hashing it. - Verify that
derived_domain_block_hash != bad_receipt.domain_block_hash
⇒ Accept the fraud proof and punish the producer ofbad_receipt
. - If both
domain_block_hash
are same ⇒ Ignore the fraud proof.
Incorrect List of Inboxed Bundles
A dishonest operator may misrepresent which bundles in the domain block were deemed invalid and excluded from execution or flag valid bundles as invalid, causing an incorrect ER::inboxed_bundles
field of structure(Valid or Invalid(InvalidBundleType), extrinsics_root)
.
A fraud proof for this field only reports the first mismatch and does not need to report if there are multiple, as a single mismatch is sufficient to demonstrate the filed is incorrect.
There are several variants of why inboxed_bundles
in the receipt can be wrong:
- Valid Bundle A valid bundle is listed as valid, but the bundle digest (list of extrinsic signers and hashes) is different.
- True Invalid Bundle
- An dishonest operator tries to pass an invalid bundle as valid. If an invalid bundle is marked as
Valid
in the bad ER, a fraud proof can be generated to demonstrate the bundle is actually wrong due to one of the above listed reasons (IllegalTx
,OutOfRangeTx
, etc.). - An dishonest operator lists an invalid bundle as
Invalid
, but the reason why it is invalid (InvalidBundleType
) is incorrect (i.e. locally checkedInvalidBundleType
is of higher precedence (in this order) than listed in the ER or happens at an earlier extrinsic.)
- An dishonest operator tries to pass an invalid bundle as valid. If an invalid bundle is marked as
- False Invalid Bundle
- An dishonest operator tries to present a valid bundle as
Invalid
. A fraud proof to show thatInvalidBundleType
is unjustified. - An dishonest operator lists an invalid bundle as
Invalid
, but the reason why it is invalid (InvalidBundleType
) is incorrect (i.e. a valid extrinsic is marked as invalid, an invalid extrinsic is marked invalid for a wrong reason, etc.)
- An dishonest operator tries to present a valid bundle as
Valid Bundle
Prover provides:
domain_id
: ID of the domain this fraud proof targets.bad_receipt_hash
: the targeted invalid ER.mmr_proof
: MMR proof for the consensus block from which the receipt is derived.maybe_domain_runtime_code_proof
: for the runtime code if it is not still present in the state.bundle_with_proof
: includingbundle_index
index of mismatched bundle;bundle
bundle body; andbundle_storage_proof
storage proof.
Verifier checks:
- Verify the
bad_receipt
withbad_receipt_hash
exists. - Verify
mmr_proof
and obtain the corresponding state root for the consensus block number in the receipt. - Get the domain runtime code that used to derive the target receipt: if the runtime code is still present in the state then get it from the state, otherwise from the
maybe_domain_runtime_code_proof
storage proof with MMR proof. - Verify the
bundle_storage_proof
. - Obtain from
bundle_with_proof
thebundle
body of the bundle in question. - Compute
valid_bundle_digest
from extrinsics in thebundle
using domain runtime code. - Compare that the digest is different from the one in
bad_receipt
at the givenbundle_index
⇒ Accept the fraud proof and punish the producer ofbad_receipt
. - If the digest is same ⇒ Ignore the fraud proof.
True/False Invalid Bundle
Prover provides:
domain_id
: ID of the domain this fraud proof targets.bad_receipt_hash
: the targeted invalid ER.mmr_proof
: MMR proof for the consensus block from which the receipt is derived.maybe_domain_runtime_code_proof
: for the runtime code if it is not still present in the state.bundle_index
: index of mismatched bundleinvalid_bundle_type
: theInvalidBundleType
indicator with the mismatched extrinsic index where applicable.is_true_invalid_fraud_proof
: whether the variant of this proof isTrueInvalid
(true
) orFalseInvalid
(false
)proof_data
: specific data for the fraud proof variant.
Verifier checks:
- Verify the
bad_receipt
withbad_receipt_hash
exists. - Verify
mmr_proof
and obtain the corresponding state root for the consensus block number in the receipt. - Get the domain runtime code that used to derive the target receipt: if the runtime code is still present in the state then get it from the state, otherwise from the
maybe_domain_runtime_code_proof
storage proof with MMR proof. - Determine the fraud proof variant. If
is_true_invalid_fraud_proof==true
then it’sTrueInvalid
, elseFalseInvalid
. - Determine which scenario the fraud proof corresponds to (if any) based on its structure:
- For
FalseInvalid
, theinvalid_bundle_type
in the fraud proof andbad_receipt
should be same forbundle_index
(because the fraud proof will try to show it is wrong). - For
TrueInvalid
, either:- The proof trying to prove the bundle at
bundle_index
is invalid due toinvalid_bundle_type
whilebad_receipt
claims bundle atbundle_index
isValid
. - The proof trying to prove there is an invalid extrinsic that the
bad_receipt
thinks is valid in the questioned bundle, so the proof should point to an extrinsic with a smallerextrinsic_index
than that in of thebad_receipt
. - The proof trying to prove the invalid extrinsic at
extrinsic_index
can not pass a validity check (e.g.OutOfRangeTx
) that thebad_receipt
thinks it can, so the proof should point to the same extrinsic and a check that is performed before the one inbad_receipt
(in this order). - The proof is trying to prove an incorrect bundle weight estimate provided in the header.
- The proof trying to prove the bundle at
- If none of the above match the fields of the fraud proof ⇒ Ignore the fraud proof.
- For
- Check if the fraud proof is targetting a bad receipt that claims an extrinsic at a non-exist
extrinsic_index
is invalid. - If
extrinsic_index
exists in the bundle, verifyinvalid_bundle_type(extrinsic_index)
as defined below.
The list below constitutes the possible fraudulent behaviors an operator can check for in a set of extrinsics included in a bundle.
Undecodable Transaction
A dishonest operator may have included an extrinsic that fails to decode or excluded a decodable extrinsic as invalid.
Proof data:
extrinsic_proof
: storage proof of inclusion for the extrinsic at the index given in theinvalid_bundle_type
.
Verifier checks:
- Verify the storage proof
extrinsic_proof
and get theencoded_extrinsic
. - Attempt to decode the
encoded_extrinsic
. - If the attempt fails, the extrinsic is truly
Undecodable
. - For a
TrueInvalid
fraud proof, the tx must beUndecodable
for the fraud proof to be considered valid. - For a
FalseInvalid
fraud proof, the tx must be decodable for the fraud proof to be considered valid.
Out Of Range Transaction
A dishonest operator may have included a transaction not in the respective tx range defined here when producing a bundle or excluded a transaction within range as being out of range.
Proof data:
bundle_with_proof
: includingbundle_index
index of mismatched bundle;bundle
bundle body; andbundle_storage_proof
storage proof.
Verifier checks:
- Verify the
bundle_storage_proof
. - Obtain from
bundle_with_proof
thebundle
body of the bundle in question. - Get the extrinsic at
extrinsic_index
. - Request a check from a stateless domain runtime call on whether the transaction is within the range according to the rule defined in Transaction Selection for Bundle Production
- For a
TrueInvalid
fraud proof, the tx must be outside of the range for fraud proof to be considered valid. - For a
FalseInvalid
fraud proof, the tx must be within the range for fraud proof to be considered valid.
Inherent Extrinsic
A dishonest operator may have included an inherent extrinsic, which should not have been bundled or excluded a valid transaction that is not inherent. The inherent extrinsic data is data external to the domain from the consensus chain.
Proof data:
extrinsic_proof
: storage proof of inclusion for the extrinsic at the index given in theinvalid_bundle_type
Verifier checks:
- Verify
extrinsic_proof
and get the extrinsic atextrinsic_index
from theextrinsic_proof
. - Request a check from a stateless domain runtime call on whether the extrinsic is an inherent extrinsic.
- For a
TrueInvalid
fraud proof, the tx must be an inherent extrinsic. - For a
FalseInvalid
fraud proof, the tx must not be an inherent extrinsic.
Invalid XDM
A dishonest operator may include an XDM that contains an invalid MMR proof, because the MMR Proof verification involve the consensus node (via host function) thus can't be proven like the basic transaction validity check in Illegal Transaction, this fraud proof variant is specially proving the MMR proof verification result in a deterministic and stateless way.
Proof data:
extrinsic_proof
: storage proof of inclusion for the extrinsic at the index given in theinvalid_bundle_type
mmr_root_proof
: the storage proof of the MMR root of the consensus block where the MMR proof is constructed
Verifier checks:
- Verify
extrinsic_proof
and get the extrinsic atextrinsic_index
from theextrinsic_proof
. - Request a check from a stateless domain runtime call to extract the MMR Proof from the extrinsic if it is an XDM
- If the extrinsic is not an XDM at all, consider
TrueInvalid
fraud proof as invalid and considerFalseInvalid
fraud proof as valid.
- If the extrinsic is not an XDM at all, consider
- Verify the
mmr_root_proof
and get the MMR root - Verify the MMR proof with the MMR root using
MMR::verify_proof_stateless
- For a
TrueInvalid
fraud proof, the MMR proof must be invalid for fraud proof to be considered valid. - For a
FalseInvalid
fraud proof, the MMR proof must be valid for fraud proof to be considered valid.
Illegal Transaction
When producing a bundle, a dishonest operator may include a transaction that fails to pass the basic transaction validity check wasting the blockspace, or exclude a valid transaction. The basic checks of transaction validity are defined in Substrate, including account balance too low, bad signature, invalid XDM.
Proof data:
bundle_with_proof
: includingbundle_index
index of mismatched bundle;bundle
bundle body; andbundle_storage_proof
storage proof.execution_proof
: storage proof recorded during computation which can be used to reconstruct a partial state trie to re-run the execution by someone who does not own the whole state.
Verifier checks:
- Verify
bundle_storage_proof
and get thebundle
body of the bundle in question. - Request a check from a stateless domain runtime call of all extrinsics in the bundle within the same runtime context
- For a
TrueInvalid
fraud proof, the tx must be illegal for fraud proof to be considered valid. - For a
FalseInvalid
fraud proof, the tx must be illegal for fraud proof to be considered valid.
Invalid Bundle Weight
A dishonest operator may have included in the bundle header an incorrect estimated_bundle_weight
field for the transactions in the bundle body.
Proof data:
bundle_with_proof
: includingbundle_index
index of mismatched bundle;bundle
bundle body; andbundle_storage_proof
storage proof.
Verifier checks:
- Verify the
bundle_storage_proof
. - Obtain from
bundle_with_proof
thebundle
body of the bundle in question (all extrinsics). - Request a check from a stateless domain runtime call on whether the sum of the weights of all transactions in the bundle is equal to the
estimated_bundle_weight
field in the bundle header. - For a
TrueInvalid
fraud proof, the sum of weights of all transactions in the bundle must be different from theestimated_bundle_weight
field in the bundle header for fraud proof to be considered valid. - For a
FalseInvalid
fraud proof, the sum of weights of all transactions in the bundle must be equal to theestimated_bundle_weight
field in the bundle header for fraud proof to be considered valid.
Note
Note, that a dishonest operator may also ignore some valid transactions by not including them in the bundle.
The motivation behind such behavior could be due to the operator's laziness or, in more concerning scenarios, the operator may be maliciously excluding valid transactions for personal gain (e.g., censorship). Unfortunately, detecting such behavior is challenging and is not feasible in any way. On the positive side, the users will resubmit their transactions, eventually going to some honest operators. In other words, our design is censorship-resistant.
Invalid State Transition
A dishonest operator may produce a domain block that results in an incorrect state root by modifying the state in an invalid way ER::execution_trace
. The honest operator detects at which index of the execution trace the ER is incorrect.
This fraud proof depends on any fraud proofs for the parent domain block execution receipt (parent_receipt.domain_block_hash
).
Proving and verification algorithm varies depending on which execution phase the transition was applied wrongly.
Prover provides:
domain_id
: ID of the domain this fraud proof targets.bad_receipt_hash
: hash of the fraudulent receipt in which the trace mismatch was found.maybe_domain_runtime_code_proof
: for the runtime code if it is not still present in the state.execution_ proof
: storage proof recorded during computation which can be used to reconstruct a partial state trie to re-run the execution by someone who does not own the whole state.execution_phase
: which execution phase the alleged wrong state transition happened.-
InitializeBlock
phaseThe input data for
InitializeBlock
is the initialized block header (seeinitialize_block(header)
definition). There are five components in the domain block header:parent_hash
: hash of parent domain block headerblock_number
:state_root
: default value of Hash as it’s not executed yetextrinsics_root
: default value of Hash as it’s not initialized yetdigest
: consensus block hash
The fields are the default value or in the receipt, so the prover constructs a storage proof
proof
of the execution of theInitializeBlock
phase with the above inputs. -
ApplyExtrinsic
phase, and specifically during application of which extrinsic with(extrinsic_proof, mismatch_index)
To prove the
ApplyExtrinsic
execution step, we provide:mismatch_index
: extrinsic index in the domain block after correct shufflingextrinsic_proof
: Merkle proof of the extrinsic data at the index againstdomain_block_extrinsics_root
Verifier can fetch the full extrinsic data from the host function, so we do not have to include it.
The prover constructs the storage
proof
for the execution delta of state right before (after executing all previous extrinsics) and right after (before executing the rest of the extrinsics). -
FinalizeBlock
phase, andtrace_length
to show after how many steps of execution trace the execution of the block should be finalized (length of trace).This phase requires no additional input data.
-
Verifier checks:
- Get the domain runtime code that used to derive the target receipt: if the runtime code is still present in the state then get it from the state, otherwise from the
maybe_domain_runtime_code_proof
storage proof with MMR proof. - Verify the correctness of transition data based on
execution_phase
:InitializeBlock
phase: fetchdomain_block_hash
in the parent receiptApplyExtrinsic
phase: verify the Merkle proofextrinsic_proof
of extrinsic againstdomain_block_extrinsics_root
FinalizeBlock
- Let
M = bad_receipt.execution_trace.len()
- If
trace_length >= M
, verify that thebad_receipt
'sexecution_trace[M-2] -> execution_trace[M-1]
is not a valid state transition offinalize_block
, means theexecution_trace
should not stop at M. - If
trace_length < M
, verify thatbad_receipt
'sexecution_trace[trace_length-2] ->
execution_trace[trace_length-1]
is a valid state transition offinalize_block
, means theexecution_trace
should stop attrace_length
.
- Let
- Re-run the state transition and get the post-state root after the execution.
- If the post-state root matches the state root in the trace of the header being challenged, then the proof is invalid ⇒ ignore the proof
- If the post-state root does not match the state root in the trace, then the proof is valid ⇒ accept the proof and punish the authors of receipt identified by
bad_receipt_hash
.
Fraud proof priority in transaction pool
To prune a chain of fraudulent Execution Receipts and slash the operators who submitted them, it is sufficient to include in a consensus block and process only a single fraud proof for the oldest fraudulent ER. If the fraud proof is valid, all the children blocks will be pruned and operators slashed automatically.
A fraud proof that targets a bad ER has a priority is defined as MAX - blocks_before_bad_er_confirm
, where blocks_before_bad_er_confirm
is how many blocks remain until this ER is outside the challenge period. A fraud proof that targets a bad ER that is closer to being confirmed is more urgent and thus has a higher priority to be accepted by the transaction pool and to be included in the next consensus block. For a given domain, at most one fraud proof will be accepted by the transaction pool at a time; if an incoming fraud proof has a higher priority than the fraud proof already in the pool then it will replace the previous fraud proof, otherwise it will be rejected.
For the bundle equivocation fraud proof, since it is not time-sensitive, its priority is a constant value MAX - challenge_period - 1
thus lower than any other type of time-sensitive fraud proofs that target bad ERs. At most one bundle equivocation fraud proof will be accepted by the transaction pool at a time for a given operator. If there is already a bundle equivocation fraud proof in the pool, incoming bundle equivocation fraud proof that targets the same operator will be rejected.
For comparison, bundles have a constant priority of 1.