Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Patch concurrent update error #458

Open
wants to merge 5 commits into
base: fallback
Choose a base branch
from

Conversation

cryptoAtwill
Copy link
Contributor

@cryptoAtwill cryptoAtwill commented Dec 7, 2023

This fixes a concurrent update error. It is possible that a validator is catching up and received a finality from peer that is higher than the value stored in cache during polling. In this case, there is no need to update cache. Adding a test case for it.

@@ -63,6 +63,17 @@ impl FinalityWithNull {
/// Clear the cache and set the committed finality to the provided value
pub fn reset(&self, finality: IPCParentFinality) -> Stm<()> {
self.cached_data.write(SequentialKeyCache::sequential())?;

if let Some(p) = self.last_committed_finality.read_clone()? {
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 .read()? should suffice here.

@@ -71,6 +82,17 @@ impl FinalityWithNull {
height: BlockHeight,
maybe_payload: Option<ParentViewPayload>,
) -> StmResult<(), Error> {
if let Some(p) = self.last_committed_finality.read_clone()? {
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
if let Some(p) = self.last_committed_finality.read_clone()? {
if let Some(p) = self.last_committed_finality.read()? {

Here too, the value isn't returned, so you can access it through the Arc

Copy link
Contributor

@aakoshh aakoshh left a comment

Choose a reason for hiding this comment

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

I didn't try to understand the tests but the logic that we don't have to add entries which have already been finalized in a different way make sense to me.

@aakoshh
Copy link
Contributor

aakoshh commented Dec 7, 2023

I would like to add that this would be a good candidate for state machine testing (fuzzing) or even just quickcheck.

You can generate an idealised block tree and then simulate multiple cursors on it, one representing your own parent, perhaps doing even reorgs, and the other representing quorums coming from your peers, either in or outside the range that you have in the cache.

If you can drive the sync outside the timers, then you can have events such as:

  • do a round of sync
  • vote on a random proposal
  • produce a proposal of your own and vote on it
  • move the parent cursor forward
  • move the parent cursor back then forward on another branch
  • move the quorum cursor forward
  • apply a block from the quorum
  • ...

And then it would bring out these random errors that you seem to be discovering live, such as the quorum cursor being further ahead than the parent cursor. You could assert whatever you like based on your overall view of the world, such as you don't propose a block which is earlier than the last finalized, you don't have entries in your cache which are older, etc.

@cryptoAtwill
Copy link
Contributor Author

@aakoshh The state machine testing is pretty cool, I will give it a try.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants