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

Cache up-to-date consensus payloads #949

Closed
wants to merge 104 commits into from
Closed
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
1514b0f
First draft for speeding up consensus with future payloads
vncoelho Jul 23, 2019
4b4b470
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jul 26, 2019
1cb33c9
Function for checking if future payloads exists
vncoelho Jul 26, 2019
9bca60e
Merge branch 'speed-up-consensus-with-future-payloads' of github.com:…
vncoelho Jul 26, 2019
d62a6ec
Finishing all design of the PR with reload of Consensus Payloads
vncoelho Jul 26, 2019
9429021
Fixing mixing context, literally
vncoelho Jul 26, 2019
bfa39ff
Just try to load payload if it is from the current height
vncoelho Jul 28, 2019
8d33283
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jul 30, 2019
de8ce2f
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jul 30, 2019
99fd182
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jul 31, 2019
c23d77e
Serialize and deserialize future payloads
vncoelho Aug 1, 2019
8191c95
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Aug 8, 2019
8411857
Limit future payloads that will be saved
vncoelho Aug 8, 2019
886cc54
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Aug 19, 2019
7e1b0ce
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Aug 24, 2019
ede5157
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Aug 25, 2019
96fa9be
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Aug 30, 2019
ab66252
dotnet format
vncoelho Aug 30, 2019
e5c2967
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Sep 24, 2019
944f7f6
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Oct 5, 2019
8a3a1b4
dotnet format
vncoelho Oct 5, 2019
351d7ad
Avoid trying to save payload that is being loaded
vncoelho Oct 5, 2019
740f258
Simplyfing and improving load
vncoelho Oct 5, 2019
3d8db39
Arrange serialization as original
vncoelho Oct 5, 2019
538e4f4
Cleaning comment
vncoelho Oct 5, 2019
3cc75ce
Adding true to Reset on Context
vncoelho Oct 5, 2019
0d9c071
Optional parameter for Reset
vncoelho Oct 5, 2019
335c36c
Adding initialization on UT for serialization
vncoelho Oct 5, 2019
599f712
Adding extra tests for S&D comparison
vncoelho Oct 5, 2019
3463930
Increasing UT timespam for expectmsg
vncoelho Oct 5, 2019
0140884
Testing timespam
vncoelho Oct 5, 2019
6ce8d0a
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Oct 15, 2019
a72ef2c
Removing extra time for actor UT
vncoelho Oct 15, 2019
6bf0036
Move conditions
shargon Oct 16, 2019
6045d67
Update neo/Consensus/ConsensusService.cs
shargon Oct 16, 2019
6762070
Update neo/Consensus/ConsensusService.cs
shargon Oct 16, 2019
b2cec4f
Update null check
shargon Oct 16, 2019
395b5ac
Update null check
shargon Oct 16, 2019
d45e158
Update ConsensusService.cs
shargon Oct 16, 2019
361c09c
Merge branch 'master' into speed-up-consensus-with-future-payloads
shargon Oct 16, 2019
f53654a
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Oct 16, 2019
48144b3
Shargon renamming to TryToConsumeFuturePayload
vncoelho Oct 16, 2019
dadfe00
Consume payloads from lower heights
vncoelho Oct 16, 2019
337405f
Renamming to avoid saving and doing so when recovering
vncoelho Oct 16, 2019
8e7af2b
Adding logic for avoiding saving payloads from lower heights
vncoelho Oct 16, 2019
0c1b8f8
Simplifying save payload into a function that sets to the array in re…
vncoelho Oct 17, 2019
9124e51
Adding missing variable
vncoelho Oct 17, 2019
770da66
Finally fixing access to null arrays!
vncoelho Oct 17, 2019
a219962
Adding random hashes for OnGetDataMessageReceived
vncoelho Oct 18, 2019
9efa148
Adding static readonly Random
vncoelho Oct 18, 2019
0a440a8
Merge branch 'master' into speed-up-consensus-with-future-payloads
shargon Oct 18, 2019
e36f787
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Oct 28, 2019
952bc63
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Oct 30, 2019
fb27884
Merge branch 'master' into speed-up-consensus-with-future-payloads
lock9 Nov 6, 2019
34cd904
Merge branch 'master' of github.com:neo-project/neo
vncoelho Nov 6, 2019
ddb8699
Merge branch 'master' of github.com:neo-project/neo
vncoelho Nov 24, 2019
5f95da8
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Nov 24, 2019
059bd55
Merge branch 'master' into speed-up-consensus-with-future-payloads
lock9 Nov 25, 2019
ab16d60
Merge branch 'master' of github.com:neo-project/neo
vncoelho Nov 25, 2019
0fbad23
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Nov 25, 2019
167802c
Lowercase fix
vncoelho Nov 25, 2019
b1d8883
Improving double if check
vncoelho Nov 25, 2019
eb7efd9
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Nov 25, 2019
49ae60a
Dotnet format
vncoelho Nov 25, 2019
0cac323
Removing wrong file on ProtocolHandler
vncoelho Nov 25, 2019
1939acc
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Nov 28, 2019
b70c53d
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Nov 29, 2019
05feece
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 3, 2019
5b64c28
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 6, 2019
a27c6d5
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 7, 2019
797fa75
@shargon tip for counter on HasFuturePayload
vncoelho Dec 7, 2019
76ba19a
Updating index when consumed
vncoelho Dec 7, 2019
c46eb64
Security reverify following @vang1ong7ang tip
vncoelho Dec 7, 2019
910b5c7
Improving consume of FuturePayload. Exiting if no more available
vncoelho Dec 7, 2019
2a507d5
Adding coverage to TryToConsume
vncoelho Dec 7, 2019
fe73960
Improving coverage by effectivelly calling with a payload from higher…
vncoelho Dec 7, 2019
4081252
Simplyfing logic when trying to save for same height and higher views
vncoelho Dec 7, 2019
add00be
Renaming Counter to Count
vncoelho Dec 7, 2019
c212a3c
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 7, 2019
c01cfa6
Erik's fix on count and minor precaution after Validator length change
vncoelho Dec 9, 2019
effb648
Dotnet format and reducing further to save to 3
vncoelho Dec 9, 2019
2ccc469
Simplify avoidSaving
vncoelho Dec 9, 2019
03b2f10
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 9, 2019
b8c4a9d
Invert consuming order
vncoelho Dec 9, 2019
d92afe8
Merge branch 'speed-up-consensus-with-future-payloads' of github.com:…
vncoelho Dec 9, 2019
e37f8fb
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 10, 2019
5907293
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 10, 2019
644f6b2
Removing FuturePayloads from Serialize/Deserialize used when Loading …
vncoelho Dec 10, 2019
cb1d3f3
Avoiding unnecessary diffs on file
vncoelho Dec 10, 2019
8e75cab
Merge branch 'master' into speed-up-consensus-with-future-payloads
shargon Dec 18, 2019
71b044b
Fix casting and type on TryToSavePayloadIntoArray
vncoelho Dec 18, 2019
c34d581
Merge branch 'speed-up-consensus-with-future-payloads' of github.com:…
vncoelho Dec 18, 2019
af24cb9
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Dec 25, 2019
7b5ddb7
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jan 6, 2020
5ae142f
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jan 6, 2020
055e10f
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jan 8, 2020
9da742d
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jan 13, 2020
d19713b
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jan 14, 2020
06027a2
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Apr 4, 2020
4f01bf9
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho May 15, 2020
00ad423
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho May 25, 2020
baccdb3
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Jun 8, 2020
067838a
Merge branch 'master' into speed-up-consensus-with-future-payloads
vncoelho Aug 17, 2020
f56261f
Update ConsensusContext.cs
vncoelho Aug 17, 2020
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
9 changes: 9 additions & 0 deletions neo.UnitTests/Consensus/UT_Consensus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ public void TestSerializeAndDeserializeConsensusContext()

