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

optimize LastSeenMessage #1834

Merged
merged 9 commits into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
22 changes: 17 additions & 5 deletions src/neo/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal class ConsensusContext : IDisposable, ISerializable
public ConsensusPayload[] LastChangeViewPayloads;
// LastSeenMessage array stores the height of the last seen message, for each validator.
// if this node never heard from validator i, LastSeenMessage[i] will be -1.
public int[] LastSeenMessage;
public Dictionary<ECPoint, int> LastSeenMessage { get; set; }

/// <summary>
/// Store all verified unsorted transactions' senders' fee currently in the consensus context.
Expand All @@ -55,7 +55,7 @@ internal class ConsensusContext : IDisposable, ISerializable
public bool WatchOnly => MyIndex < 0;
public Header PrevHeader => Snapshot.GetHeader(Block.PrevHash);
public int CountCommitted => CommitPayloads.Count(p => p != null);
public int CountFailed => LastSeenMessage.Count(p => p < (((int)Block.Index) - 1));
public int CountFailed => LastSeenMessage.Count(p => p.Value < (((int)Block.Index) - 1));

#region Consensus States
public bool RequestSentOrReceived => PreparationPayloads[Block.ConsensusData.PrimaryIndex] != null;
Expand Down Expand Up @@ -386,9 +386,21 @@ public void Reset(byte viewNumber)
CommitPayloads = new ConsensusPayload[Validators.Length];
if (LastSeenMessage == null)
{
LastSeenMessage = new int[Validators.Length];
LastSeenMessage = new Dictionary<ECPoint, int>();
for (int i = 0; i < Validators.Length; i++)
LastSeenMessage[i] = -1;
LastSeenMessage[Validators[i]] = -1;
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
}
if (0 < Snapshot.Height && Blockchain.Singleton.GetBlock(Snapshot.Height - 1).NextConsensus != Blockchain.Singleton.GetBlock(Snapshot.Height).NextConsensus)
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
{
var previous_last_seen_message = LastSeenMessage;
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
LastSeenMessage = new Dictionary<ECPoint, int>();
foreach (var validator in Validators)
{
if (previous_last_seen_message.TryGetValue(validator, out int value))
LastSeenMessage[validator] = value;
else
LastSeenMessage[validator] = -1;
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
}
}
keyPair = null;
for (int i = 0; i < Validators.Length; i++)
Expand Down Expand Up @@ -418,7 +430,7 @@ public void Reset(byte viewNumber)
Block.Transactions = null;
TransactionHashes = null;
PreparationPayloads = new ConsensusPayload[Validators.Length];
if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index;
if (MyIndex >= 0) LastSeenMessage[Validators[MyIndex]] = (int)Block.Index;
}

public void Save()
Expand Down
2 changes: 1 addition & 1 deletion src/neo/Consensus/ConsensusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private void OnConsensusPayload(ConsensusPayload payload)
{
return;
}
context.LastSeenMessage[payload.ValidatorIndex] = (int)payload.BlockIndex;
context.LastSeenMessage[context.Validators[payload.ValidatorIndex]] = (int)payload.BlockIndex;
foreach (IP2PPlugin plugin in Plugin.P2PPlugins)
if (!plugin.OnConsensusMessage(payload))
return;
Expand Down
30 changes: 24 additions & 6 deletions tests/neo.UnitTests/Consensus/UT_Consensus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
Console.WriteLine($"\n(UT-Consensus) Wallet is: {mockWallet.Object.GetAccount(UInt160.Zero).GetKey().PublicKey}");

var mockContext = new Mock<ConsensusContext>(mockWallet.Object, Blockchain.Singleton.Store);
mockContext.Object.LastSeenMessage = new int[] { 0, 0, 0, 0, 0, 0, 0 };
mockContext.Object.LastSeenMessage = new Dictionary<ECPoint, int>();

KeyPair[] kp_array = new KeyPair[7]
{
Expand Down Expand Up @@ -136,6 +136,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
// As we may expect, as soon as consensus start it sends a RecoveryRequest of this aforementioned type
var askingForInitialRecovery = subscriber.ExpectMsg<LocalNode.SendDirectly>();
Console.WriteLine($"Recovery Message I: {askingForInitialRecovery}");
foreach (var validator in mockContext.Object.Validators)
{
mockContext.Object.LastSeenMessage[validator] = 0;
}
// Ensuring cast of type ConsensusPayload from the received message from subscriber
ConsensusPayload initialRecoveryPayload = (ConsensusPayload)askingForInitialRecovery.Inventory;
// Ensuring casting of type RecoveryRequest
Expand Down Expand Up @@ -166,7 +170,11 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
mockContext.Object.ChangeViewPayloads[mockContext.Object.MyIndex] = null;
Console.WriteLine("Forcing Failed nodes for recovery request... ");
mockContext.Object.CountFailed.Should().Be(0);
mockContext.Object.LastSeenMessage = new int[] { -1, -1, -1, -1, -1, -1, -1 };
mockContext.Object.LastSeenMessage = new Dictionary<ECPoint, int>();
foreach (var validator in mockContext.Object.Validators)
{
mockContext.Object.LastSeenMessage[validator] = -1;
}
mockContext.Object.CountFailed.Should().Be(7);
Console.WriteLine("\nWaiting for recovery due to failed nodes... ");
var backupOnRecoveryDueToFailedNodes = subscriber.ExpectMsg<LocalNode.SendDirectly>();
Expand Down Expand Up @@ -266,6 +274,12 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
kp_array[6].PublicKey
};
Console.WriteLine($"Generated keypairs PKey:");
//refresh LastSeenMessage
mockContext.Object.LastSeenMessage = new Dictionary<ECPoint, int>();
foreach (var item in mockContext.Object.Validators)
{
mockContext.Object.LastSeenMessage[item] = -1;
}
for (int i = 0; i < mockContext.Object.Validators.Length; i++)
Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}");
var updatedContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators);
Expand Down Expand Up @@ -308,7 +322,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
Console.WriteLine("\nAsserting CountCommitted is 2...");
mockContext.Object.CountCommitted.Should().Be(2);
Console.WriteLine($"\nAsserting CountFailed is 1...");
mockContext.Object.CountFailed.Should().Be(1);
mockContext.Object.CountFailed.Should().Be(6);

Console.WriteLine("\nCN6 simulation time");
TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData));
Expand All @@ -318,7 +332,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
Console.WriteLine("\nAsserting CountCommitted is 3...");
mockContext.Object.CountCommitted.Should().Be(3);
Console.WriteLine($"\nAsserting CountFailed is 0...");
mockContext.Object.CountFailed.Should().Be(0);
mockContext.Object.CountFailed.Should().Be(5);

Console.WriteLine("\nCN5 simulation time");
TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData));
Expand Down Expand Up @@ -381,10 +395,14 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm
Console.WriteLine("\nAsserting CountCommitted is 0...");
mockContext.Object.CountCommitted.Should().Be(0);
Console.WriteLine($"\nAsserting CountFailed is 0...");
mockContext.Object.CountFailed.Should().Be(0);
mockContext.Object.CountFailed.Should().Be(3);
Console.WriteLine($"\nModifying CountFailed and asserting 7...");
// This will ensure a non-deterministic behavior after last recovery
mockContext.Object.LastSeenMessage = new int[] { -1, -1, -1, -1, -1, -1, -1 };
mockContext.Object.LastSeenMessage = new Dictionary<ECPoint, int>();
foreach (var validator in mockContext.Object.Validators)
{
mockContext.Object.LastSeenMessage[validator] = -1;
}
mockContext.Object.CountFailed.Should().Be(7);

TellConsensusPayload(actorConsensus, rmPayload);
Expand Down