-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Stage 3 of dBFT (Commit) #320
Changes from 15 commits
2de2101
17b5ad0
66709f6
e6f52a5
6eb2ae0
1788d01
97322b0
fb1f9a1
2415611
e08e0b0
700ff6f
3d56256
a1272fa
ef134fe
77a5d37
4e12b24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System.IO; | ||
using Neo.IO; | ||
|
||
namespace Neo.Consensus | ||
{ | ||
internal class CommitAgreement : ConsensusMessage | ||
{ | ||
/// <summary> | ||
/// Block hash of the signature | ||
/// </summary> | ||
public UInt256 BlockHash; | ||
|
||
/// <summary> | ||
/// Constructors | ||
/// </summary> | ||
public CommitAgreement() : base(ConsensusMessageType.CommitAgreement) { } | ||
|
||
public override void Deserialize(BinaryReader reader) | ||
{ | ||
base.Deserialize(reader); | ||
|
||
BlockHash = reader.ReadSerializable<UInt256>(); | ||
} | ||
|
||
public override void Serialize(BinaryWriter writer) | ||
{ | ||
base.Serialize(writer); | ||
|
||
writer.Write(BlockHash); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -85,10 +85,17 @@ private bool CheckPolicy(Transaction tx) | |||
return true; | ||||
} | ||||
|
||||
private void CheckSignatures() | ||||
private void OnCommitAgreement(ConsensusPayload payload, CommitAgreement message) | ||||
{ | ||||
Log($"{nameof(OnCommitAgreement)}: height={payload.BlockIndex} hash={message.BlockHash.ToString()} view={message.ViewNumber} index={payload.ValidatorIndex}"); | ||||
|
||||
if (context.State.HasFlag(ConsensusState.BlockSent) || | ||||
!context.TryToCommit(payload, message)) return; | ||||
|
||||
if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean line 95: neo/neo/Consensus/ConsensusService.cs Line 95 in 77a5d37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But this method is called when receive a commit, no when you sent your commit, so if you receive 6 commits, and you don't send your commit, you never relay the block. |
||||
{ | ||||
context.State |= ConsensusState.BlockSent; | ||||
|
||||
Contract contract = Contract.CreateMultiSigContract(context.M, context.Validators); | ||||
Block block = context.MakeHeader(); | ||||
ContractParametersContext sc = new ContractParametersContext(block); | ||||
|
@@ -101,9 +108,26 @@ private void CheckSignatures() | |||
sc.Verifiable.Scripts = sc.GetScripts(); | ||||
block.Transactions = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray(); | ||||
Log($"relay block: {block.Hash}"); | ||||
|
||||
if (!localNode.Relay(block)) | ||||
{ | ||||
Log($"reject block: {block.Hash}"); | ||||
context.State |= ConsensusState.BlockSent; | ||||
} | ||||
} | ||||
} | ||||
|
||||
private void CheckSignatures() | ||||
{ | ||||
if (!context.State.HasFlag(ConsensusState.CommitSent) && | ||||
context.Signatures.Count(p => p != null) >= context.M && | ||||
context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) | ||||
{ | ||||
// Send my commit | ||||
|
||||
context.State |= ConsensusState.CommitSent; | ||||
SignAndRelay(context.MakeCommitAgreement()); | ||||
|
||||
Log($"Commit sent: height={context.BlockIndex} hash={context.CommitHash} state={context.State}"); | ||||
} | ||||
} | ||||
|
||||
|
@@ -206,61 +230,62 @@ private void InitializeConsensus(byte view_number) | |||
|
||||
private void LocalNode_InventoryReceived(object sender, IInventory inventory) | ||||
{ | ||||
ConsensusPayload payload = inventory as ConsensusPayload; | ||||
if (payload != null) | ||||
if (inventory == null || !(inventory is ConsensusPayload payload)) return; | ||||
|
||||
lock (context) | ||||
{ | ||||
lock (context) | ||||
if (payload.ValidatorIndex == context.MyIndex || | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not see the Is this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #233 :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I think that we can remove |
||||
payload.ValidatorIndex >= context.Validators.Length || | ||||
payload.Version != ConsensusContext.Version) return; | ||||
|
||||
if (payload.PrevHash != context.PrevHash || payload.BlockIndex != context.BlockIndex) | ||||
{ | ||||
if (payload.ValidatorIndex == context.MyIndex) return; | ||||
// Request blocks | ||||
|
||||
if (payload.Version != ConsensusContext.Version) | ||||
return; | ||||
if (payload.PrevHash != context.PrevHash || payload.BlockIndex != context.BlockIndex) | ||||
if (Blockchain.Default?.Height + 1 < payload.BlockIndex) | ||||
{ | ||||
// Request blocks | ||||
Log($"chain sync: expected={payload.BlockIndex} current: {Blockchain.Default?.Height} nodes={localNode.RemoteNodeCount}"); | ||||
|
||||
if (Blockchain.Default?.Height + 1 < payload.BlockIndex) | ||||
{ | ||||
Log($"chain sync: expected={payload.BlockIndex} current: {Blockchain.Default?.Height} nodes={localNode.RemoteNodeCount}"); | ||||
localNode.RequestGetBlocks(); | ||||
} | ||||
|
||||
localNode.RequestGetBlocks(); | ||||
} | ||||
return; | ||||
} | ||||
|
||||
return; | ||||
} | ||||
ConsensusMessage message; | ||||
try | ||||
{ | ||||
message = ConsensusMessage.DeserializeFrom(payload.Data); | ||||
} | ||||
catch | ||||
{ | ||||
return; | ||||
} | ||||
|
||||
if (payload.ValidatorIndex >= context.Validators.Length) return; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check if payload validator Index could had changed on RequestGetBlocks() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I move this validation to the begining of the method |
||||
ConsensusMessage message; | ||||
try | ||||
{ | ||||
message = ConsensusMessage.DeserializeFrom(payload.Data); | ||||
} | ||||
catch | ||||
{ | ||||
return; | ||||
} | ||||
if (message.ViewNumber != context.ViewNumber && message.Type != ConsensusMessageType.ChangeView) | ||||
return; | ||||
switch (message.Type) | ||||
{ | ||||
case ConsensusMessageType.ChangeView: | ||||
OnChangeViewReceived(payload, (ChangeView)message); | ||||
break; | ||||
case ConsensusMessageType.PrepareRequest: | ||||
OnPrepareRequestReceived(payload, (PrepareRequest)message); | ||||
break; | ||||
case ConsensusMessageType.PrepareResponse: | ||||
OnPrepareResponseReceived(payload, (PrepareResponse)message); | ||||
break; | ||||
} | ||||
if (message.ViewNumber != context.ViewNumber && message.Type != ConsensusMessageType.ChangeView) | ||||
return; | ||||
|
||||
switch (message.Type) | ||||
{ | ||||
case ConsensusMessageType.ChangeView: | ||||
OnChangeViewReceived(payload, (ChangeView)message); | ||||
break; | ||||
case ConsensusMessageType.PrepareRequest: | ||||
OnPrepareRequestReceived(payload, (PrepareRequest)message); | ||||
break; | ||||
case ConsensusMessageType.PrepareResponse: | ||||
OnPrepareResponseReceived(payload, (PrepareResponse)message); | ||||
break; | ||||
case ConsensusMessageType.CommitAgreement: | ||||
OnCommitAgreement(payload, (CommitAgreement)message); | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
|
||||
private void LocalNode_InventoryReceiving(object sender, InventoryReceivingEventArgs e) | ||||
{ | ||||
Transaction tx = e.Inventory as Transaction; | ||||
if (tx != null) | ||||
if (e.Inventory is Transaction tx) | ||||
{ | ||||
lock (context) | ||||
{ | ||||
|
@@ -274,22 +299,23 @@ private void LocalNode_InventoryReceiving(object sender, InventoryReceivingEvent | |||
} | ||||
} | ||||
|
||||
protected virtual void Log(string message) | ||||
{ | ||||
} | ||||
protected virtual void Log(string message) { } | ||||
|
||||
private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message) | ||||
{ | ||||
Log($"{nameof(OnChangeViewReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} nv={message.NewViewNumber}"); | ||||
|
||||
if (message.NewViewNumber <= context.ExpectedView[payload.ValidatorIndex]) | ||||
return; | ||||
|
||||
context.ExpectedView[payload.ValidatorIndex] = message.NewViewNumber; | ||||
CheckExpectedView(message.NewViewNumber); | ||||
} | ||||
|
||||
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) | ||||
{ | ||||
Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); | ||||
|
||||
if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived)) | ||||
return; | ||||
if (payload.ValidatorIndex != context.PrimaryIndex) return; | ||||
|
@@ -298,6 +324,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m | |||
Log($"Timestamp incorrect: {payload.Timestamp}"); | ||||
return; | ||||
} | ||||
|
||||
context.State |= ConsensusState.RequestReceived; | ||||
context.Timestamp = payload.Timestamp; | ||||
context.Nonce = message.Nonce; | ||||
|
@@ -328,8 +355,10 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m | |||
private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse message) | ||||
{ | ||||
Log($"{nameof(OnPrepareResponseReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}"); | ||||
|
||||
if (context.State.HasFlag(ConsensusState.BlockSent)) return; | ||||
if (context.Signatures[payload.ValidatorIndex] != null) return; | ||||
|
||||
Block header = context.MakeHeader(); | ||||
if (header == null || !Crypto.Default.VerifySignature(header.GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) return; | ||||
context.Signatures[payload.ValidatorIndex] = message.Signature; | ||||
|
@@ -373,6 +402,8 @@ private void RequestChangeView() | |||
|
||||
private void SignAndRelay(ConsensusPayload payload) | ||||
{ | ||||
if (payload == null) return; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this just for the commit case or it is a general case that has been happening? |
||||
|
||||
ContractParametersContext sc; | ||||
try | ||||
{ | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this double check necessary? Because
CheckSignatures()
already checked it and called OnCommitAgreement.