consensusContext.LastChangeViewPayloads = new ConsensusPayload[consensusContext.Validators.Length];

consensusContext.FutureCommitPayloads = new ConsensusPayload[consensusContext.Validators.Length];
consensusContext.FuturePreparationPayloads = new ConsensusPayload[consensusContext.Validators.Length];
consensusContext.FutureChangeViewPayloads = new ConsensusPayload[consensusContext.Validators.Length];
consensusContext.FutureRecoveryPayloads = new ConsensusPayload[consensusContext.Validators.Length];

var copiedContext = TestUtils.CopyMsgBySerialization(consensusContext, new ConsensusContext(null, null));

copiedContext.Block.PrevHash.Should().Be(consensusContext.Block.PrevHash);
Expand All @@ -225,6 +230,10 @@ public void TestSerializeAndDeserializeConsensusContext()
copiedContext.PreparationPayloads.Should().BeEquivalentTo(consensusContext.PreparationPayloads);
copiedContext.CommitPayloads.Should().BeEquivalentTo(consensusContext.CommitPayloads);
copiedContext.ChangeViewPayloads.Should().BeEquivalentTo(consensusContext.ChangeViewPayloads);
copiedContext.FutureCommitPayloads.Should().BeEquivalentTo(consensusContext.FutureCommitPayloads);
copiedContext.FuturePreparationPayloads.Should().BeEquivalentTo(consensusContext.FuturePreparationPayloads);
copiedContext.FutureChangeViewPayloads.Should().BeEquivalentTo(consensusContext.FutureChangeViewPayloads);
copiedContext.FutureRecoveryPayloads.Should().BeEquivalentTo(consensusContext.FutureRecoveryPayloads);
}

