Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Add Error message when sync is still in progress. #9475

Merged
merged 19 commits into from
Nov 26, 2018
Merged

Add Error message when sync is still in progress. #9475

merged 19 commits into from
Nov 26, 2018

Conversation

seunlanlege
Copy link
Member

@seunlanlege seunlanlege commented Sep 4, 2018

fix #9188

@parity-cla-bot
Copy link

It looks like @seunlanlege hasn't signed our Contributor License Agreement, yet.

The purpose of a CLA is to ensure that the guardian of a project's outputs has the necessary ownership or grants of rights over all contributions to allow them to distribute under the chosen licence.
Wikipedia

You can read and sign our full Contributor License Agreement at the following URL: https://cla.parity.io

Once you've signed, please reply to this thread with [clabot:check] to prove it.

Many thanks,

Parity Technologies CLA Bot

@seunlanlege
Copy link
Member Author

[clabot:check]

@parity-cla-bot
Copy link

It looks like @seunlanlege signed our Contributor License Agreement. 👍

Many thanks,

Parity Technologies CLA Bot

dvdplm
dvdplm previously requested changes Sep 5, 2018
if let Ok(SyncStatus::Info(_)) = self.syncing() {
// alas, we're still syncing!
warn!("Attempted to fetch transaction via hash while sync is in progress");
return Box::new(future::err(errors::ancient_block_missing()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't it possible to be in a syncing state even while we're quite close to the head of the chain? As a user I think I'd be surprised to see an error about "ancient" blocks if I were essentially synched. Maybe the error message should be something more generic like Block is unavailable?

if res.is_none() {
if let Ok(SyncStatus::Info(_)) = self.syncing() {
// alas, we're still syncing!
warn!("Call made to transaction_by_block_hash_and_index while sync is in progress");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure that using the full method name here is a good idea. How about "RPC call is unavailable while synching".

if let Ok(SyncStatus::Info(_)) = self.syncing() {
// alas, we're still syncing!
warn!("Attempted to fetch transaction via hash while sync is in progress");
return Box::new(future::err(errors::ancient_block_missing()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comments from above apply here.

Maybe there's a way to add these warnings to all RPC calls higher up in the call chain so we don't have to pollute each method with log/warn calls?

Copy link
Contributor

@andresilva andresilva left a comment

Choose a reason for hiding this comment

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

I don't think this is correct and I don't think it's easy to implement this properly. The main issue is that if I give you an hash how do you distinguish from you not having the data (because you're still syncing) or the data not existing in the first place? Also the current checks for self.syncing() only check for normal sync as far as I remember, and even though I'm syncing I may already have the data available, e.g. I'm synced to block #2000 (but still syncing up to say #4000) and you ask for data from block #1000.

@andresilva
Copy link
Contributor

(reposting from private chat)

I guess for some RPCs we could implement a best-effort approach. For example to fetch transaction by hash:

  • We try to fetch it from the current chain, if we find something we return it (same behavior as now)
  • If we don't find it and we know that we're still syncing ancient blocks then we return with an error saying that the transaction wasn't found but we still don't have all the data yet, i.e. this could be a false negative (so the user can retry later when sync is finished)
  • If we don't find the data but we are fully synced we just return None in this case

Can we use this strategy for all RPC methods? Do we want to implement something like this?

@5chdn 5chdn added this to the 2.1 milestone Sep 5, 2018
@5chdn 5chdn added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. M6-rpcapi 📣 RPC API. labels Sep 5, 2018
@lexfrl lexfrl added the A5-grumble 🔥 Pull request has minor issues that must be addressed before merging. label Sep 5, 2018
Copy link
Collaborator

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

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

As in #9188 (comment) it's not really possible to implement this with significant changes to snapshot format. What's more I don't really think it's a good idea to store the tx hashes in snapshots anyway (perhaps we could store at most a bloom filter).

That said, I like @andresilva's suggestion to return an error instead of None in case we know we have not fetched ancient blocks yet (note it's very different from syncing, so self.syncing() is not the right method to use here).

If Andre's suggestion gets implemented we should also consider disabling that behaviour in case someone is consciously running with --no-ancient-blocks.

@tomusdrw
Copy link
Collaborator

tomusdrw commented Sep 5, 2018

#7411 might be a bit more straightforward - we have the block number there so we can just return an error in case block_number < latest_block_number and the data is missing (would be worth to handle logs as well, as in the comment in that issue).

Copy link
Collaborator

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

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

Still incorrect, but better. We're almost there.

RpcResult<Option<T>> {
move |res| {
if res.is_none() {
if let Ok(SyncStatus::Info(_)) = sync_status {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The syncing state doesn't really matter, unless there is a variant that tells you that: "The chain is incomplete - We are still syncing/importing ancient blocks" (Which is completely different than regular sync, some more details about warp sync: https://wiki.parity.io/Warp-Sync.html)

if let BlockNumber::Num(number) = num {
match self.client.chain_info().best_block_number {
BlockNumber::Num(best_block_number) => {
if num < best_block_number {
Copy link
Collaborator

@tomusdrw tomusdrw Sep 5, 2018

Choose a reason for hiding this comment

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

This is quite wrong, actually these are the only queries that make sense at all, since:

  1. In database we store blocks from [0...best_block_number]
  2. Querying anything from that range should succeed
  3. Querying anything greater than best_block_number will always fail

With ancient blocks the case is that the database is not complete, so we have a situation where:

  1. We have [0..best_ancient_block] ... [first_block .. best_block]
  2. The latter range has been restored together with the snapshot
  3. The former range has been downloaded during ancient block import
  4. Any query that tries to get num < best_block_number and fails (i.e. returns None) most likely falls into (best_ancient_block .. first_block) range, so we should detect that and return the error only in such case.

fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.rich_block(num.into(), include_txs)))
let result = self.check_block_existence(num)
.and_then(|_| self.rich_block(num.into(), include_txs));
Copy link
Collaborator

Choose a reason for hiding this comment

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

To make it correct you should:

  1. First query the block
  2. If it's None and num < best_block_number return ancient block unavailable error.

rpc/src/v1/impls/eth.rs Outdated Show resolved Hide resolved
@Tbaut
Copy link
Contributor

Tbaut commented Sep 5, 2018

Despite trying hard, I still can't manage to know all issues by number :) Having a human understandable description and title for a PR is therefore requested!

@5chdn 5chdn removed the A0-pleasereview 🤓 Pull request needs code review. label Sep 6, 2018
@seunlanlege seunlanlege changed the title closes #9188 Adds Error message for when sync is still in progress. Sep 6, 2018
@niklasad1 niklasad1 changed the title Adds Error message for when sync is still in progress. Add Error message when sync is still in progress. Sep 6, 2018
@5chdn 5chdn modified the milestones: 2.1, 2.2 Sep 11, 2018
Copy link
Contributor

@andresilva andresilva left a comment

Choose a reason for hiding this comment

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

Overall LGTM. Just minor comments.

return Err(Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
// this error message feels pretty straightforward to me. ¯\_(ツ)_/¯
message: "We cannot tell for sure if the thing you requested is not available or we just don't have it".into(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably better to be explicit about it? "Ancient block sync is still in progress."

let BlockChainInfo { ancient_block_hash, first_block_hash, .. } = client.chain_info();
// block information was requested, but unfortunately we couldn't find it and there
// are gaps in the database ethcore/src/blockchain/blockchain.rs:202
if ancient_block_hash.is_some() && first_block_hash.is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think first_block_hash will always be some.

pub fn unavailable_block() -> Error {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Block is unavailable".into(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably better to have a more explicit message about ancient block sync?

@andresilva
Copy link
Contributor

Please rebase/merge master to fix conflicts.

@5chdn 5chdn added the A3-stale 🍃 Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Sep 18, 2018
Copy link
Collaborator

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

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

lgtm, minor grumble regarding error message - we can distinguish between:

  1. Knowing for sure that the blocks is not there because of ancient sync
  2. Assuming that it might be not found, because we don't have all the blocks yet.

Also I believe if we merge that we should also have an option to disable this behaviour since it's a breaking change (instead of returning Ok(None) we return an Error)

{
move |response| {
if response.is_none() {
let BlockChainInfo { ancient_block_hash, first_block_hash, .. } = client.chain_info();
Copy link
Collaborator

Choose a reason for hiding this comment

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

first_block_hash is unused

// block information was requested, but unfortunately we couldn't find it and there
// are gaps in the database ethcore/src/blockchain/blockchain.rs:202
if ancient_block_hash.is_some() {
return Err(unavailable_block())
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a bit different than check_block_number_existence. Here we are unsure if the block is not valid or was not found, in the former we actually have certainty that the block is missing because we are still syncing ancient blocks.

TBH I think we should express that in the error message as well.

@5chdn 5chdn added A0-pleasereview 🤓 Pull request needs code review. and removed A3-stale 🍃 Pull request did not receive any updates in a long time. No review needed at this stage. Close it. A5-grumble 🔥 Pull request has minor issues that must be addressed before merging. labels Sep 21, 2018
@5chdn 5chdn removed the A8-looksgood 🦄 Pull request is reviewed well. label Nov 17, 2018
@seunlanlege seunlanlege added A8-looksgood 🦄 Pull request is reviewed well. and removed A7-looksgoodtestsfail 🤖 Pull request is reviewed well, but cannot be merged due to tests failing. labels Nov 20, 2018
@5chdn 5chdn added A7-looksgoodcantmerge 🙄 Pull request is reviewed well, but cannot be merged due to conflicts. and removed A8-looksgood 🦄 Pull request is reviewed well. labels Nov 21, 2018
Copy link
Collaborator

@sorpaas sorpaas left a comment

Choose a reason for hiding this comment

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

Current changes LGTM. A few grumbles. And I think there're also other APIs in eth_ namespace that can apply the same strategy:

  • block_transaction_count_by_hash
  • block_transaction_count_by_number
  • block_uncles_count_by_hash
  • block_uncles_count_by_number
  • uncle_by_block_hash_and_index
  • uncle_by_block_number_and_index

@@ -1230,6 +1234,7 @@ struct Rpc {
keep_alive: Option<bool>,
experimental_rpcs: Option<bool>,
poll_lifetime: Option<u32>,
jsonrpc_allow_missing_blocks: Option<bool>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: maybe name this just allow_missing_blocks? We need the jsonrpc prefix for args but they're already under the category for configs.

deps.miner.clone(),
$nonces,
deps.gas_price_percentile,
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: indentation is wrong.

}
}
}
}};
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: this indentation looks weird

@sorpaas
Copy link
Collaborator

sorpaas commented Nov 25, 2018

Also there's a test failure:

error[E0063]: missing field `jsonrpc_allow_missing_blocks` in initializer of `v1::impls::eth::EthClientOptions`
   --> rpc/src/v1/tests/eth.rs:143:4
    |
143 |             EthClientOptions {
    |             ^^^^^^^^^^^^^^^^ missing `jsonrpc_allow_missing_blocks`

@sorpaas sorpaas added A5-grumble 🔥 Pull request has minor issues that must be addressed before merging. and removed A7-looksgoodcantmerge 🙄 Pull request is reviewed well, but cannot be merged due to conflicts. labels Nov 25, 2018
    block_transaction_count_by_hash
    block_transaction_count_by_number
    block_uncles_count_by_hash
    block_uncles_count_by_number
    uncle_by_block_hash_and_index
    uncle_by_block_number_and_index
fix PR grumbles
parity/cli/mod.rs Outdated Show resolved Hide resolved
parity/cli/mod.rs Outdated Show resolved Hide resolved
sorpaas and others added 2 commits November 26, 2018 13:20
revert config name

Co-Authored-By: seunlanlege <[email protected]>
revert cli arg

Co-Authored-By: seunlanlege <[email protected]>
parity/cli/mod.rs Outdated Show resolved Hide resolved
parity/configuration.rs Outdated Show resolved Hide resolved
revert config name

Co-Authored-By: seunlanlege <[email protected]>
let best_block = self.client.chain_info().best_block_number;
if let Some(receipt) = self.miner.pending_receipt(best_block, &hash) {
return Box::new(future::ok(Some(receipt.into())));
match (self.miner.pending_receipt(best_block, &hash), self.options.allow_pending_receipt_query) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will unnecessarily call self.miner.pending_receipt even when self.options.allow_pending_receipt_query is false. I would suggest to change it back to the old two if form.

}

fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> {
let best_block = self.client.chain_info().best_block_number;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is only used inside if self.options.allow_pending_receipt_query {, so maybe it's better to move it back.

@sorpaas sorpaas added A8-looksgood 🦄 Pull request is reviewed well. and removed A5-grumble 🔥 Pull request has minor issues that must be addressed before merging. labels Nov 26, 2018
@sorpaas sorpaas merged commit f2281dc into master Nov 26, 2018
@sorpaas sorpaas deleted the issue-9188 branch November 26, 2018 18:58
niklasad1 pushed a commit that referenced this pull request Dec 16, 2018
* closes #9188

* check_for_unavailable_block in
eth_getTransactionByHash
eth_getTransactionByBlockHashAndIndex
eth_getTransactionByBlockNumberAndIndex
eth_getTransactionReceipt

* check for unavailable block in eth_getBlockByNumber

* corrected checks for unavailable_block

* check for block gaps in db

* corrected error messages

* corrected error information

* added allow-empty-block-result cli flag

* address grumbles

* --jsonrpc-allow-missing-blocks

* fix tests

* added checks to
    block_transaction_count_by_hash
    block_transaction_count_by_number
    block_uncles_count_by_hash
    block_uncles_count_by_number
    uncle_by_block_hash_and_index
    uncle_by_block_number_and_index
fix PR grumbles

* Update parity/cli/mod.rs

revert config name

Co-Authored-By: seunlanlege <[email protected]>

* Update parity/cli/mod.rs

revert cli arg

Co-Authored-By: seunlanlege <[email protected]>

* Apply suggestions from code review

revert config name

Co-Authored-By: seunlanlege <[email protected]>

* fix PR grumbles

* fix more PR grumbles
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well. B7-releasenotes 📜 Changes should be mentioned in the release notes of the next minor version release. M4-core ⛓ Core client code / Rust. M6-rpcapi 📣 RPC API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add error message for eth_getTransactionReceipt when ancient blocks haven't been downloaded yet (warp-sync)
9 participants