stateright / stateright

A model checker for implementing distributed systems.

Home Page:https://docs.rs/stateright

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug in the explorer

LiangrunDa opened this issue · comments

I integrated stateright to my Raft implementation and I was trying to explore state space using Web UI. I got a bug with the explorer and you can easily reproduce it in the following steps:

  1. Clone my Raft project with https://github.com/LiangrunDa/raft-lite.git and run cargo run -- -m explore -n unordered-duplicating to start the explorer (It is bug free with unordered-nonduplicating network)

  2. Start with http://localhost:3000/#/steps/17615423386414597689/8809746236804019274/1839872530274288054/12494312633948216985/16316435326953127737/

image

  1. click the next action "Id(2) → VoteResponse(VoteResponseArgs { voter_id: 2, term: 1, granted: true }) → Id(0)".

  2. The "Path of Actions" will show that the last action is "Id(0) → VoteRequest(VoteRequestArgs { cid: 0, cterm: 1, clog_length: 0, clog_term: 0 }) → Id(2)", which is not the action taken in step 3.

image

I found that it is caused by the following code in ui/app.js line 253 :

step = nextSteps.find(step => step.fingerprint == nextFingerprint);

The array nextSteps contains steps that might be taken next. However, the fingerprint associated with each step may not be unique. Consequently, the find function will simply return the first step encountered with a matching fingerprint.

This lack of uniqueness arises from certain actions not changing the state of the actor and the unordered-duplicate network also remains unchanged. By "unchanged," it is meant that the envelope in the unordered-duplicate network is not consumed.

It is very common to have such action that doesn't change the actor state in a distributed system. For example, in the Raft algorithm, the action VoteResponse does not change the actor state if the recipient is already a leader of the term.

In above case, in step3, we take Id(2) → VoteResponse(VoteResponseArgs { voter_id: 2, term: 1, granted: true }) → Id(0), since Id(0) is already a leader, the fingerprint of this step will be same as the previous one.

Since duplicate delivery of Id(0) → VoteRequest(VoteRequestArgs { cid: 0, cterm: 1, clog_length: 0, clog_term: 0 }) → Id(2) will also not change the actor state, the fingerprint should be the same as the previous one as well.

Consequently, the Web UI encounters two subsequent actions with identical fingerprints, and it simply selects the first one Id(0) → VoteRequest(VoteRequestArgs { cid: 0, cterm: 1, clog_length: 0, clog_term: 0 }) → Id(2) as the action taken in step 3.

Would it be possible to add some additional information to the network state to make the fingerprint unique? That is, we need to let the system "remember" an action that is taken by the user but does not change the actor state.

Thank for identifying this and for the detailed repro details @LiangrunDa!