shardtree: `Nil` nodes cannot replace any other sort of node in the tree.
This commit is contained in:
parent
811d384bd4
commit
57b6e8999f
|
@ -547,111 +547,116 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
|
||||||
is_complete: bool,
|
is_complete: bool,
|
||||||
contains_marked: bool,
|
contains_marked: bool,
|
||||||
) -> Result<(PrunableTree<H>, Vec<IncompleteAt>), InsertionError> {
|
) -> Result<(PrunableTree<H>, Vec<IncompleteAt>), InsertionError> {
|
||||||
// In the case that we are replacing a node entirely, we need to extend the
|
|
||||||
// subtree up to the level of the node being replaced, adding Nil siblings
|
|
||||||
// and recording the presence of those incomplete nodes when necessary
|
|
||||||
let replacement = |ann: Option<Arc<H>>, mut node: LocatedPrunableTree<H>| {
|
|
||||||
// construct the replacement node bottom-up
|
|
||||||
let mut incomplete = vec![];
|
|
||||||
while node.root_addr.level() < root_addr.level() {
|
|
||||||
incomplete.push(IncompleteAt {
|
|
||||||
address: node.root_addr.sibling(),
|
|
||||||
required_for_witness: contains_marked,
|
|
||||||
});
|
|
||||||
node = LocatedTree {
|
|
||||||
root_addr: node.root_addr.parent(),
|
|
||||||
root: if node.root_addr.is_right_child() {
|
|
||||||
Tree(Node::Parent {
|
|
||||||
ann: None,
|
|
||||||
left: Arc::new(Tree(Node::Nil)),
|
|
||||||
right: Arc::new(node.root),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Tree(Node::Parent {
|
|
||||||
ann: None,
|
|
||||||
left: Arc::new(node.root),
|
|
||||||
right: Arc::new(Tree(Node::Nil)),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(node.root.reannotate_root(ann), incomplete)
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
root_addr = ?root_addr,
|
root_addr = ?root_addr,
|
||||||
max_position = ?LocatedTree::max_position_internal(root_addr, into),
|
max_position = ?LocatedTree::max_position_internal(root_addr, into),
|
||||||
to_insert = ?subtree.root_addr(),
|
to_insert = ?subtree.root_addr(),
|
||||||
"Subtree insert"
|
"Subtree insert"
|
||||||
);
|
);
|
||||||
match into {
|
// An empty tree cannot replace any other type of tree.
|
||||||
Tree(Node::Nil) => Ok(replacement(None, subtree)),
|
if subtree.root().is_nil() {
|
||||||
Tree(Node::Leaf { value: (value, _) }) => {
|
Ok((into.clone(), vec![]))
|
||||||
if root_addr == subtree.root_addr {
|
} else {
|
||||||
if is_complete {
|
// In the case that we are replacing a node entirely, we need to extend the
|
||||||
// It is safe to replace the existing root unannotated, because we
|
// subtree up to the level of the node being replaced, adding Nil siblings
|
||||||
// can always recompute the root from a complete subtree.
|
// and recording the presence of those incomplete nodes when necessary
|
||||||
Ok((subtree.root, vec![]))
|
let replacement = |ann: Option<Arc<H>>, mut node: LocatedPrunableTree<H>| {
|
||||||
} else if subtree.root.node_value().iter().all(|v| v == &value) {
|
// construct the replacement node bottom-up
|
||||||
|
let mut incomplete = vec![];
|
||||||
|
while node.root_addr.level() < root_addr.level() {
|
||||||
|
incomplete.push(IncompleteAt {
|
||||||
|
address: node.root_addr.sibling(),
|
||||||
|
required_for_witness: contains_marked,
|
||||||
|
});
|
||||||
|
node = LocatedTree {
|
||||||
|
root_addr: node.root_addr.parent(),
|
||||||
|
root: if node.root_addr.is_right_child() {
|
||||||
|
Tree(Node::Parent {
|
||||||
|
ann: None,
|
||||||
|
left: Arc::new(Tree(Node::Nil)),
|
||||||
|
right: Arc::new(node.root),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Tree(Node::Parent {
|
||||||
|
ann: None,
|
||||||
|
left: Arc::new(node.root),
|
||||||
|
right: Arc::new(Tree(Node::Nil)),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(node.root.reannotate_root(ann), incomplete)
|
||||||
|
};
|
||||||
|
|
||||||
|
match into {
|
||||||
|
Tree(Node::Nil) => Ok(replacement(None, subtree)),
|
||||||
|
Tree(Node::Leaf { value: (value, _) }) => {
|
||||||
|
if root_addr == subtree.root_addr {
|
||||||
|
if is_complete {
|
||||||
|
// It is safe to replace the existing root unannotated, because we
|
||||||
|
// can always recompute the root from a complete subtree.
|
||||||
|
Ok((subtree.root, vec![]))
|
||||||
|
} else if subtree.root.node_value().iter().all(|v| v == &value) {
|
||||||
|
Ok((
|
||||||
|
// at this point we statically know the root to be a parent
|
||||||
|
subtree.root.reannotate_root(Some(Arc::new(value.clone()))),
|
||||||
|
vec![],
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
cur_root = ?value,
|
||||||
|
new_root = ?subtree.root.node_value(),
|
||||||
|
"Insertion conflict",
|
||||||
|
);
|
||||||
|
Err(InsertionError::Conflict(root_addr))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(replacement(Some(Arc::new(value.clone())), subtree))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent if root_addr == subtree.root_addr => {
|
||||||
|
// Merge the existing subtree with the subtree being inserted.
|
||||||
|
// A merge operation can't introduce any new incomplete roots.
|
||||||
|
parent
|
||||||
|
.clone()
|
||||||
|
.merge_checked(root_addr, subtree.root)
|
||||||
|
.map_err(InsertionError::Conflict)
|
||||||
|
.map(|tree| (tree, vec![]))
|
||||||
|
}
|
||||||
|
Tree(Node::Parent { ann, left, right }) => {
|
||||||
|
// In this case, we have an existing parent but we need to dig down farther
|
||||||
|
// before we can insert the subtree that we're carrying for insertion.
|
||||||
|
let (l_addr, r_addr) = root_addr.children().unwrap();
|
||||||
|
if l_addr.contains(&subtree.root_addr) {
|
||||||
|
let (new_left, incomplete) =
|
||||||
|
go(l_addr, left.as_ref(), subtree, is_complete, contains_marked)?;
|
||||||
Ok((
|
Ok((
|
||||||
// at this point we statically know the root to be a parent
|
Tree::unite(
|
||||||
subtree.root.reannotate_root(Some(Arc::new(value.clone()))),
|
root_addr.level() - 1,
|
||||||
vec![],
|
ann.clone(),
|
||||||
|
new_left,
|
||||||
|
right.as_ref().clone(),
|
||||||
|
),
|
||||||
|
incomplete,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
trace!(
|
let (new_right, incomplete) = go(
|
||||||
cur_root = ?value,
|
r_addr,
|
||||||
new_root = ?subtree.root.node_value(),
|
right.as_ref(),
|
||||||
"Insertion conflict",
|
subtree,
|
||||||
);
|
is_complete,
|
||||||
Err(InsertionError::Conflict(root_addr))
|
contains_marked,
|
||||||
|
)?;
|
||||||
|
Ok((
|
||||||
|
Tree::unite(
|
||||||
|
root_addr.level() - 1,
|
||||||
|
ann.clone(),
|
||||||
|
left.as_ref().clone(),
|
||||||
|
new_right,
|
||||||
|
),
|
||||||
|
incomplete,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Ok(replacement(Some(Arc::new(value.clone())), subtree))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parent if root_addr == subtree.root_addr => {
|
|
||||||
// Merge the existing subtree with the subtree being inserted.
|
|
||||||
// A merge operation can't introduce any new incomplete roots.
|
|
||||||
parent
|
|
||||||
.clone()
|
|
||||||
.merge_checked(root_addr, subtree.root)
|
|
||||||
.map_err(InsertionError::Conflict)
|
|
||||||
.map(|tree| (tree, vec![]))
|
|
||||||
}
|
|
||||||
Tree(Node::Parent { ann, left, right }) => {
|
|
||||||
// In this case, we have an existing parent but we need to dig down farther
|
|
||||||
// before we can insert the subtree that we're carrying for insertion.
|
|
||||||
let (l_addr, r_addr) = root_addr.children().unwrap();
|
|
||||||
if l_addr.contains(&subtree.root_addr) {
|
|
||||||
let (new_left, incomplete) =
|
|
||||||
go(l_addr, left.as_ref(), subtree, is_complete, contains_marked)?;
|
|
||||||
Ok((
|
|
||||||
Tree::unite(
|
|
||||||
root_addr.level() - 1,
|
|
||||||
ann.clone(),
|
|
||||||
new_left,
|
|
||||||
right.as_ref().clone(),
|
|
||||||
),
|
|
||||||
incomplete,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
let (new_right, incomplete) = go(
|
|
||||||
r_addr,
|
|
||||||
right.as_ref(),
|
|
||||||
subtree,
|
|
||||||
is_complete,
|
|
||||||
contains_marked,
|
|
||||||
)?;
|
|
||||||
Ok((
|
|
||||||
Tree::unite(
|
|
||||||
root_addr.level() - 1,
|
|
||||||
ann.clone(),
|
|
||||||
left.as_ref().clone(),
|
|
||||||
new_right,
|
|
||||||
),
|
|
||||||
incomplete,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue