Beispiel #1
0
 private void OnRecoveryMessageReceived(ConsensusPayload payload, RecoveryMessage message)
 {
     if (message.ViewNumber < context.ViewNumber)
     {
         return;
     }
     Log($"{nameof(OnRecoveryMessageReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}");
     isRecovering = true;
     try
     {
         if (message.ViewNumber > context.ViewNumber)
         {
             if (context.CommitSent())
             {
                 return;
             }
             ConsensusPayload[] changeViewPayloads = message.GetChangeViewPayloads(context, payload);
             foreach (ConsensusPayload changeViewPayload in changeViewPayloads)
             {
                 ReverifyAndProcessPayload(changeViewPayload);
             }
         }
         if (message.ViewNumber != context.ViewNumber)
         {
             return;
         }
         if (!context.CommitSent())
         {
             if (!context.RequestSentOrReceived())
             {
                 ConsensusPayload prepareRequestPayload = message.GetPrepareRequestPayload(context, payload);
                 if (prepareRequestPayload != null)
                 {
                     ReverifyAndProcessPayload(prepareRequestPayload);
                 }
                 else if (context.IsPrimary())
                 {
                     SendPrepareRequest();
                 }
             }
             ConsensusPayload[] prepareResponsePayloads = message.GetPrepareResponsePayloads(context, payload);
             foreach (ConsensusPayload prepareResponsePayload in prepareResponsePayloads)
             {
                 ReverifyAndProcessPayload(prepareResponsePayload);
             }
         }
         ConsensusPayload[] commitPayloads = message.GetCommitPayloadsFromRecoveryMessage(context, payload);
         foreach (ConsensusPayload commitPayload in commitPayloads)
         {
             ReverifyAndProcessPayload(commitPayload);
         }
     }
     finally
     {
         isRecovering = false;
     }
 }
Beispiel #2
0
        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
            // additonal recovery message response.
            if (!knownHashes.Add(payload.Hash))
            {
                return;
            }
            if (message.NewViewNumber <= context.ViewNumber)
            {
                bool shouldSendRecovery = false;
                // Limit recovery to sending from `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 = GetLastExpectedView(payload.ValidatorIndex);

            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 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);
        }