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

[dBFT CONSENSUS]: dBFT 3.0 with double speakers model #680

Closed
wants to merge 69 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
e97daeb
Draft 0.1 for dBFT 3.0
vncoelho Dec 17, 2021
0343f4a
Moving on
vncoelho Dec 17, 2021
c432ffc
Moving on
vncoelho Dec 17, 2021
970e482
format
vncoelho Dec 17, 2021
01d033c
moving on
vncoelho Dec 17, 2021
02fa0b7
format
vncoelho Dec 17, 2021
5523a31
Adding new
vncoelho Dec 17, 2021
bbb33ae
More fix
vncoelho Dec 17, 2021
ab8eec2
Additional fix
vncoelho Dec 17, 2021
cad5562
General fixes
vncoelho Dec 17, 2021
43166ec
format
vncoelho Dec 17, 2021
94e42b4
Minor fix
vncoelho Dec 17, 2021
6d5939c
Minor fix fixed
vncoelho Dec 17, 2021
4489d37
Fixing conditions and other fixed variables
vncoelho Jan 17, 2022
bedb125
Format
vncoelho Jan 17, 2022
73626ac
Fixing state
vncoelho Jan 17, 2022
ff7a5a1
Merge branch 'master' into dbft3.0-doublespeakers
Jun 8, 2022
29e267b
fix build error
Jun 8, 2022
d0b1c75
optimize
Jun 8, 2022
d06424f
fix commitedcount
Jun 8, 2022
482d055
recovery contains PreCommit and P2 messages
Jun 9, 2022
d7f452a
fix OnStart and message sizes
Jun 10, 2022
ffc5771
optimize
Jun 10, 2022
52f0659
optimize primary check
Jun 10, 2022
40348e1
Round-Robin strategy 2
Jun 10, 2022
7a43c5c
rm comment
Jun 10, 2022
11a7747
clean
Jun 13, 2022
e2ad61e
apply https://github.com/neo-project/neo/issues/2058
Jun 14, 2022
6772a46
format
Jun 14, 2022
a811dcf
Merge branch 'master' into dbft3.0-doublespeakers
Jun 14, 2022
cc4b3d0
Merge branch 'master' into dbft3.0-doublespeakers
Aug 9, 2022
6d5daf5
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Aug 19, 2022
e86de2a
fix tx dump
Sep 1, 2022
c86f4ce
Merge branch 'master' into dbft3.0-doublespeakers
Sep 5, 2022
c2f0b02
fix
Sep 13, 2022
19d2810
clean
Sep 13, 2022
d524245
Initial fix on countcommitted and fix cleaning CommitPayloads after c…
vncoelho Sep 16, 2022
76f4253
pId
Sep 21, 2022
7009fa8
log
Sep 21, 2022
6e59214
ValidatorIndex in PrepareRequest of RecoveryMessage
Sep 21, 2022
f9f0465
Comment
vncoelho Sep 21, 2022
9324899
name
Sep 21, 2022
a91dd63
fix fallback primary index
Oct 8, 2022
e490566
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Nov 14, 2022
dc474fc
Merge branch 'master' into dbft3.0-doublespeakers
superboyiii Dec 6, 2022
8d3f65d
Merge branch 'master' into dbft3.0-doublespeakers
superboyiii Dec 12, 2022
0c7b5eb
Fix Null with basic logic following Owen finding
vncoelho Dec 14, 2022
a2df166
Format
vncoelho Dec 14, 2022
4e8c6ba
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Jan 27, 2023
78f3033
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Apr 5, 2023
5677567
Merge branch 'master' into dbft3.0-doublespeakers
superboyiii May 11, 2023
3f90ec4
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Oct 10, 2023
44c5d7c
format
vncoelho Oct 10, 2023
33aaeb3
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Oct 19, 2023
b13b6c4
Update ConsensusService.cs
vncoelho Oct 19, 2023
47f83fc
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Nov 21, 2023
d2e314a
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Jan 8, 2024
ff291f6
Merge branch 'master' into dbft3.0-doublespeakers
Jim8y Feb 17, 2024
7aa1b45
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Feb 22, 2024
cb370f1
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Feb 24, 2024
d2c4e6a
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Mar 12, 2024
8b493f2
dotnet format
vncoelho Mar 12, 2024
2cda440
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Mar 18, 2024
8048f69
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Mar 18, 2024
7445a1c
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Mar 19, 2024
2f793cf
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Mar 21, 2024
fc82203
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho Apr 5, 2024
653c615
Merge branch 'master' into dbft3.0-doublespeakers
vncoelho May 11, 2024
c72c9c6
Merge branch 'master' into dbft3.0-doublespeakers
Jim8y May 12, 2024
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
5 changes: 2 additions & 3 deletions src/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ internal void EnsureMaxBlockLimitation(IEnumerable<Transaction> txs, uint pID)

public ExtensiblePayload MakePrepareRequest(uint pID)
{
Log($"MakePrepareRequest I", LogLevel.Debug);
EnsureMaxBlockLimitation(neoSystem.MemPool.GetSortedVerifiedTransactions(), pID);
Block[pID].Header.Timestamp = Math.Max(TimeProvider.Current.UtcNow.ToTimestampMS(), PrevHeader.Timestamp + 1);
Block[pID].Header.Nonce = GetNonce();
Expand All @@ -132,7 +131,7 @@ public ExtensiblePayload MakeRecoveryRequest()
public ExtensiblePayload MakeRecoveryMessage()
{
PrepareRequest prepareRequestMessage = null;
if (TransactionHashes != null)
if (TransactionHashes[0] != null)
{
prepareRequestMessage = new PrepareRequest
{
Expand Down Expand Up @@ -171,7 +170,7 @@ public ExtensiblePayload MakePreCommit(uint i)
{
return PreCommitPayloads[i][MyIndex] = MakeSignedPayload(new PreCommit
{
PreparationHash = PreCommitPayloads[i][Block[i].PrimaryIndex].Hash,
PreparationHash = PreparationPayloads[i][Block[i].PrimaryIndex].Hash,
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
Id = i
});
}
Expand Down
31 changes: 18 additions & 13 deletions src/DBFTPlugin/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ public partial class ConsensusContext : IDisposable, ISerializable
public bool IsPriorityPrimary => MyIndex == GetPriorityPrimaryIndex(ViewNumber);
public bool IsFallbackPrimary => MyIndex == GetFallbackPrimaryIndex(ViewNumber);

public bool IsAPrimary => IsPriorityPrimary || IsFallbackPrimary;
public bool IsAPrimary => IsPriorityPrimary || (ViewNumber == 0 && IsFallbackPrimary);
vncoelho marked this conversation as resolved.
Show resolved Hide resolved

//Modify to be 1 or 4/3
public float PrimaryTimerPriorityMultiplier => 1;
public float PrimaryTimerFallBackMultiplier => 4 / 3;
public float PrimaryTimerFallBackMultiplier => (float)4 / 3;
public float PrimaryTimerMultiplier => IsPriorityPrimary ? PrimaryTimerPriorityMultiplier : PrimaryTimerFallBackMultiplier;
public bool IsBackup => MyIndex >= 0 && !IsPriorityPrimary && IsFallbackPrimary;
public bool IsBackup => MyIndex >= 0 && !IsPriorityPrimary && !IsFallbackPrimary;
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
public bool WatchOnly => MyIndex < 0;
public Header PrevHeader => NativeContract.Ledger.GetHeader(Snapshot, Block[0].PrevHash);
public int CountCommitted => CommitPayloads.Count(p => p != null);
public int CountCommitted => CommitPayloads[0].Count(p => p != null);
public int CountFailed
{
get
Expand All @@ -98,10 +98,11 @@ public bool ValidatorsChanged
}

#region Consensus States
public bool RequestSentOrReceived => (PreparationPayloads[0][GetPriorityPrimaryIndex(ViewNumber)] != null || PreparationPayloads[1][GetFallbackPrimaryIndex(ViewNumber)] != null);
public bool ResponseSent => !WatchOnly && (PreparationPayloads[0][MyIndex] != null || PreparationPayloads[1][MyIndex] != null);
public bool CommitSent => !WatchOnly && (CommitPayloads[0][MyIndex] != null || CommitPayloads[1][MyIndex] != null);
public bool BlockSent => (Block[0].Transactions != null || Block[1].Transactions != null);
public bool RequestSentOrReceived => PreparationPayloads[0][GetPriorityPrimaryIndex(ViewNumber)] != null || (ViewNumber == 0 && PreparationPayloads[1][GetFallbackPrimaryIndex(ViewNumber)] != null);
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
public bool ResponseSent => !WatchOnly && (PreparationPayloads[0][MyIndex] != null || (ViewNumber == 0 && PreparationPayloads[1][MyIndex] != null));
public bool PreCommitSent => !WatchOnly && (PreCommitPayloads[0][MyIndex] != null || (ViewNumber == 0 && PreCommitPayloads[1][MyIndex] != null));
public bool CommitSent => !WatchOnly && (CommitPayloads[0][MyIndex] != null || (ViewNumber == 0 && CommitPayloads[1][MyIndex] != null));
public bool BlockSent => Block[0].Transactions != null || (ViewNumber == 0 && Block[1]?.Transactions != null);
public bool ViewChanging => !WatchOnly && GetMessage<ChangeView>(ChangeViewPayloads[MyIndex])?.NewViewNumber > ViewNumber;
public bool NotAcceptingPayloadsDueToViewChanging => ViewChanging && !MoreThanFNodesCommittedOrLost;
// A possible attack can happen if the last node to commit is malicious and either sends change view after his
Expand Down Expand Up @@ -228,7 +229,10 @@ public void Reset(byte viewNumber)
}
MyIndex = -1;
for (uint i = 0; i <= 1; i++)
{
PreCommitPayloads[i] = new ExtensiblePayload[Validators.Length];
CommitPayloads[i] = new ExtensiblePayload[Validators.Length];
}
ChangeViewPayloads = new ExtensiblePayload[Validators.Length];
LastChangeViewPayloads = new ExtensiblePayload[Validators.Length];
if (ValidatorsChanged || LastSeenMessage is null)
Expand Down Expand Up @@ -266,7 +270,6 @@ public void Reset(byte viewNumber)
ViewNumber = viewNumber;
for (uint pID = 0; pID <= 1; pID++)
{
Block[pID].Header.PrimaryIndex = GetPriorityPrimaryIndex(viewNumber);
Block[pID].Header.MerkleRoot = null;
Block[pID].Header.Timestamp = 0;
Block[pID].Header.Nonce = 0;
Expand All @@ -275,7 +278,8 @@ public void Reset(byte viewNumber)
PreparationPayloads[pID] = new ExtensiblePayload[Validators.Length];
if (MyIndex >= 0) LastSeenMessage[Validators[MyIndex]] = Block[pID].Index;
}

Block[0].Header.PrimaryIndex = GetPriorityPrimaryIndex(viewNumber);
Block[1].Header.PrimaryIndex = GetFallbackPrimaryIndex(viewNumber);
//=========================================
// Disable Fallback if viewnumber > 1
if (viewNumber > 0)
Expand All @@ -299,8 +303,10 @@ public void Save()
public void Deserialize(ref MemoryReader reader)
{
Reset(0);
ViewNumber = reader.ReadByte();
for (uint pID = 0; pID <= 1; pID++)
{
if (ViewNumber > 0 && pID > 0) break;
if (reader.ReadUInt32() != Block[pID].Version) throw new FormatException();
if (reader.ReadUInt32() != Block[pID].Index) throw new InvalidOperationException();
Block[pID].Header.Timestamp = reader.ReadUInt64();
Expand All @@ -326,17 +332,17 @@ public void Deserialize(ref MemoryReader reader)
VerificationContext[pID].AddTransaction(tx);
}
}

ViewNumber = reader.ReadByte();
ChangeViewPayloads = reader.ReadNullableArray<ExtensiblePayload>(neoSystem.Settings.ValidatorsCount);
LastChangeViewPayloads = reader.ReadNullableArray<ExtensiblePayload>(neoSystem.Settings.ValidatorsCount);

}

public void Serialize(BinaryWriter writer)
{
writer.Write(ViewNumber);
for (uint i = 0; i <= 1; i++)
{
if (ViewNumber > 0 && i > 0) break;
writer.Write(Block[i].Version);
writer.Write(Block[i].Index);
writer.Write(Block[i].Timestamp);
Expand All @@ -349,7 +355,6 @@ public void Serialize(BinaryWriter writer)
writer.WriteNullableArray(PreCommitPayloads[i]);
writer.WriteNullableArray(CommitPayloads[i]);
}
writer.Write(ViewNumber);
writer.WriteNullableArray(ChangeViewPayloads);
writer.WriteNullableArray(LastChangeViewPayloads);
}
Expand Down
41 changes: 23 additions & 18 deletions src/DBFTPlugin/Consensus/ConsensusService.Check.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ private bool CheckPrepareResponse(uint i)
{
// if we are the primary for this view, but acting as a backup because we recovered our own
// previously sent prepare request, then we don't want to send a prepare response.
if (context.IsAPrimary || context.WatchOnly) return true;
if ((i == 0 && context.IsPriorityPrimary) || (i == 1 && context.IsFallbackPrimary) || context.WatchOnly) return true;

// Check maximum block size via Native Contract policy
if (context.GetExpectedBlockSize(i) > dbftSettings.MaxBlockSize)
Expand Down Expand Up @@ -101,25 +101,30 @@ private void CheckExpectedView(byte viewNumber)

private void CheckPreparations(uint pID)
{
int thresholdForPrep = pID == 0 ? context.F + 1 : context.M;

if (context.PreparationPayloads[pID].Count(p => p != null) >= thresholdForPrep && context.TransactionHashes[pID].All(p => context.Transactions[pID].ContainsKey(p)))
if (context.TransactionHashes[pID].All(p => context.Transactions[pID].ContainsKey(p)))
{
ExtensiblePayload payload = context.MakePreCommit(pID);
Log($"Sending {nameof(PreCommit)} pOrF={pID}");
context.Save();
localNode.Tell(new LocalNode.SendDirectly { Inventory = payload });
// Set timer, so we will resend the commit in case of a networking issue
ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock));
CheckPreCommits(pID);

// ==============================================
// Speed-up path to also send commit
if (pID == 0 && context.PreparationPayloads[0].Count(p => p != null) >= context.M)
var preparationsCount = context.PreparationPayloads[pID].Count(p => p != null);
if (context.ViewNumber > 0)
{
if (preparationsCount >= context.M)
CheckPreCommits(0, true);
return;
}
if (!context.PreCommitSent
&& ((pID == 0 && preparationsCount >= context.F + 1)
|| (pID == 1 && preparationsCount >= context.M)))
{
ExtensiblePayload payload = context.MakePreCommit(pID);
Log($"Sending {nameof(PreCommit)} pOrF={pID}");
context.Save();
localNode.Tell(new LocalNode.SendDirectly { Inventory = payload });
// Set timer, so we will resend the commit in case of a networking issue
ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock));
}
if (context.ViewNumber == 0 && pID == 0 && preparationsCount >= context.M)
{
CheckPreCommits(0, true);
// ==============================================

return;
}
}
}
}
Expand Down
16 changes: 11 additions & 5 deletions src/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private void OnConsensusPayload(ExtensiblePayload payload)
private void OnPrepareRequestReceived(ExtensiblePayload payload, PrepareRequest message)
{
if (context.RequestSentOrReceived || context.NotAcceptingPayloadsDueToViewChanging) return;
uint pOrF = Convert.ToUInt32(message.ValidatorIndex == context.GetPriorityPrimaryIndex(context.ViewNumber));
uint pOrF = message.ValidatorIndex == context.GetPriorityPrimaryIndex(context.ViewNumber) || context.ViewNumber > 0 ? 0u : 1u;
// Add verification for Fallback
if (message.ValidatorIndex != context.Block[pOrF].PrimaryIndex || message.ViewNumber != context.ViewNumber) return;
if (message.Version != context.Block[pOrF].Version || message.PrevHash != context.Block[pOrF].PrevHash) return;
Expand Down Expand Up @@ -160,8 +160,14 @@ private void OnPrepareResponseReceived(ExtensiblePayload payload, PrepareRespons
{
if (message.ViewNumber != context.ViewNumber) return;
if (context.PreparationPayloads[message.Id][message.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return;
if (context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex].Hash))
return;
if (context.RequestSentOrReceived)
{
// Check if we have joined another consensus process
if (context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex] == null) return;
if (!message.PreparationHash.Equals(context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex].Hash))
return;
}


// Timeout extension: prepare response has been received with success
// around 2*15/M=30.0/5 ~ 40% block time (for M=5)
Expand All @@ -177,8 +183,8 @@ private void OnPrepareResponseReceived(ExtensiblePayload payload, PrepareRespons
private void OnPreCommitReceived(ExtensiblePayload payload, PreCommit message)
{
if (message.ViewNumber != context.ViewNumber) return;
if (context.PreparationPayloads[message.Id][message.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return;
if (context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex].Hash))
if (context.PreCommitPayloads[message.Id][message.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return;
if (context.PreCommitPayloads[message.Id][context.Block[message.Id].PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[message.Id][context.Block[message.Id].PrimaryIndex].Hash))
return;

Log($"{nameof(OnPreCommitReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} Id={message.Id}");
Expand Down
7 changes: 2 additions & 5 deletions src/DBFTPlugin/Consensus/ConsensusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private void InitializeConsensus(byte viewNumber)
if (viewNumber > 0)
Log($"View changed: view={viewNumber} primary={context.Validators[context.GetPriorityPrimaryIndex((byte)(viewNumber - 1u))]}", LogLevel.Warning);
uint blockCurrentIndex = context.Block[0].Index;
Log($"Initialize: height={blockCurrentIndex} view={viewNumber} index={context.MyIndex} role={(context.IsPriorityPrimary ? "PrimaryP1" : context.IsFallbackPrimary ? "PrimaryP2" : context.WatchOnly ? "WatchOnly" : "Backup")}");
Log($"Initialize: height={blockCurrentIndex} view={viewNumber} index={context.MyIndex} role={(context.IsPriorityPrimary ? (viewNumber > 0 ? "Primary" : "PrimaryP1") : (context.IsFallbackPrimary && viewNumber == 0 ? "PrimaryP2" : (context.WatchOnly ? "WatchOnly" : "Backup")))}");
if (context.WatchOnly) return;
if (context.IsAPrimary)
{
Expand Down Expand Up @@ -168,7 +168,7 @@ private void OnStart()

private void OnTimer(Timer timer)
{
uint pID = Convert.ToUInt32(!context.IsPriorityPrimary);
uint pID = Convert.ToUInt32(!(context.IsPriorityPrimary || context.ViewNumber > 0));
if (context.WatchOnly || context.BlockSent) return;
if (timer.Height != context.Block[pID].Index || timer.ViewNumber != context.ViewNumber) return;
if (context.IsAPrimary && !context.RequestSentOrReceived)
Expand Down Expand Up @@ -206,14 +206,11 @@ private void SendPrepareRequest(uint pID)
if (context.Validators.Length == 1)
CheckPreparations(pID);

Log($"SendPrepareRequest I", LogLevel.Debug);

if (context.TransactionHashes[pID].Length > 0)
{
foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, context.TransactionHashes[pID]))
localNode.Tell(Message.Create(MessageCommand.Inv, payload));
}
Log($"SendPrepareRequest II", LogLevel.Debug);
ChangeTimer(TimeSpan.FromMilliseconds(context.PrimaryTimerMultiplier * ((neoSystem.Settings.MillisecondsPerBlock << (context.ViewNumber + 1)) - (context.ViewNumber == 0 ? neoSystem.Settings.MillisecondsPerBlock : 0))));
}

Expand Down