[TestMethod]
Expand Down
59 changes: 58 additions & 1 deletion neo/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ internal class ConsensusContext : IDisposable, ISerializable
// if this node never heard from validator i, LastSeenMessage[i] will be -1.
public int[] LastSeenMessage;

/// <summary>
/// Future payloads used when CN are probably lagged
/// Verified ConsensusPayloads are cached and the lastest height are stored
/// They are possibly used when the nodes syncs to the last height
/// </summary>
public ConsensusPayload[] FuturePreparationPayloads;
public ConsensusPayload[] FutureCommitPayloads;
public ConsensusPayload[] FutureChangeViewPayloads;
public ConsensusPayload[] FutureRecoveryPayloads;

/// <summary>
/// Store all verified unsorted transactions' senders' fee currently in the consensus context.
/// </summary>
Expand Down Expand Up @@ -107,12 +117,20 @@ public void Deserialize(BinaryReader reader)
Block.NextConsensus = null;
Block.ConsensusData = reader.ReadSerializable<ConsensusData>();
ViewNumber = reader.ReadByte();

TransactionHashes = reader.ReadSerializableArray<UInt256>();
Transaction[] transactions = reader.ReadSerializableArray<Transaction>(Block.MaxTransactionsPerBlock);

PreparationPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);
CommitPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);
ChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);
LastChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);

FuturePreparationPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);
FutureCommitPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);
FutureChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);
FutureRecoveryPayloads = reader.ReadNullableArray<ConsensusPayload>(Blockchain.MaxValidators);

if (TransactionHashes.Length == 0 && !RequestSentOrReceived)
TransactionHashes = null;
Transactions = transactions.Length == 0 && !RequestSentOrReceived ? null : transactions.ToDictionary(p => p.Hash);
Expand Down Expand Up @@ -336,7 +354,7 @@ public ConsensusPayload MakePrepareResponse()
});
}

