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

Check finalized block in blockchain::Blockchain #8410

Closed
wants to merge 7 commits into from

Conversation

sorpaas
Copy link
Collaborator

@sorpaas sorpaas commented Apr 16, 2018

  • Takes BlockDetails to contain finalized and metadatas in a backward compatible way -- if finalized is false and metadata is empty, it is stored as the old 4 value RLP. Otherwise, it's stored as the extended 6 value RLP.
  • Adds Blockchain::mark_finalized and Blockchain::update_metadata to update finalized value and metadata for any block (but it's not currently used anywhere).
  • Changes Blockchain::block_info to refuse re-org if it goes pass a finalized block.

@sorpaas sorpaas added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. labels Apr 16, 2018
@sorpaas sorpaas added this to the 1.11 milestone Apr 16, 2018
@sorpaas
Copy link
Collaborator Author

sorpaas commented Apr 16, 2018

In the short term we probably need to keep total_difficulty in BlockDetails. Moving it out to whatever metadata format we decide would work for full node, but breaks wrap sync and light client. This PR also uses BlockDetails for per-block metadata storage. Using this or just use the engine's new global metadata storage would both work, but I just wary whether there's any pruning operations that might remove block extra information. Need to check on this.

// but nothing in between.
let finalized_block = route.blocks.iter()
.map(|route_hash| self.block_details(&route_hash).unwrap_or_else(|| panic!("Invalid block hash in tree route: {:?}", route_hash)))
.enumerate()
Copy link
Collaborator

Choose a reason for hiding this comment

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

why not just take(route.index)?

// If anything on the tree route is finalized, refuse to reorg. The common ancestor can be finalized,
// but nothing in between.
let finalized_block = route.blocks.iter()
.map(|route_hash| self.block_details(&route_hash).unwrap_or_else(|| panic!("Invalid block hash in tree route: {:?}", route_hash)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't it be better to include finalized already in tree_route? Seems that we query block details there anyway.

@@ -979,6 +995,34 @@ impl BlockChain {
}
}

/// Mark a block to be considered finalized. Panic if the hash does not exist.
pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) {
let mut block_details = self.block_details(&block_hash).unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe better to return Result instead of panicking?

Copy link
Contributor

Choose a reason for hiding this comment

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

agree, or at least prove it won't happen

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The rest of BlockChain struct is also using panic for pub fns when a block hash is not found. I think for our case is that we're going to use mark_finalized here for results returned from Engine, and it will only call this function for already known block hashes. Otherwise, it indicates a logic error in our code. So I think it would be fine to use panic given we indicated the panic condition in the documentation.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@sorpaas I'm pretty sure we use .expect(PROOF) form everywhere, and public APIs return Option<.> if some particular block/header/details might not be available.

Seems that only add_child panics in case it's called with invalid block, the other ones calling panic are not public, and I guess could easily use expect instead.

}

/// Update metadata detail for an existing block.
pub fn update_metadatas(&self, batch: &mut DBTransaction, block_hash: H256, metadatas: HashMap<Bytes, Bytes>) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't it be better to have metadata in some more structured way? Seems that HashMap<Bytes, Bytes> is even worse than HashMap<String, String> (the latter is at least human readable)

Copy link
Collaborator Author

@sorpaas sorpaas Apr 16, 2018

Choose a reason for hiding this comment

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

Maybe HashMap<String, Bytes>? For many cases (for example, to store Casper score info U256), the value itself is readable anyway.

Another issue for the key is if we just want to prefix something recognizable with something non-readable. In that case, converting from prefix string to Bytes is easy, but probably not the other way around.

Copy link
Contributor

Choose a reason for hiding this comment

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

also: metadata is already plural

Copy link
Collaborator

@tomusdrw tomusdrw Apr 16, 2018

Choose a reason for hiding this comment

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

What I mean is maybe to return T: TryFrom<HashMap<Bytes, Bytes>> or sth (if we want to be super generic), so that the caller can decide on the expected type of metadata, otherwise we might be passing a lot of weakly-typed structures in the codebase and imho would be best to avoid that.

Alternatively maybe an enum with possible types of stored metadata if we are ok with having less generic solution and a single place where all kinds of metadata is defined.

}

/// Prepares extras block detail update.
fn prepare_details_update(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does it just prepare the update or write it to cache? Seems there is already prepare_block_details_update method in this struct and it returns the HashMap, might be a bit misleading to have that one here as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That was meant to be a stripped version of prepare_update, but yeah looks confusing. I'll change the name.

@sorpaas
Copy link
Collaborator Author

sorpaas commented Apr 17, 2018

I'm going to move this to #8401 because some of the changes are related and I might create unnecessary merge conflicts. I think I got a design now, and will explain it soon.

@sorpaas sorpaas closed this Apr 17, 2018
@5chdn 5chdn added A8-looksgood 🦄 Pull request is reviewed well. Z7-duplicate 🖨 Issue is a duplicate. Closer should comment with a link to the duplicate. and removed A0-pleasereview 🤓 Pull request needs code review. A8-looksgood 🦄 Pull request is reviewed well. labels May 16, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
M4-core ⛓ Core client code / Rust. Z7-duplicate 🖨 Issue is a duplicate. Closer should comment with a link to the duplicate.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants