Esempio n. 1
0
        /// <summary>
        /// Checks and computes stake.
        /// </summary>
        /// <param name="context">Context that contains variety of information regarding blocks validation and execution.</param>
        /// <exception cref="ConsensusErrors.PrevStakeNull">Thrown if previous stake is not found.</exception>
        /// <exception cref="ConsensusErrors.SetStakeEntropyBitFailed">Thrown if failed to set stake entropy bit.</exception>
        private void CheckAndComputeStake(RuleContext context)
        {
            ChainedHeader chainedHeader = context.ValidationContext.ChainedHeaderToValidate;
            Block         block         = context.ValidationContext.BlockToValidate;

            var posRuleContext = context as PosRuleContext;

            if (posRuleContext.BlockStake == null)
            {
                posRuleContext.BlockStake = BlockStake.Load(context.ValidationContext.BlockToValidate);
            }

            BlockStake blockStake = posRuleContext.BlockStake;

            // Verify hash target and signature of coinstake tx.
            if (BlockStake.IsProofOfStake(block))
            {
                ChainedHeader prevChainedHeader = chainedHeader.Previous;

                BlockStake prevBlockStake = this.stakeChain.Get(prevChainedHeader.HashBlock);
                if (prevBlockStake == null)
                {
                    ConsensusErrors.PrevStakeNull.Throw();
                }

                // Only do proof of stake validation for blocks that are after the assumevalid block or after the last checkpoint.
                if (!context.SkipValidation)
                {
                    this.stakeValidator.CheckProofOfStake(posRuleContext, prevChainedHeader, prevBlockStake, block.Transactions[1], chainedHeader.Header.Bits.ToCompact());
                }
                else
                {
                    this.Logger.LogTrace("POS validation skipped for block at height {0}.", chainedHeader.Height);
                }
            }

            // PoW is checked in CheckBlock().
            if (BlockStake.IsProofOfWork(block))
            {
                posRuleContext.HashProofOfStake = chainedHeader.Header.GetPoWHash();
            }

            // Compute stake entropy bit for stake modifier.
            if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit()))
            {
                this.Logger.LogTrace("(-)[STAKE_ENTROPY_BIT_FAIL]");
                ConsensusErrors.SetStakeEntropyBitFailed.Throw();
            }

            // Record proof hash value.
            blockStake.HashProof = posRuleContext.HashProofOfStake;

            int lastCheckpointHeight = this.Parent.Checkpoints.GetLastCheckpointHeight();

            if (chainedHeader.Height > lastCheckpointHeight)
            {
                // Compute stake modifier.
                ChainedHeader prevChainedHeader = chainedHeader.Previous;
                BlockStake    blockStakePrev    = prevChainedHeader == null ? null : this.stakeChain.Get(prevChainedHeader.HashBlock);
                blockStake.StakeModifierV2 = this.stakeValidator.ComputeStakeModifierV2(prevChainedHeader, blockStakePrev?.StakeModifierV2, blockStake.IsProofOfWork() ? chainedHeader.HashBlock : blockStake.PrevoutStake.Hash);
            }
            else if (chainedHeader.Height == lastCheckpointHeight)
            {
                // Copy checkpointed stake modifier.
                CheckpointInfo checkpoint = this.Parent.Checkpoints.GetCheckpoint(lastCheckpointHeight);
                blockStake.StakeModifierV2 = checkpoint.StakeModifierV2;
                this.Logger.LogTrace("Last checkpoint stake modifier V2 loaded: '{0}'.", blockStake.StakeModifierV2);
            }
            else
            {
                this.Logger.LogTrace("POS stake modifier computation skipped for block at height {0} because it is not above last checkpoint block height {1}.", chainedHeader.Height, lastCheckpointHeight);
            }
        }
 // Use this for initialization
 void Start()
 {
     checkpointinfo = CheckpointInfo.instance;
 }
 public Task CheckpointAsync(CheckpointInfo checkpointInfo)
 {
     return(this.reliableLog.CheckpointAsync(checkpointInfo));
 }
Esempio n. 4
0
 private void OnEnable()
 {
     currentCeckpoint  = checkpoints[0];
     nextCheckpointPos = checkpoints[1].position;
     StartCoroutine(MoveBetweenCheckpoints());
 }
        /// <summary>
        /// When a header is checkpointed and has a correct hash, chain that ends with such a header
        /// will be marked as <see cref="ValidationState.AssumedValid" /> and requested for download.
        /// </summary>
        /// <param name="chainedHeader">Checkpointed header.</param>
        /// <param name="latestNewHeader">The latest new header that was presented by the peer.</param>
        /// <param name="checkpoint">Information about the checkpoint at the height of the <paramref name="chainedHeader"/>.</param>
        private ConnectNewHeadersResult HandleCheckpointsHeader(ChainedHeader chainedHeader, ChainedHeader latestNewHeader, CheckpointInfo checkpoint)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:'{3}',{4}.{5}:'{6}')", nameof(chainedHeader), chainedHeader, nameof(latestNewHeader), latestNewHeader, nameof(checkpoint), nameof(checkpoint.Hash), checkpoint.Hash);

            if (checkpoint.Hash != chainedHeader.HashBlock)
            {
                this.logger.LogDebug("Chained header '{0}' does not match checkpoint '{1}'.", chainedHeader, checkpoint.Hash);
                this.logger.LogTrace("(-)[INVALID_HEADER_NOT_MATCHING_CHECKPOINT]");
                throw new InvalidHeaderException();
            }

            ChainedHeader subchainTip = chainedHeader;

            if (chainedHeader.Height == this.checkpoints.GetLastCheckpointHeight())
            {
                subchainTip = latestNewHeader;
            }

            ConnectNewHeadersResult connectNewHeadersResult = this.MarkBetterChainAsRequired(subchainTip);

            this.MarkTrustedChainAsAssumedValid(chainedHeader);

            this.logger.LogTrace("(-):{0}", connectNewHeadersResult);
            return(connectNewHeadersResult);
        }
        /// <summary>
        /// A new list of headers are presented by a peer, the headers will try to be connected to the tree.
        /// Blocks associated with headers that are interesting (i.e. represent a chain with greater chainwork than our consensus tip)
        /// will be requested for download.
        /// </summary>
        /// <remarks>
        /// The headers are assumed to be in consecutive order.
        /// </remarks>
        /// <param name="networkPeerId">Id of a peer that presented the headers.</param>
        /// <param name="headers">The list of headers to connect to the tree.</param>
        /// <returns>
        /// Information about which blocks need to be downloaded together with information about which input headers were processed.
        /// Only headers that we can validate will be processed. The rest of the headers will be submitted later again for processing.
        /// </returns>
        public ConnectNewHeadersResult ConnectNewHeaders(int networkPeerId, List <BlockHeader> headers)
        {
            Guard.NotNull(headers, nameof(headers));
            this.logger.LogTrace("({0}:{1},{2}.{3}:{4})", nameof(networkPeerId), networkPeerId, nameof(headers), nameof(headers.Count), headers.Count);

            if (!this.chainedHeadersByHash.ContainsKey(headers[0].HashPrevBlock))
            {
                this.logger.LogTrace("(-)[HEADER_COULD_NOT_CONNECT]");
                throw new ConnectHeaderException();
            }

            List <ChainedHeader> newChainedHeaders = this.CreateNewHeaders(headers);
            uint256 lastHash = headers.Last().GetHash();

            this.AddOrReplacePeerTip(networkPeerId, lastHash);

            if (newChainedHeaders == null)
            {
                this.logger.LogTrace("(-)[NO_NEW_HEADERS]");
                return(new ConnectNewHeadersResult()
                {
                    Consumed = this.chainedHeadersByHash[lastHash]
                });
            }

            ChainedHeader earliestNewHeader = newChainedHeaders.First();
            ChainedHeader latestNewHeader   = newChainedHeaders.Last();

            ConnectNewHeadersResult connectNewHeadersResult = null;

            bool isAssumedValidEnabled = this.consensusSettings.BlockAssumedValid != null;
            bool isBelowLastCheckpoint = this.consensusSettings.UseCheckpoints && (earliestNewHeader.Height <= this.checkpoints.GetLastCheckpointHeight());

            if (isBelowLastCheckpoint || isAssumedValidEnabled)
            {
                ChainedHeader currentChainedHeader = latestNewHeader;

                // When we look for a checkpoint header or an assume valid header, we go from the last presented
                // header to the first one in the reverse order because if there were multiple checkpoints or a checkpoint
                // and an assume valid header inside of the presented list of headers, we would only be interested in the last
                // one as it would cover all previous headers. Reversing the order of processing guarantees that we only need
                // to deal with one special header, which simplifies the implementation.
                while (currentChainedHeader != earliestNewHeader)
                {
                    if (currentChainedHeader.HashBlock == this.consensusSettings.BlockAssumedValid)
                    {
                        this.logger.LogDebug("Chained header '{0}' represents an assumed valid block.", currentChainedHeader);

                        connectNewHeadersResult = this.HandleAssumedValidHeader(currentChainedHeader, latestNewHeader, isBelowLastCheckpoint);
                        break;
                    }

                    CheckpointInfo checkpoint = this.checkpoints.GetCheckpoint(currentChainedHeader.Height);
                    if (checkpoint != null)
                    {
                        this.logger.LogDebug("Chained header '{0}' is a checkpoint.", currentChainedHeader);

                        connectNewHeadersResult = this.HandleCheckpointsHeader(currentChainedHeader, latestNewHeader, checkpoint);
                        break;
                    }

                    currentChainedHeader = currentChainedHeader.Previous;
                }

                if ((connectNewHeadersResult == null) && isBelowLastCheckpoint)
                {
                    connectNewHeadersResult = new ConnectNewHeadersResult()
                    {
                        Consumed = latestNewHeader
                    };
                    this.logger.LogTrace("Chained header '{0}' below last checkpoint.", currentChainedHeader);
                }

                if (connectNewHeadersResult != null)
                {
                    this.logger.LogTrace("(-)[CHECKPOINT_OR_ASSUMED_VALID]:{0}", connectNewHeadersResult);
                    return(connectNewHeadersResult);
                }
            }

            if (latestNewHeader.ChainWork > this.GetConsensusTip().ChainWork)
            {
                this.logger.LogDebug("Chained header '{0}' is the tip of a chain with more work than our current consensus tip.", latestNewHeader);

                connectNewHeadersResult = this.MarkBetterChainAsRequired(latestNewHeader);
            }

            this.logger.LogTrace("(-):{0}", connectNewHeadersResult);
            return(connectNewHeadersResult);
        }
Esempio n. 7
0
        private async Task ProcessMessagesRunAsync(CancellationToken cancelToken)
        {
            var operation         = nameof(this.ProcessMessagesRunAsync);
            var runStartTimestamp = DateTime.UtcNow;

            var offset = await this.messageQueue.GetCheckpointedRecordInfoAsync();

            if (offset.Index == RecordInfo.InvalidIndex)
            {
                offset         = offset.Next();
                this.inclusive = true;
            }
            else
            {
                this.inclusive = false;
            }

            var fabricErrorsStartedTimestamp = DateTime.Now;
            var fabricErrorsStarted          = false;

            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".Read", OperationStates.Starting, $"requestOffset: {offset}, inclusive: {inclusive}");
            while (!cancelToken.IsCancellationRequested)
            {
                var pumpStartTimestamp = DateTime.UtcNow;

                try
                {
                    IReadOnlyList <Record <TMessage> > readResult = null;

                    readResult = await this.messageQueue.ReadAsync(
                        offset,
                        this.setting.PartitionSetting.MessagePumpBatchSize,
                        this.inclusive,
                        ReadTimeout,
                        cancelToken);

                    if (readResult == null || readResult.Count == 0)
                    {
                        MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".Read", OperationStates.Succeeded, $"requestOffset: {offset}, inclusive: {inclusive}, resultOffset: NULL, resultMessageCount: 0");
                    }
                    else
                    {
                        var inputMessages = readResult.Select(r => r.Item).ToList();

                        MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".Read", OperationStates.Succeeded, $"requestOffset: {offset}, inclusive: {inclusive}, resultOffset: {readResult[readResult.Count - 1].RecordInfo.Index}, resultMessageCount: {inputMessages.Count}");

                        if (this.inclusive == true)
                        {
                            this.inclusive = false;
                        }

                        IList <OutputMessage> filteredEvents;

                        try
                        {
                            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".Filter", OperationStates.Starting, $"inputEventCount: {inputMessages.Count}");
                            filteredEvents = await this.filteringEngine.FilterAsync(inputMessages, cancelToken);

                            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".Filter", OperationStates.Succeeded, $"outputEventCount: {filteredEvents.Count}");
                        }
                        catch (Exception ex)
                        {
                            MessageDispatcherEventSource.Current.ErrorException(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".Filter", OperationStates.Failed, string.Empty, ex);
                            throw;
                        }

                        var checkpointInfo = new CheckpointInfo(readResult[0].RecordInfo, readResult[readResult.Count - 1].RecordInfo, inputMessages.Count);
                        this.checkpointQueue.Enqueue(checkpointInfo);

                        if (filteredEvents != null && filteredEvents.Count > 0)
                        {
                            await this.ScheduleDeliveryAsync(filteredEvents, checkpointInfo);
                        }
                        else
                        {
                            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation + ".ScheduleDelivery", OperationStates.Skipping, string.Empty);
                            checkpointInfo.Tcs.SetResult(true);
                        }

                        offset = checkpointInfo.LastRecordInfo;
                    }

                    fabricErrorsStarted = false;
                }
                catch (Exception ex)
                {
                    var runStartElapsed  = runStartTimestamp - DateTime.UtcNow;
                    var pumpStartElapsed = pumpStartTimestamp - DateTime.UtcNow;

                    if (runStartElapsed < MinimumRunDurationBeforeFaulting || !ex.IsFabricCriticalException())
                    {
                        fabricErrorsStarted = false;
                        MessageDispatcherEventSource.Current.Warning(MessageDispatcherEventSource.EmptyTrackingId, this, operation, OperationStates.Failed, $"runStartElapsed={runStartElapsed} pumpStartElapsed={pumpStartElapsed} Waiting for={UnhandledExceptionDelay.TotalMilliseconds} ms Ex={ex.ToString()}");
                        await TaskHelper.TryDelay(UnhandledExceptionDelay, cancelToken);
                    }
                    else
                    {
                        var fabricErrorsStartedElapsed = fabricErrorsStartedTimestamp - DateTime.UtcNow;
                        var faultMessage = $"MessagePump encountered a critical fabric exception. FabricErrorsStartedElapsed={fabricErrorsStartedElapsed} (Threshold={FabricExceptionsDurationBeforeFaulting}) AND runStartElapsed={runStartElapsed} (Threshold={MinimumRunDurationBeforeFaulting}) pumpStartElapsed={pumpStartElapsed}";

                        if (!fabricErrorsStarted)
                        {
                            fabricErrorsStarted          = true;
                            fabricErrorsStartedTimestamp = DateTime.UtcNow;
                            MessageDispatcherEventSource.Current.Warning(MessageDispatcherEventSource.EmptyTrackingId, this, operation, OperationStates.FailedNotFaulting, faultMessage + $" ex={ex.ToString()}");
                        }
                        else
                        {
                            if (runStartElapsed > MinimumRunDurationBeforeFaulting &&
                                fabricErrorsStartedElapsed > FabricExceptionsDurationBeforeFaulting)
                            {
                                MessageDispatcherEventSource.Current.Error(MessageDispatcherEventSource.EmptyTrackingId, this, operation, OperationStates.Faulting, faultMessage + $" ex={ex.ToString()}");
                                this.FaultPump(faultMessage, ex);
                            }
                            else
                            {
                                MessageDispatcherEventSource.Current.Warning(MessageDispatcherEventSource.EmptyTrackingId, this, operation, OperationStates.FailedNotFaulting, faultMessage + $" ex={ex.ToString()}");
                            }
                        }
                    }
                }
            }

            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, operation, OperationStates.Succeeded, $"requestOffset: {offset}, inclusive: {inclusive}");
        }
Esempio n. 8
0
        private async Task ScheduleDeliveryAsync(IList <OutputMessage> outputMessages, CheckpointInfo checkpointInfo)
        {
            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, nameof(this.ScheduleDeliveryAsync), OperationStates.Starting, $"outputMessageCount: {outputMessages.Count}, checkpointInfo: {checkpointInfo}");
            var deliverTask = await this.messageDispatcher.DispatchAsync(outputMessages).ConfigureAwait(false);

            MessageDispatcherEventSource.Current.Info(MessageDispatcherEventSource.EmptyTrackingId, this, nameof(this.ScheduleDeliveryAsync), OperationStates.Succeeded, $"outputMessageCount: {outputMessages.Count}, checkpointInfo: {checkpointInfo}");

            this.CompleteScheduleDeliveryAsync(deliverTask, checkpointInfo).Fork();
        }