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

Adding is_descendent_of defenitions and fork tree testing with blockqueues #1198

Merged
merged 33 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
baed83b
Adding fork-tree to worker
coax1d Feb 28, 2023
b7a6a37
Rebasing
coax1d Feb 28, 2023
8686ccc
Cargo fmt and clippy
coax1d Feb 28, 2023
4533b6b
taplo fmt
coax1d Feb 28, 2023
111b7c8
adding in default impl for clippy and removing senseless comments
coax1d Mar 1, 2023
07dcd74
minor fmt
coax1d Mar 1, 2023
fdbe2c6
Cherry picking and merging
coax1d Mar 1, 2023
de3d31a
Cherry picking test of is_descendent_builder
coax1d Mar 1, 2023
26daddc
Removing comments and cleanup
coax1d Mar 1, 2023
cfe8a6a
Adding in build_queue_header helper
coax1d Mar 1, 2023
56d63cb
Adding in imports for SidechainBlockBuilderTrait
coax1d Mar 1, 2023
9882418
Cargo fmt taplo fmt and clippy
coax1d Mar 1, 2023
80a1c1e
Adding some documentation to new structures
coax1d Mar 1, 2023
35f055e
cargo fmt
coax1d Mar 1, 2023
e88a6f0
Rebasing
coax1d Mar 1, 2023
473ce64
Addressing comments
coax1d Mar 1, 2023
97128ef
Refactoring for pr
coax1d Mar 1, 2023
01a574c
Fix incorrect comment
coax1d Mar 1, 2023
5d666cd
fixing docstring
coax1d Mar 1, 2023
2e6ab83
rebasing
coax1d Mar 1, 2023
c452dc2
cargo fmt
coax1d Mar 1, 2023
ae8143a
Moving errors to correct file
coax1d Mar 2, 2023
d88d4ea
refactor from comments half
coax1d Mar 6, 2023
8dc3830
Refactoring for Chris comments
coax1d Mar 6, 2023
8620d4e
Merge branch 'master' into adding_is_descendent_of_fork_tree_testing
coax1d Mar 7, 2023
3fddc34
Missing import
coax1d Mar 7, 2023
511b8cf
cargo fmt
coax1d Mar 7, 2023
45afc72
Merge branch 'master' into adding_is_descendent_of_fork_tree_testing
coax1d Mar 7, 2023
3eccee1
Minor fixes for `is_descendant_builder` (#1206)
clangenb Mar 8, 2023
d35d025
Update sidechain/consensus/common/src/is_descendant_of_builder.rs
coax1d Mar 8, 2023
47b57fd
Update sidechain/consensus/common/src/is_descendant_of_builder.rs
coax1d Mar 8, 2023
6202662
Update sidechain/consensus/common/src/is_descendant_of_builder.rs
coax1d Mar 8, 2023
8b6669a
Update sidechain/consensus/common/src/is_descendant_of_builder.rs
coax1d Mar 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions sidechain/consensus/common/src/header_db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
Copyright 2021 Integritee AG and Supercomputing Systems AG

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/
use itp_types::H256;
use its_primitives::{traits::Header as HeaderT, types::header::SidechainHeader};
use std::{collections::HashMap, hash::Hash as HashT};

// Normally implemented on the Client in substrate
pub trait HeaderDbTrait {
type Header: HeaderT;
/// Retrieves Header for the corresponding block hash.
fn header(&self, hash: &H256) -> Option<Self::Header>;
}

/// A mocked Header Database which allows you to take a Block Hash and Query a Block Header.
pub struct HeaderDb<Hash, Header>(pub HashMap<Hash, Header>);
impl<Hash, Header> HeaderDb<Hash, Header>
where
Hash: PartialEq + Eq + HashT + Clone,
Header: Clone,
{
pub fn new() -> Self {
Self(HashMap::new())
}

pub fn insert(&mut self, hash: Hash, header: Header) {
let _ = self.0.insert(hash, header);
}
}

impl<Hash, Header> From<&[(Hash, Header)]> for HeaderDb<Hash, Header>
where
Hash: HashT + Eq + Copy + Clone,
Header: Copy + Clone,
{
fn from(items: &[(Hash, Header)]) -> Self {
let mut header_db = HeaderDb::<Hash, Header>::new();
for item in items {
let (hash, header) = item;
header_db.insert(*hash, *header);
}
header_db
}
}

impl<Hash, Header> HeaderDbTrait for HeaderDb<Hash, Header>
where
Hash: PartialEq + HashT + Into<H256> + From<H256> + std::cmp::Eq + Clone,
Header: HeaderT + Clone + Into<SidechainHeader>,
{
type Header = SidechainHeader;
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove the Into<SidechainHeader> and just use:

type Header = Header

Copy link
Contributor Author

@coax1d coax1d Mar 6, 2023

Choose a reason for hiding this comment

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

This is needed or else you get this

error[E0277]: the trait bound `SidechainHeader: From<Header>` is not satisfied
  --> sidechain/consensus/common/src/header_db.rs:42:8
   |
42 |         Some(header.clone().into())
   |              ^^^^^^^^^^^^^^ ---- required by a bound introduced by this call
   |              |
   |              the trait `From<Header>` is not implemented for `SidechainHeader`
   |
   = note: required for `Header` to implement `Into<SidechainHeader>`
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
   |
36 |     Header: HeaderT + Clone, SidechainHeader: From<Header>
   |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0277`.

Copy link
Contributor

Choose a reason for hiding this comment

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

The thing is that you don't need .into() when Header = SidechainHeader. Or a different question, why do you assume that the Header and Sidechainheader are not effectively the same type?


fn header(&self, hash: &H256) -> Option<Self::Header> {
let header = self.0.get(&Hash::from(*hash))?;
Some(header.clone().into())
}
}
#[derive(Debug)]
pub enum TestError {
Error,
}

impl From<()> for TestError {
fn from(_a: ()) -> Self {
TestError::Error
}
}

impl std::fmt::Display for TestError {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
impl std::fmt::Display for TestError {
impl core::fmt::Display for TestError {

fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "TestError")
}
}

impl std::error::Error for TestError {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
impl std::error::Error for TestError {}
impl core::error::Error for TestError {}

146 changes: 120 additions & 26 deletions sidechain/consensus/common/src/is_descendent_of_builder.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,129 @@
#[cfg(test)]
use std::marker::PhantomData;

#[cfg(test)]
pub struct IsDescendentOfBuilder<Hash>(PhantomData<Hash>);
#[cfg(test)]
impl<'a, Hash: PartialEq> IsDescendentOfBuilder<Hash> {
#[cfg(test)]
/*
Copyright 2021 Integritee AG and Supercomputing Systems AG

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/
use crate::header_db::HeaderDbTrait;
use itp_types::H256;
use its_primitives::traits::Header as HeaderT;
use std::{hash::Hash as HashT, marker::PhantomData};

#[allow(dead_code)]
pub struct IsDescendentOfBuilder<Hash, HeaderDb, Error>(PhantomData<(Hash, HeaderDb, Error)>);
impl<'a, Hash, HeaderDb, Error> IsDescendentOfBuilder<Hash, HeaderDb, Error>
where
Error: From<()>,
Hash: PartialEq + HashT + Default + Into<H256> + From<H256> + Clone,
HeaderDb: HeaderDbTrait,
{
/// Build the `is_descendent_of` closure for the fork-tree structure
/// to utilize when adding and removing nodes from the tree.
#[allow(dead_code)]
pub fn build_is_descendent_of(
_curr_block: Option<(&Hash, &Hash)>,
) -> impl Fn(&Hash, &Hash) -> Result<bool, ()> + 'a {
move |_base, _head| Ok(true)
current: Option<(&'a Hash, &'a Hash)>,
header_db: &'a HeaderDb,
) -> impl Fn(&Hash, &Hash) -> Result<bool, Error> + 'a {
move |base, head| {
if base == head {
return Ok(false)
}

let mut head = head;
if let Some((current_hash, current_parent_hash)) = current {
if current_hash == base {
return Ok(false)
}

if current_hash == head {
if current_parent_hash == base {
return Ok(true)
} else {
head = current_parent_hash;
}
}
}

let ancestor =
<LowestCommonAncestorFinder<Hash, HeaderDb>>::find_lowest_common_ancestor(
head, base, header_db,
)?;
Ok(ancestor == *base)
}
}
}

#[cfg(test)]
pub struct LowestCommonAncestorFinder<Hash>(PhantomData<Hash>);
#[cfg(test)]
impl<Hash: PartialEq + Default> LowestCommonAncestorFinder<Hash> {
#[cfg(test)]
#[allow(dead_code)]
pub struct LowestCommonAncestorFinder<Hash, HeaderDb>(PhantomData<(Hash, HeaderDb)>);
impl<Hash, HeaderDb> LowestCommonAncestorFinder<Hash, HeaderDb>
where
Hash: PartialEq + Default + Into<H256> + From<H256> + Clone,
HeaderDb: HeaderDbTrait,
{
/// Used by the `build_is_descendent_of` to find the LCA of two nodes in the fork-tree.
pub fn find_lowest_common_ancestor(_a: Hash, _b: Hash) -> Hash {
Default::default()
}
}
#[allow(dead_code)]
fn find_lowest_common_ancestor(a: &Hash, b: &Hash, header_db: &HeaderDb) -> Result<Hash, ()> {
let header_1 = header_db.header(&a.clone().into()).ok_or(())?;
let header_2 = header_db.header(&b.clone().into()).ok_or(())?;
let mut blocknum_1 = header_1.block_number();
let mut blocknum_2 = header_2.block_number();
let mut parent_1 = Hash::from(header_1.parent_hash());
let mut parent_2 = Hash::from(header_2.parent_hash());

if *a == parent_2 {
// Then a is the common ancestor of b and it means it is itself the ancestor
return Ok(parent_2)
}

if *b == parent_1 {
// Then b is the common ancestor of a and it means it is itself the ancestor
return Ok(parent_1)
}

while blocknum_1 > blocknum_2 {
// This means block 1 is further down in the tree than block 2
let new_parent = header_db.header(&parent_1.clone().into()).ok_or(())?;

if new_parent.block_number() >= blocknum_2 {
blocknum_1 = new_parent.block_number();
parent_1 = Hash::from(new_parent.parent_hash());
} else {
break
}
}

#[cfg(test)]
#[test]
fn test_build_is_descendent_of_works() {
let is_descendent_of = <IsDescendentOfBuilder<u64>>::build_is_descendent_of(None);
let my_result = is_descendent_of(&42u64, &42u64);
assert_eq!(my_result, Ok(true));
while blocknum_2 > blocknum_1 {
// This means block 2 is further down in the tree than block 1
let new_parent = header_db.header(&parent_2.clone().into()).ok_or(())?;

if new_parent.block_number() >= blocknum_1 {
blocknum_2 = new_parent.block_number();
parent_2 = Hash::from(new_parent.parent_hash());
} else {
break
}
}

// At this point will be at equal height
while parent_1 != parent_2 {
// go up on both nodes
let new_header_1 = header_db.header(&parent_1.into()).ok_or(())?;
let new_header_2 = header_db.header(&parent_2.into()).ok_or(())?;
parent_1 = Hash::from(new_header_1.parent_hash());
parent_2 = Hash::from(new_header_2.parent_hash());
}

// Return any Parent node Hash as in worst case scenario it is the root which is shared amongst all
Ok(parent_1)
}
}
1 change: 1 addition & 0 deletions sidechain/consensus/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod block_import;
mod block_import_confirmation_handler;
mod block_import_queue_worker;
mod error;
mod header_db;
mod is_descendent_of_builder;
mod peer_block_sync;

Expand Down
Loading