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

Fix poll_ready usage in ChainVerifier #1700

Merged
merged 11 commits into from
Feb 8, 2021

Conversation

oxarbitrage
Copy link
Contributor

@oxarbitrage oxarbitrage commented Feb 5, 2021

Motivation

Work in progress for #1679

Solution

Review

Related Issues

Closes #1679.

Fixes part of #1675.

Follow Up Work

Clippy will fail on this PR until #1706 merges.

And rename the chain verifier fields so `block` means `Arc<Block>`, and
`block_verifier` means `Buffer<BlockVerifier, ...>`.
Comment on lines 59 to +62
/// block could not be checkpointed
Checkpoint(#[source] VerifyCheckpointError),
Checkpoint(#[source] BoxError),
/// block could not be verified
Block(#[source] VerifyBlockError),
Block(#[source] BoxError),
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we're using a Buffer, we get BoxErrors back from the checkpoint and block verifiers.

@teor2345 teor2345 force-pushed the issue1679 branch 2 times, most recently from 89dd361 to 1c8c435 Compare February 8, 2021 00:41
Comment on lines +78 to +80
// We can't call `poll_ready` on the block and checkpoint verifiers here,
// because each `poll_ready` must be followed by a `call`, and we don't
// know which verifier we're going to choose yet.
Copy link
Contributor

Choose a reason for hiding this comment

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

We can't call poll_ready here - it doesn't matter what we do with the results, it's the call that takes up a buffer slot.

Copy link
Contributor

@teor2345 teor2345 Feb 8, 2021

Choose a reason for hiding this comment

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

@yaahc - this constraint is something to keep in mind for future service code reviews.

If we call poll_ready, but there isn't a matching call, we fill up our Buffers with unused reservations, and Zebra hangs.

Comment on lines -75 to +102
.checkpoint
.call(block)
.checkpoint_verifier
.clone()
.oneshot(block)
.map_err(VerifyChainError::Checkpoint)
.boxed(),
// This also covers blocks with no height, which the block verifier
// will reject immediately.
_ => self
.block
.call(block)
.block_verifier
.clone()
.oneshot(block)
Copy link
Contributor

@teor2345 teor2345 Feb 8, 2021

Choose a reason for hiding this comment

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

These services are now Buffered, so we don't need an async block. We can just call ServiceExt::oneshot on a cloned service, and return those futures.

Copy link
Contributor

Choose a reason for hiding this comment

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

@yaahc @oxarbitrage the best way to avoid poll_ready / call mismatches is to just use a oneshot.

It handles the poll_ready and call internally, so we can't possibly get it wrong.

Comment on lines +149 to +159
let block_verifier = BlockVerifier::new(network, state_service.clone());
let checkpoint_verifier = CheckpointVerifier::from_checkpoint_list(list, tip, state_service);

let block_verifier = Buffer::new(block_verifier, VERIFIER_BUFFER_BOUND);
let checkpoint_verifier = Buffer::new(checkpoint_verifier, VERIFIER_BUFFER_BOUND);
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a bit easier to read the code if we create the services, then replace them with buffered versions.

@teor2345 teor2345 changed the title [WIP] Attempt to fix poll_ready usage in ChainVerifier Fix poll_ready usage in ChainVerifier Feb 8, 2021
@teor2345 teor2345 added A-rust Area: Updates to Rust code C-bug Category: This is a bug C-cleanup Category: This is a cleanup P-High labels Feb 8, 2021
@teor2345 teor2345 added this to the 2021 Sprint 2 milestone Feb 8, 2021
And:
* make the code look like the `main` branch as much as possible
* document the `poll_ready`/`call` invariant
Comment on lines +140 to 148
// Correctness:
//
// We use `ServiceExt::oneshot` to make sure every `poll_ready` has a
// matching `call`. See #1593 for details.
let tip = match state_service
.ready_and()
.await
.unwrap()
.call(zs::Request::Tip)
.clone()
.oneshot(zs::Request::Tip)
.await
.unwrap()
Copy link
Contributor

Choose a reason for hiding this comment

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

This fix is part of #1675 - and it's actually something I missed during my review last week.

Since we're fixing this file, let's also use ServiceExt::oneshot here.

Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

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

I think this PR is fine now, but I wrote some of it, so @oxarbitrage or @yaahc should review it before it merges.

@oxarbitrage
Copy link
Contributor Author

@teor2345 this looks great and thank you for all the comments, the logic looks good and the code very clean and concise.

I had a few problems with the references we had before to do this change.

1- #1593 was too long and general. This is ok and all useful information but i got lost.
2- #1620 makes more changes than are actually needed to implement oneshot. Got lost trying to understand them.
3- The issue #1679 was suggesting initially a solution without oneshot. I was not smart enough to try to apply it anyways, it is a lot easier than making the matches "manually".

However, with the content of this PR everything is a lot clear to me.

This PR teaches:

  • how to buffer and use buffered services and errors.
  • how to use oneshot.
  • comments explain how to do poll_ready and match calls method.

@teor2345
Copy link
Contributor

teor2345 commented Feb 8, 2021

I'm re-running the jobs to make sure #1706 fixes clippy.

@teor2345
Copy link
Contributor

teor2345 commented Feb 8, 2021

I think clippy failed because it's working on the head commit, or an old merge.

Let's just merge, the type is used, so clippy should pass on main.

Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

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

I wrote some of this, and others have checked it, so it's good.

@teor2345 teor2345 merged commit 0723ac5 into ZcashFoundation:main Feb 8, 2021
dconnolly pushed a commit that referenced this pull request Feb 11, 2021
* change `poll_ready()` and `call()` of `ChainVerifier`
* add bound, move max_checkpoint_height
* add buffers to the checkpoint and block verifiers

And rename the chain verifier fields so `block` means `Arc<Block>`, and
`block_verifier` means `Buffer<BlockVerifier, ...>`.

* Fix the error types
* Use `ServiceExt::oneshot` in `ChainVerifier::call`

And:
* make the code look like the `main` branch as much as possible
* document the `poll_ready`/`call` invariant

* Use `ServiceExt::oneshot` in `chain::init`

Co-authored-by: teor <[email protected]>
teor2345 added a commit that referenced this pull request Feb 15, 2021
teor2345 added a commit that referenced this pull request Feb 20, 2021
* Revert "Fix poll_ready usage in ChainVerifier (#1700)"

This reverts commit 0723ac5.

* Keep the VERIFIER_BUFFER_BOUND change
* Correctly implement multiple readiness
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rust Area: Updates to Rust code C-bug Category: This is a bug C-cleanup Category: This is a cleanup
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix poll_ready usage for the ChainVerifier service
2 participants