Esempio n. 1
0
        public void Idempotent()
        {
            // NOTE: This test checks that blocks can be evaluated idempotently. Also it checks
            // the action results in pre-evaluation step and in evaluation step are equal.
            const int repeatCount = 2;
            var       signer      = new PrivateKey();
            var       timestamp   = DateTimeOffset.UtcNow;
            var       txAddress   = signer.ToAddress();
            var       txs         = new[]
            {
                Transaction <RandomAction> .Create(
                    nonce : 0,
                    privateKey : signer,
                    genesisHash : null,
                    actions : new[] { new RandomAction(txAddress), }),
            };
            var stateStore = new TrieStateStore(new MemoryKeyValueStore());
            HashAlgorithmGetter hashAlgorithmGetter            = _ => HashAlgorithmType.Of <SHA256>();
            PreEvaluationBlock <RandomAction> noStateRootBlock = MineGenesis(
                hashAlgorithmGetter: hashAlgorithmGetter,
                miner: GenesisMiner.PublicKey,
                timestamp: timestamp,
                transactions: txs
                );
            Block <RandomAction> stateRootBlock =
                noStateRootBlock.Evaluate(GenesisMiner, null, stateStore);
            var actionEvaluator =
                new ActionEvaluator <RandomAction>(
                    hashAlgorithmGetter: hashAlgorithmGetter,
                    policyBlockAction: null,
                    stateGetter: ActionEvaluator <RandomAction> .NullStateGetter,
                    balanceGetter: ActionEvaluator <RandomAction> .NullBalanceGetter,
                    trieGetter: null);
            var generatedRandomNumbers = new List <int>();

            AssertPreEvaluationBlocksEqual(stateRootBlock, noStateRootBlock);

            for (int i = 0; i < repeatCount; ++i)
            {
                var actionEvaluations = actionEvaluator.Evaluate(
                    noStateRootBlock,
                    StateCompleterSet <RandomAction> .Reject);
                generatedRandomNumbers.Add(
                    (Integer)actionEvaluations[0].OutputStates.GetState(txAddress));
                actionEvaluations = actionEvaluator.Evaluate(
                    stateRootBlock,
                    StateCompleterSet <RandomAction> .Reject);
                generatedRandomNumbers.Add(
                    (Integer)actionEvaluations[0].OutputStates.GetState(txAddress));
            }

            for (int i = 1; i < generatedRandomNumbers.Count; ++i)
            {
                Assert.Equal(generatedRandomNumbers[0], generatedRandomNumbers[i]);
            }
        }
Esempio n. 2
0
        internal void RenderFastForward(
            bool render,
            Block <T> oldTip,
            Block <T> newTip,
            Block <T> branchpoint,
            IReadOnlyList <Block <T> > fastForwardPath,
            StateCompleterSet <T> stateCompleters)
        {
            if (render && ActionRenderers.Any())
            {
                _logger.Debug("Rendering actions in new chain.");

                long count = 0;
                foreach (Block <T> block in fastForwardPath)
                {
                    ImmutableList <ActionEvaluation> evaluations =
                        ActionEvaluator.Evaluate(block, stateCompleters).ToImmutableList();

                    count += RenderActions(
                        evaluations: evaluations,
                        block: block,
                        stateCompleters: stateCompleters);
                }

                _logger.Debug(
                    $"{nameof(Swap)}() completed rendering {{Count}} actions.",
                    count);

                foreach (IActionRenderer <T> renderer in ActionRenderers)
                {
                    renderer.RenderBlockEnd(oldTip, newTip);
                }
            }
        }
Esempio n. 3
0
        internal void RenderRewind(
            bool render,
            Block <T> oldTip,
            Block <T> newTip,
            Block <T> branchpoint,
            IReadOnlyList <Block <T> > rewindPath,
            StateCompleterSet <T> stateCompleters)
        {
            if (render && ActionRenderers.Any())
            {
                // Unrender stale actions.
                _logger.Debug("Unrendering abandoned actions...");

                long count = 0;

                foreach (Block <T> block in rewindPath)
                {
                    ImmutableList <ActionEvaluation> evaluations =
                        ActionEvaluator.Evaluate(block, stateCompleters)
                        .ToImmutableList().Reverse();

                    count += UnrenderActions(
                        evaluations: evaluations,
                        block: block,
                        stateCompleters: stateCompleters);
                }

                _logger.Debug(
                    $"{nameof(Swap)}() completed unrendering {{Actions}} actions.",
                    count);
            }
        }
Esempio n. 4
0
        internal long RenderActions(
            IReadOnlyList <ActionEvaluation> evaluations,
            Block <T> block,
            StateCompleterSet <T> stateCompleters)
        {
            DateTimeOffset startTime = DateTimeOffset.UtcNow;

            _logger.Debug(
                "Rendering actions in block #{BlockIndex} {BlockHash}...",
                block.Index,
                block.Hash);

            if (evaluations is null)
            {
                evaluations = ActionEvaluator.Evaluate(block, stateCompleters);
            }

            long count = 0;

            foreach (var evaluation in evaluations)
            {
                foreach (IActionRenderer <T> renderer in ActionRenderers)
                {
                    if (evaluation.Exception is null)
                    {
                        renderer.RenderAction(
                            evaluation.Action,
                            evaluation.InputContext.GetUnconsumedContext(),
                            evaluation.OutputStates);
                    }
                    else
                    {
                        renderer.RenderActionError(
                            evaluation.Action,
                            evaluation.InputContext.GetUnconsumedContext(),
                            evaluation.Exception);
                    }

                    count++;
                }
            }

            TimeSpan renderDuration = DateTimeOffset.Now - startTime;

            _logger
            .ForContext("Tag", "Metric")
            .ForContext("Subtag", "BlockRenderDuration")
            .Debug(
                "Finished rendering {RenderCount} renders for actions in " +
                "block #{BlockIndex} {BlockHash} in {DurationMs:F0}ms.",
                count,
                block.Index,
                block.Hash,
                renderDuration.TotalMilliseconds);
            return(count);
        }
