private void OnChangeViewReceived(ExtensiblePayload payload, ChangeView message) { if (message.NewViewNumber <= context.ViewNumber) { OnRecoveryRequestReceived(payload, message); } if (context.CommitSent) { return; } var expectedView = context.GetMessage <ChangeView>(context.ChangeViewPayloads[message.ValidatorIndex])?.NewViewNumber ?? 0; if (message.NewViewNumber <= expectedView) { return; } Log($"{nameof(OnChangeViewReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} nv={message.NewViewNumber} reason={message.Reason}"); context.ChangeViewPayloads[message.ValidatorIndex] = payload; CheckExpectedView(message.NewViewNumber); }
private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message) { if (message.NewViewNumber <= context.ViewNumber) { OnRecoveryRequestReceived(payload); } if (context.CommitSent()) { return; } var expectedView = context.ChangeViewPayloads[payload.ValidatorIndex]?.GetDeserializedMessage <ChangeView>().NewViewNumber ?? (byte)0; if (message.NewViewNumber <= expectedView) { return; } Log($"{nameof(OnChangeViewReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} nv={message.NewViewNumber}"); context.ChangeViewPayloads[payload.ValidatorIndex] = payload; CheckExpectedView(message.NewViewNumber); }
private void CheckExpectedView(byte viewNumber) { if (context.ViewNumber >= viewNumber) { return; } // if there are `M` change view payloads with NewViewNumber greater than viewNumber, then, it is safe to move if (context.ChangeViewPayloads.Count(p => p != null && p.GetDeserializedMessage <ChangeView>().NewViewNumber >= viewNumber) >= context.M) { if (!context.WatchOnly) { ChangeView message = context.ChangeViewPayloads[context.MyIndex]?.GetDeserializedMessage <ChangeView>(); // Communicate the network about my agreement to move to `viewNumber` // if my last change view payload, `message`, has NewViewNumber lower than current view to change if (message is null || message.NewViewNumber < viewNumber) { localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeChangeView(ChangeViewReason.ChangeAgreement) }); } } InitializeConsensus(viewNumber); } }
private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message) { // We keep track of the payload hashes received in this block, and don't respond with recovery // in response to the same payload that we already responded to previously. // ChangeView messages include a Timestamp when the change view is sent, thus if a node restarts // and issues a change view for the same view, it will have a different hash and will correctly respond // again; however replay attacks of the ChangeView message from arbitrary nodes will not trigger an // additional recovery message response. if (!knownHashes.Add(payload.Hash)) { return; } if (message.NewViewNumber <= context.ViewNumber) { if (context.WatchOnly()) { return; } if (!context.CommitSent()) { bool shouldSendRecovery = false; // Limit recovery to be sent from, at least, `f` nodes when the request is from a lower view number. int allowedRecoveryNodeCount = context.F(); for (int i = 0; i < allowedRecoveryNodeCount; i++) { var eligibleResponders = context.Validators.Length - 1; var chosenIndex = (payload.ValidatorIndex + i + message.NewViewNumber) % eligibleResponders; if (chosenIndex >= payload.ValidatorIndex) { chosenIndex++; } if (chosenIndex != context.MyIndex) { continue; } shouldSendRecovery = true; break; } if (!shouldSendRecovery) { return; } } Log($"send recovery from view: {message.ViewNumber} to view: {context.ViewNumber}"); localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeRecoveryMessage() }); } if (context.CommitSent()) { return; } var expectedView = context.ChangeViewPayloads[payload.ValidatorIndex]?.GetDeserializedMessage <ChangeView>().NewViewNumber ?? (byte)0; if (message.NewViewNumber <= expectedView) { return; } Log($"{nameof(OnChangeViewReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} nv={message.NewViewNumber}"); context.ChangeViewPayloads[payload.ValidatorIndex] = payload; CheckExpectedView(message.NewViewNumber); }