public void Reset(byte viewNumber)
public void Reset(byte viewNumber, bool resetFutures = true)
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
{
if (viewNumber == 0)
{
Expand Down Expand Up @@ -405,6 +423,38 @@ public void Reset(byte viewNumber)
TransactionHashes = null;
PreparationPayloads = new ConsensusPayload[Validators.Length];
if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index;

if (resetFutures)
ResetFuturePayloads();
}

public void ResetFuturePayloads()
{
FutureCommitPayloads = new ConsensusPayload[Validators.Length];
FuturePreparationPayloads = new ConsensusPayload[Validators.Length];
FutureChangeViewPayloads = new ConsensusPayload[Validators.Length];
FutureRecoveryPayloads = new ConsensusPayload[Validators.Length];
}

public bool HasFuturePayloads()
{
if (FuturePreparationPayloads != null)
foreach (var payload in FuturePreparationPayloads)
if (payload != null)
return true;
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
if (FutureChangeViewPayloads != null)
foreach (var payload in FutureChangeViewPayloads)
if (payload != null)
return true;
if (FutureCommitPayloads != null)
foreach (var payload in FutureCommitPayloads)
if (payload != null)
return true;
if (FutureRecoveryPayloads != null)
foreach (var payload in FutureRecoveryPayloads)
if (payload != null)
return true;
return false;
}

public void Save()
Expand All @@ -422,10 +472,17 @@ public void Serialize(BinaryWriter writer)
writer.Write(ViewNumber);
writer.Write(TransactionHashes ?? new UInt256[0]);
writer.Write(Transactions?.Values.ToArray() ?? new Transaction[0]);

writer.WriteNullableArray(PreparationPayloads);
writer.WriteNullableArray(CommitPayloads);
writer.WriteNullableArray(ChangeViewPayloads);
writer.WriteNullableArray(LastChangeViewPayloads);

writer.WriteNullableArray(FuturePreparationPayloads);
writer.WriteNullableArray(FutureCommitPayloads);
writer.WriteNullableArray(FutureChangeViewPayloads);
writer.WriteNullableArray(FutureRecoveryPayloads);

}
}
}
102 changes: 97 additions & 5 deletions neo/Consensus/ConsensusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ private void CheckPreparations()

private void InitializeConsensus(byte viewNumber)
{
context.Reset(viewNumber);
bool hasFuturePayload = context.HasFuturePayloads();
context.Reset(viewNumber, !hasFuturePayload);
if (viewNumber > 0)
Log($"changeview: view={viewNumber} primary={context.Validators[context.GetPrimaryIndex((byte)(viewNumber - 1u))]}", LogLevel.Warning);
Log($"initialize: height={context.Block.Index} view={viewNumber} index={context.MyIndex} role={(context.IsPrimary ? "Primary" : context.WatchOnly ? "WatchOnly" : "Backup")}");
Expand All @@ -185,8 +186,36 @@ private void InitializeConsensus(byte viewNumber)
{
ChangeTimer(TimeSpan.FromMilliseconds(Blockchain.MillisecondsPerBlock << (viewNumber + 1)));
}

// Try to speed up consensus if cached future payloads exists
if (hasFuturePayload)
{
TryToConsumeFuturePayload(context.FuturePreparationPayloads);
TryToConsumeFuturePayload(context.FutureCommitPayloads);
TryToConsumeFuturePayload(context.FutureChangeViewPayloads);
TryToConsumeFuturePayload(context.FutureRecoveryPayloads);
}
}

private void TryToConsumeFuturePayload(ConsensusPayload[] payloadsArray)
{
for (int p = 0; p < payloadsArray.Length; p++)
{
var payload = payloadsArray[p];
if (payload != null)
{
if (payload.BlockIndex < context.Block.Index)
{
payloadsArray[p] = null;
}
else if (payload.PrevHash == context.Block.PrevHash && payload.BlockIndex == context.Block.Index)
{
OnConsensusPayload(payload, true);
payloadsArray[p] = null;
}
}
}
}
private void Log(string message, LogLevel level = LogLevel.Info)
{
Plugin.Log(nameof(ConsensusService), level, message);
Expand Down Expand Up @@ -252,10 +281,74 @@ private void ExtendTimerByFactor(int maxDelayInBlockTimes)
ChangeTimer(nextDelay);
}

private void OnConsensusPayload(ConsensusPayload payload)
private void TryToSaveFuturePayloads(ConsensusPayload payload)
{
// Limit the maximum future payload to be saved,
// avoiding caching payload when node is lagged behind by more than furtherPayloadToSave locks
uint furtherPayloadToSave = 10;
Copy link
Member

Choose a reason for hiding this comment

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

Move it to a constant?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think so.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you move it, @shargon? It is not done yet.

if ((payload.BlockIndex >= context.Block.Index + 1) && (payload.BlockIndex <= context.Block.Index + furtherPayloadToSave))
{
ConsensusMessage futureMessage;
try
{
futureMessage = payload.ConsensusMessage;
}
catch (FormatException)
{
return;
}
catch (IOException)
{
return;
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
}

switch (futureMessage)
{
case ChangeView view:
tryToSavePayloadIntoArray(context.FutureChangeViewPayloads, payload, futureMessage.ViewNumber);
break;
case Commit commit:
tryToSavePayloadIntoArray(context.FutureCommitPayloads, payload, futureMessage.ViewNumber);
break;
case RecoveryMessage recovery:
tryToSavePayloadIntoArray(context.FutureRecoveryPayloads, payload, futureMessage.ViewNumber);
break;
case PrepareRequest request:
case PrepareResponse response:
tryToSavePayloadIntoArray(context.FuturePreparationPayloads, payload, futureMessage.ViewNumber);
break;
}
}
}

private void tryToSavePayloadIntoArray(ConsensusPayload[] payloadsArray, ConsensusPayload payload, byte pViewNumber)
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
{
byte lastViewNumber = payloadsArray[payload.ValidatorIndex] != null ? (byte)payloadsArray[payload.ValidatorIndex]?.GetDeserializedMessage<ChangeView>().ViewNumber : (byte)0;
uint lastHeight = payloadsArray[payload.ValidatorIndex] != null ? payloadsArray[payload.ValidatorIndex].BlockIndex : 0;
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
if (payload.BlockIndex < lastHeight)
{
Log($"Trying to save validator {payload.ValidatorIndex} payload from height {payload.BlockIndex} but payload of {lastHeight} is already known", LogLevel.Warning);
}
else if (payload.BlockIndex == lastHeight)
{
payloadsArray[payload.ValidatorIndex] = (lastViewNumber != 0 && pViewNumber > lastViewNumber) ? payload : payloadsArray[payload.ValidatorIndex];
}
else
{
payloadsArray[payload.ValidatorIndex] = payload;
}
}

private void OnConsensusPayload(ConsensusPayload payload, bool avoidSaving = false)
{
if (context.BlockSent) return;
if (payload.Version != context.Block.Version) return;
if (payload.ValidatorIndex >= context.Validators.Length) return;

// Avoiding saving payload when it is being consumed or processed due to a recover payload
if (!avoidSaving)
TryToSaveFuturePayloads(payload);

if (context.BlockSent) return;
if (payload.PrevHash != context.Block.PrevHash || payload.BlockIndex != context.Block.Index)
{
if (context.Block.Index < payload.BlockIndex)
Expand All @@ -264,7 +357,6 @@ private void OnConsensusPayload(ConsensusPayload payload)
}
return;
}
if (payload.ValidatorIndex >= context.Validators.Length) return;
ConsensusMessage message;
try
{
Expand Down Expand Up @@ -629,7 +721,7 @@ private void RequestChangeView(ChangeViewReason reason)
private bool ReverifyAndProcessPayload(ConsensusPayload payload)
{
if (!payload.Verify(context.Snapshot)) return false;
OnConsensusPayload(payload);
OnConsensusPayload(payload, true);
return true;
}

Expand Down