Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check the execution receipt received from network properly #236

Merged
merged 13 commits into from
Feb 9, 2022

Conversation

liuchengxu
Copy link
Contributor

@liuchengxu liuchengxu commented Jan 29, 2022

This PR is mainly for making the locally produced execution receipt persistent for a while so that the executor can compare it with the external ER and propose a fraud proof in case of any invalid state transition in the external ER.

The first 3 commits are basically about some refactorings, and then the core of this PR follows. Making it a draft due to these TODOs, but the other commits are ready to be reviewed.

TODOs:

Copy link
Member

@nazar-pc nazar-pc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I think we need something like orphan ERs in this case to handle it gracefully, but it is definitely tricky to do in a way that is DoS resistant

cumulus/client/cirrus-executor/src/processor.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/lib.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/aux_schema.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/lib.rs Show resolved Hide resolved
rx.recv()??
};

// TODO: What happens for this obvious error?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as in any other case, you compare trace item one by one and generate fraud proof for item that is wrong or missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a possible case that an external ER that contains all the valid roots and some extra ones? In that case comparing on the iterator won't detect it, but I believe the block will still fail in the verification somewhere else.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything is possible, adversary can create whatever ER they want 🙂

cumulus/client/cirrus-executor/src/lib.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/lib.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/processor.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/Cargo.toml Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/processor.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/processor.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/aux_schema.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/aux_schema.rs Outdated Show resolved Hide resolved
@liuchengxu
Copy link
Contributor Author

@nazar-pc This PR is ready for another review, the last 4 commits are new since your last review.

Copy link
Member

@nazar-pc nazar-pc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments, but nothing critical

Comment on lines 62 to 63
let mut to_delete_block_number = first_saved_receipt;
while to_delete_block_number < new_first_saved_receipt {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_delete_block_number is basically from and new_first_saved_receipt is basically to.

Instead of transforming those into Block::Header::Number, I'd convert them into subspace_core_primitives::BlockNumber and iterated over the range of numbers instead, that would be easier to read rather than manually incrementing stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converting to subspace_core_primitives::BlockNumber might be helpful to simplify the loop, but you have to convert it back to Number as the encode for u32 and Block::Header::Number is different(discovered by the existing test, perhaps the compact of codec is related, I didn't look into this) unless you want to use u32 as the part of the final key to insert into the store.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is fine to use BlockNumber as a final key. Also it might be different in tests (I see that often tests use u64 for block number), but should be the same in production since we use u32 everywhere as a block number otherwise.

cumulus/client/cirrus-executor/src/aux_schema.rs Outdated Show resolved Hide resolved
@@ -47,18 +59,28 @@ pub(super) fn write_execution_receipt<Backend: AuxStore, Block: BlockT>(
new_first_saved_receipt = block_number.saturating_sub((PRUNING_DEPTH - 1).saturated_into());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these cases I would honestly prefer .expect() since we don't expect these numbers to ever be beyond u32::MAX.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to refactor it directly as I don't see another style that is satisfying to me using expect() :P.

cumulus/client/cirrus-executor/src/processor.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/merkle_tree.rs Outdated Show resolved Hide resolved
cumulus/client/cirrus-executor/src/merkle_tree.rs Outdated Show resolved Hide resolved
i1i1
i1i1 previously approved these changes Feb 9, 2022
Refactor `ExecutionReceipt`:

- Rename `state_transition_root` to `trace_root`.
- Include the list of all storage roots in the execution as `trace`.
Only the authority executors are allowed to participate the election,
the winner of which will be able to broadcast the exeuction recepit to
the network, and then we could run an authority executor node and
a full executor node locally.
We have to use the block number as key because the time is measured in
block number only.
Store the execution receipt by block hash, use another storage for
tracking the associated block number to have knowledge of if it's too
old and should be pruned.

This commit also removes the deletion of local ER even it's correctly
validated, now the obsolete ERs will be removed soly according to the
prune depth.
…te_roots()`

Using `parent_hash` is wrong because we need to call the api on top of
the newly created best block to get the intermediate roots for this
just executed block.
@liuchengxu liuchengxu merged commit adffe34 into main Feb 9, 2022
@liuchengxu liuchengxu deleted the check-external-ER branch February 9, 2022 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants