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

[DRAFT] Require locking agreement to ChangeView and allowing committed nodes to move to higher views #653

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3f56ceb
Restore Liveness: Prevent Commit after ChangeView. Require locking ag…
jsolman Mar 24, 2019
7b36d00
Merge branch 'master' into consensus/liveness
shargon Mar 24, 2019
4edf61f
To prevent duplicate blocks, since we allow commits to move, we canno…
jsolman Mar 24, 2019
6099547
Fix log message.
jsolman Mar 24, 2019
01be5aa
Add additional criteria for sending recovery since we must recover no…
jsolman Mar 24, 2019
d4d233a
Merge branch 'master' into consensus/liveness
jsolman Mar 24, 2019
87d61cb
Fix logic for inhibiting locking commit.
jsolman Mar 24, 2019
f795cf8
Primary should always help recover nodes missing prepare response.
jsolman Mar 24, 2019
51fbbf7
Need to be able to recover commit in the same view.
jsolman Mar 24, 2019
770ca57
Fix bug in sending recovery logic.
jsolman Mar 24, 2019
00a5e0a
Fix recovery response logic.
jsolman Mar 24, 2019
b4ded67
Adjust logic for inhibiting view changing since now locking view chan…
jsolman Mar 24, 2019
900baac
Simplify.
jsolman Mar 24, 2019
9b59e5c
Make all respond for now for shouldRecoverPrepareResponseInSameView.
jsolman Mar 24, 2019
da33693
Minor naming refactor.
jsolman Mar 24, 2019
e54638c
Move logic for whether to send recovery from OnChangeView into a meth…
jsolman Mar 24, 2019
38f1550
Clean-up.
jsolman Mar 24, 2019
42a5832
Added needed special logic to handle recovering while the view is cha…
jsolman Mar 25, 2019
e7e67d5
Fix threshold for valid preparations and sending prepare response fro…
jsolman Mar 25, 2019
0c194e9
Fix calculating valid preparations during recovery while changing view.
jsolman Mar 25, 2019
f75e037
Primary doesn't send requests to change view.
jsolman Mar 25, 2019
23586db
Adding some comments and notes
vncoelho Mar 25, 2019
67d53f0
Updating notes
vncoelho Mar 25, 2019
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
16 changes: 13 additions & 3 deletions neo/Consensus/ChangeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ public class ChangeView : ConsensusMessage
public byte NewViewNumber;
/// <summary>
/// Timestamp of when the ChangeView message was created. This allows receiving nodes to ensure
// they only respond once to a specific ChangeView request (it thus prevents replay of the ChangeView
// message from repeatedly broadcasting RecoveryMessages).
/// they only respond once to a specific ChangeView request (it thus prevents replay of the ChangeView
/// message from repeatedly broadcasting RecoveryMessages).
/// </summary>
public uint Timestamp;
/// <summary>
/// Flag whether the node is locked/committed to change view from it's current view.
/// If not set, this indicates this is a request to change view, but not a commitment, and therefore it may
/// still accept further preparations and commit to generate a block in the current view.
/// If set, this node is locked to change view, and will not accept further preparations in the current view.
/// </summary>
public bool Locked;

public override int Size => base.Size
+ sizeof(byte) //NewViewNumber
+ sizeof(uint); //Timestamp
+ sizeof(uint) //Timestamp
+ sizeof(bool); //Committed

public ChangeView()
: base(ConsensusMessageType.ChangeView)
Expand All @@ -26,13 +34,15 @@ public override void Deserialize(BinaryReader reader)
base.Deserialize(reader);
NewViewNumber = reader.ReadByte();
Timestamp = reader.ReadUInt32();
Locked = reader.ReadBoolean();
}

public override void Serialize(BinaryWriter writer)
{
base.Serialize(writer);
writer.Write(NewViewNumber);
writer.Write(Timestamp);
writer.Write(Locked);
}
}
}
23 changes: 15 additions & 8 deletions neo/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,23 @@ public bool Load()

public ConsensusPayload MakeChangeView(byte newViewNumber)
{
var changeViewLockedCount = ChangeViewPayloads.Count(p => p != null && p.GetDeserializedMessage<ChangeView>().NewViewNumber > ViewNumber);
if (ChangeViewPayloads[MyIndex]?.GetDeserializedMessage<ChangeView>().NewViewNumber <= ViewNumber && newViewNumber > ViewNumber)
changeViewLockedCount++;
return ChangeViewPayloads[MyIndex] = MakeSignedPayload(new ChangeView
{
NewViewNumber = newViewNumber,
Timestamp = TimeProvider.Current.UtcNow.ToTimestamp()
Timestamp = TimeProvider.Current.UtcNow.ToTimestamp(),
Locked = changeViewLockedCount >= this.M() && !(this.ResponseSent() || this.IsPrimary())
});
}

public ConsensusPayload MakeCommit()
{
if (CommitPayloads[MyIndex] == null)
CommitPayloads[MyIndex] = MakeSignedPayload(new Commit
{
Signature = MakeHeader()?.Sign(keyPair)
});
return CommitPayloads[MyIndex];
return CommitPayloads[MyIndex] ?? (CommitPayloads[MyIndex] = MakeSignedPayload(new Commit
{
Signature = MakeHeader()?.Sign(keyPair)
}));
}

private Block _header = null;
Expand Down Expand Up @@ -235,6 +237,7 @@ public ConsensusPayload MakeRecoveryMessage()
}
return MakeSignedPayload(new RecoveryMessage()
{
Timestamp = TimeProvider.Current.UtcNow.ToTimestamp(),
ChangeViewMessages = LastChangeViewPayloads.Where(p => p != null).Select(p => RecoveryMessage.ChangeViewPayloadCompact.FromPayload(p)).Take(this.M()).ToDictionary(p => (int)p.ValidatorIndex),
PrepareRequestMessage = prepareRequestMessage,
// We only need a PreparationHash set if we don't have the PrepareRequest information.
Expand Down Expand Up @@ -280,10 +283,14 @@ public void Reset(byte viewNumber)
else
{
for (int i = 0; i < LastChangeViewPayloads.Length; i++)
if (ChangeViewPayloads[i]?.GetDeserializedMessage<ChangeView>().NewViewNumber == viewNumber)
{
var changeViewMessage = ChangeViewPayloads[i]?.GetDeserializedMessage<ChangeView>();
if (changeViewMessage?.NewViewNumber == viewNumber && changeViewMessage.Locked)
LastChangeViewPayloads[i] = ChangeViewPayloads[i];
else
LastChangeViewPayloads[i] = null;
}

}
ViewNumber = viewNumber;
PrimaryIndex = this.GetPrimaryIndex(viewNumber);
Expand Down
Loading