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

feat(chain): add block merkle root to BlockHeaderInnerLite #2643

Merged
merged 6 commits into from
May 18, 2020

Conversation

bowenwang1996
Copy link
Collaborator

Add block merkle root to block header so that we light client can verify transaction outcomes in blocks that are not known by the light client. Resolves #2632.

Test plan

  • Unit tests test_merkle_tree and test_invalid_block_merkle_root.
  • Manually trigger nightly to see if anything breaks.

@gitpod-io
Copy link

gitpod-io bot commented May 14, 2020

@@ -98,6 +98,41 @@ pub fn verify_path<T: BorshSerialize>(root: MerkleHash, path: &MerklePath, item:
hash == root
}

#[derive(Default, Clone, BorshSerialize, BorshDeserialize)]
pub struct MerkleTree {
Copy link
Collaborator

Choose a reason for hiding this comment

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

PartialMerkleTree?

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

@@ -2969,6 +2969,13 @@ impl<'a> ChainUpdate<'a> {
{
return Err(ErrorKind::InvalidFinalityInfo.into());
}

let mut block_merkle_tree =
self.chain_store_update.get_block_merkle_tree(&header.prev_hash)?.clone();
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like we update merkle tree and then throw it away. Don't we store updated merkle tree somewhere? Should we either use the stored merkle tree to verify the root, or update the stored merkle tree in this code?

Copy link
Collaborator Author

@bowenwang1996 bowenwang1996 May 16, 2020

Choose a reason for hiding this comment

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

We store it when we process the block. We could potentially do an optimization of storing the updated one when we produce the block, but I don't see the need to do that as it might introduce unnecessary bugs.

@@ -143,6 +143,9 @@ pub enum ErrorKind {
/// Invalid VRF proof, or incorrect random_output in the header
#[fail(display = "Invalid Randomness Beacon Output")]
InvalidRandomnessBeaconOutput,
/// Invalid block merkle root.
#[fail(display = "Invalid Block Merkle Root")]
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we elaborate when this error occurs? Does it occur when we already know the merkle tree but then receivd the block header such that the root of the updated merkle tree does not match the one in that we know from the block? Doesn't it imply that we know the block body before its block header? It what cases it is possible?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This happens when the block merkle root contained in header is invalid -- that is, it doesn't match the one calculated from prev header. The only assumption we are making is that when we process a header its prev header is known. If that's the case the merkle tree can be constructed. If the prev header is not known then process header will fail earlier.

fn update_and_save_block_merkle_tree(&mut self, header: &BlockHeader) -> Result<(), Error> {
let prev_hash = header.prev_hash;
if prev_hash == CryptoHash::default() {
self.save_block_merkle_tree(header.hash(), MerkleTree::default());
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it be a merkle tree with one node, instead of tree with no nodes? For consistency reasons.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No. We store the merkle tree up to the current block (exclusive), which means for genesis block, there is nothing to store, so the tree is empty.

@@ -352,8 +352,12 @@ impl Client {
};

// Get block extra from previous block.
let prev_block_extra = self.chain.get_block_extra(&head.last_block_hash)?.clone();
let prev_block = self.chain.get_block(&head.last_block_hash)?;
let mut block_merkle_tree =
Copy link
Contributor

Choose a reason for hiding this comment

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

For the record. We should start thinking of: #2348

@@ -155,6 +156,19 @@ impl Message for GetBlock {
type Result = Result<BlockView, String>;
}

/// Get block with the block merkle tree. Used for testing
pub struct GetBlockWithMerkleTree(pub BlockIdOrFinality);
Copy link
Contributor

Choose a reason for hiding this comment

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

This type seems to exist only to workaround the actix framework. Can we rename it to something like: RequestForBlockWithMerkleTree?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I would prefer it to be consistent with what we already have, i.e, GetBlock.

@@ -98,6 +98,41 @@ pub fn verify_path<T: BorshSerialize>(root: MerkleHash, path: &MerklePath, item:
hash == root
}

#[derive(Default, Clone, BorshSerialize, BorshDeserialize)]
pub struct MerkleTree {
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

@bowenwang1996 bowenwang1996 requested a review from frol as a code owner May 18, 2020 18:41
@bowenwang1996 bowenwang1996 merged commit f734525 into master May 18, 2020
@bowenwang1996 bowenwang1996 deleted the block-merkle-root branch May 18, 2020 20:09
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.

Add merkle tree of the block headers of the epoch into the block header
3 participants