Esempio n. 5
0
        internal long UnrenderActions(
            IReadOnlyList <ActionEvaluation> evaluations,
            Block <T> block,
            StateCompleterSet <T> stateCompleters)
        {
            _logger.Debug(
                "Unrender actions in block #{BlockIndex} {BlockHash}", block?.Index, block?.Hash);

            if (evaluations is null)
            {
                evaluations =
                    ActionEvaluator.Evaluate(block, stateCompleters)
                    .Reverse().ToImmutableList();
            }

            long count = 0;

            foreach (ActionEvaluation evaluation in evaluations)
            {
                foreach (IActionRenderer <T> renderer in ActionRenderers)
                {
                    if (evaluation.Exception is null)
                    {
                        renderer.UnrenderAction(
                            evaluation.Action,
                            evaluation.InputContext.GetUnconsumedContext(),
                            evaluation.OutputStates);
                    }
                    else
                    {
                        renderer.UnrenderActionError(
                            evaluation.Action,
                            evaluation.InputContext.GetUnconsumedContext(),
                            evaluation.Exception);
                    }
                }

                count++;
            }

            return(count);
        }
Esempio n. 6
0
        /// <summary>
        /// Render actions of the given <paramref name="block"/>.
        /// </summary>
        /// <param name="evaluations"><see cref="ActionEvaluation"/>s of the block.  If it is
        /// <c>null</c>, evaluate actions of the <paramref name="block"/> again.</param>
        /// <param name="block"><see cref="Block{T}"/> to render actions.</param>
        /// <param name="stateCompleters">The strategy to complement incomplete block states.
        /// <see cref="StateCompleterSet{T}.Recalculate"/> by default.</param>
        /// <returns>The number of actions rendered.</returns>
        internal long RenderActions(
            IReadOnlyList <ActionEvaluation> evaluations,
            Block <T> block,
            StateCompleterSet <T> stateCompleters)
        {
            _logger.Debug("Render actions in block {blockIndex}: {block}", block?.Index, block);

            if (evaluations is null)
            {
                evaluations = ActionEvaluator.Evaluate(block, stateCompleters);
            }

            long count = 0;

            foreach (var evaluation in evaluations)
            {
                foreach (IActionRenderer <T> renderer in ActionRenderers)
                {
                    if (evaluation.Exception is null)
                    {
                        renderer.RenderAction(
                            evaluation.Action,
                            evaluation.InputContext.GetUnconsumedContext(),
                            evaluation.OutputStates);
                    }
                    else
                    {
                        renderer.RenderActionError(
                            evaluation.Action,
                            evaluation.InputContext.GetUnconsumedContext(),
                            evaluation.Exception);
                    }

                    count++;
                }
            }

            return(count);
        }
        /// <summary>
        /// Recalculates and complements all <i>missing</i> block states including and upto given
        /// <paramref name="blockHash"/> starting from the genesis block.
        /// </summary>
        /// <param name="blockHash">The inclusive limit of target hash to terminate complementation.
        /// </param>
        /// <remarks>
        /// <para>
        /// If a complementation of the entire blockchain is needed, call with the tip hash of the
        /// <see cref="BlockChain{T}"/>.
        /// </para>
        /// <para>
        /// Unlike <see cref="RecalculateBlockStates"/>, this method skips recalculations if states
        /// are found for intermediate blocks. This may not be fully secure if states for
        /// blocks in <see cref="IStateStore"/> are somehow corrupted.
        /// </para>
        /// </remarks>
        internal void ComplementAllBlockStates(BlockHash blockHash)
        {
            _logger.Verbose("Complementing all block states upto {BlockHash}...", blockHash);

            // Prevent recursive trial to recalculate & complement incomplete block states by
            // mistake; if the below code works as intended, these state completers must never
            // be invoked.
            StateCompleterSet <T> stateCompleters = StateCompleterSet <T> .Reject;

            // Calculates and fills the incomplete states on the fly.
            foreach (BlockHash hash in BlockHashes)
            {
                Block <T> block = this[hash];
                if (StateStore.ContainsStateRoot(block.StateRootHash))
                {
                    continue;
                }

                IReadOnlyList <ActionEvaluation> evaluations = ActionEvaluator.Evaluate(
                    block,
                    stateCompleters);

                _rwlock.EnterWriteLock();
                try
                {
                    SetStates(block, evaluations);
                }
                finally
                {
                    _rwlock.ExitWriteLock();
                }

                if (blockHash.Equals(hash))
                {
                    break;
                }
            }
        }