Exemplo n.º 1
0
        // FIXME it's very dangerous because replacing Id means
        // ALL blocks (referenced by MineBlock(), etc.) will be changed.
        // we need to add a synchronization mechanism to handle this correctly.
        internal void Swap(BlockChain <T> other)
        {
            // Finds the branch point.
            Block <T> topmostCommon = null;
            long      shorterHeight =
                Math.Min(this.LongCount(), other.LongCount()) - 1;

            for (
                Block <T> t = this[shorterHeight], o = other[shorterHeight];
                t.PreviousHash is HashDigest <SHA256> tp &&
                o.PreviousHash is HashDigest <SHA256> op;
                t = Blocks[tp], o = other.Blocks[op]
                )
            {
                if (t.Equals(o))
                {
                    topmostCommon = t;
                    break;
                }
            }

            // Unrender stale actions.
            for (
                Block <T> b = Tip;
                !(b is null) && b.Index > (topmostCommon?.Index ?? -1) &&
                b.PreviousHash is HashDigest <SHA256> ph;
                b = Blocks[ph]
                )
            {
                var actions = b.EvaluateActionsPerTx(a =>
                                                     GetStates(new[] { a }, b.PreviousHash).GetValueOrDefault(a)
                                                     ).Reverse();
                foreach (var(_, evaluation) in actions)
                {
                    evaluation.Action.Unrender(
                        evaluation.InputContext,
                        evaluation.OutputStates
                        );
                }
            }

            try
            {
                _rwlock.EnterWriteLock();

                Id           = other.Id;
                Blocks       = new BlockSet <T>(Store);
                Transactions = new TransactionSet <T>(Store);
            }
            finally
            {
                _rwlock.ExitWriteLock();
            }

            // Render actions that had been behind.
            IEnumerable <Block <T> > blocksToRender =
                topmostCommon is Block <T> branchPoint
                    ? this.SkipWhile(b => b.Index <= branchPoint.Index)
                    : this;

            foreach (Block <T> b in blocksToRender)
            {
                var actions = b.EvaluateActionsPerTx(a =>
                                                     GetStates(new[] { a }, b.PreviousHash).GetValueOrDefault(a)
                                                     );
                foreach (var(_, evaluation) in actions)
                {
                    evaluation.Action.Render(
                        evaluation.InputContext,
                        evaluation.OutputStates
                        );
                }
            }
        }
Exemplo n.º 2
0
        // FIXME it's very dangerous because replacing Id means
        // ALL blocks (referenced by MineBlock(), etc.) will be changed.
        // we need to add a synchronization mechanism to handle this correctly.
        internal void Swap(BlockChain <T> other, bool render)
        {
            // Finds the branch point.
            Block <T> topmostCommon = null;

            if (render && !(Tip is null || other.Tip is null))
            {
                long shorterHeight =
                    Math.Min(this.LongCount(), other.LongCount()) - 1;
                for (
                    Block <T> t = this[shorterHeight], o = other[shorterHeight];
                    t.PreviousHash is HashDigest <SHA256> tp &&
                    o.PreviousHash is HashDigest <SHA256> op;
                    t = Blocks[tp], o = other.Blocks[op]
                    )
                {
                    if (t.Equals(o))
                    {
                        topmostCommon = t;
                        break;
                    }
                }
            }

            if (render)
            {
                // Unrender stale actions.
                for (
                    Block <T> b = Tip;
                    !(b is null) && b.Index > (topmostCommon?.Index ?? -1) &&
                    b.PreviousHash is HashDigest <SHA256> ph;
                    b = Blocks[ph]
                    )
                {
                    List <ActionEvaluation> evaluations = b.EvaluateActionsPerTx(a =>
                                                                                 GetStates(new[] { a }, b.PreviousHash).GetValueOrDefault(a))
                                                          .Select(te => te.Item2).ToList();

                    if (Policy.BlockAction is IAction)
                    {
                        evaluations.Add(EvaluateBlockAction(b, evaluations));
                    }

                    evaluations.Reverse();

                    foreach (var evaluation in evaluations)
                    {
                        evaluation.Action.Unrender(
                            evaluation.InputContext,
                            evaluation.OutputStates
                            );
                    }
                }
            }

            try
            {
                _rwlock.EnterWriteLock();

                var tipChangedEventArgs = new TipChangedEventArgs
                {
                    PreviousHash  = Tip?.Hash,
                    PreviousIndex = Tip?.Index,
                    Hash          = other.Tip.Hash,
                    Index         = other.Tip.Index,
                };
                Guid obsoleteId = Id;
                Id = other.Id;
                Store.SetCanonicalChainId(Id);
                Blocks = new BlockSet <T>(Store);
                TipChanged?.Invoke(this, tipChangedEventArgs);
                Transactions = new TransactionSet <T>(Store);
                Store.DeleteChainId(obsoleteId);
            }
            finally
            {
                _rwlock.ExitWriteLock();
            }

            if (render)
            {
                // Render actions that had been behind.
                IEnumerable <Block <T> > blocksToRender =
                    topmostCommon is Block <T> branchPoint
                        ? this.SkipWhile(b => b.Index <= branchPoint.Index)
                        : this;

                foreach (Block <T> b in blocksToRender)
                {
                    List <ActionEvaluation> evaluations = b.EvaluateActionsPerTx(a =>
                                                                                 GetStates(new[] { a }, b.PreviousHash).GetValueOrDefault(a))
                                                          .Select(te => te.Item2).ToList();

                    if (Policy.BlockAction is IAction)
                    {
                        evaluations.Add(EvaluateBlockAction(b, evaluations));
                    }

                    foreach (var evaluation in evaluations)
                    {
                        evaluation.Action.Render(
                            evaluation.InputContext,
                            evaluation.OutputStates
                            );
                    }
                }
            }
        }
Exemplo n.º 3
0
        // FIXME it's very dangerous because replacing Id means
        // ALL blocks (referenced by MineBlock(), etc.) will be changed.
        // we need to add a synchronization mechanism to handle this correctly.
        internal void Swap(BlockChain <T> other, bool render)
        {
            _logger.Debug(
                "Swaping block chain. (from: {fromChainId}) (to: {toChainId})", Id, other.Id);

            // Finds the branch point.
            Block <T> topmostCommon = null;

            if (render && !(Tip is null || other.Tip is null))
            {
                long shorterHeight =
                    Math.Min(LongCount(), other.LongCount()) - 1;
                for (
                    Block <T> t = this[shorterHeight], o = other[shorterHeight];
                    t.PreviousHash is HashDigest <SHA256> tp &&
                    o.PreviousHash is HashDigest <SHA256> op;
                    t = this[tp], o = other[op]
                    )
                {
                    if (t.Equals(o))
                    {
                        topmostCommon = t;
                        break;
                    }
                }
            }

            _logger.Debug(
                "Branchpoint is {branchPoint} (at {index})", topmostCommon, topmostCommon?.Index);

            if (render)
            {
                _logger.Debug("Unrendering abandoned actions...");

                // Unrender stale actions.
                for (
                    Block <T> b = Tip;
                    !(b is null) && b.Index > (topmostCommon?.Index ?? -1) &&
                    b.PreviousHash is HashDigest <SHA256> ph;
                    b = this[ph]
                    )
                {
                    List <ActionEvaluation> evaluations = b.EvaluateActionsPerTx(a =>
                                                                                 GetState(a, b.PreviousHash).GetValueOrDefault(a))
                                                          .Select(te => te.Item2).ToList();

                    if (Policy.BlockAction is IAction)
                    {
                        evaluations.Add(EvaluateBlockAction(b, evaluations));
                    }

                    evaluations.Reverse();

                    foreach (var evaluation in evaluations)
                    {
                        _logger.Debug("Unrender action {action}", evaluation.Action);
                        evaluation.Action.Unrender(
                            evaluation.InputContext,
                            evaluation.OutputStates
                            );
                    }
                }

                _logger.Debug($"Unrender for {nameof(Swap)}() is completed.");
            }

            try
            {
                _rwlock.EnterWriteLock();

                var tipChangedEventArgs = new TipChangedEventArgs
                {
                    PreviousHash  = Tip?.Hash,
                    PreviousIndex = Tip?.Index,
                    Hash          = other.Tip.Hash,
                    Index         = other.Tip.Index,
                };
                Guid obsoleteId = Id;
                Id = other.Id;
                Store.SetCanonicalChainId(Id);
                _blocks = new BlockSet <T>(Store);
                TipChanged?.Invoke(this, tipChangedEventArgs);
                _transactions = new TransactionSet <T>(Store);
                Store.DeleteChainId(obsoleteId);
            }
            finally
            {
                _rwlock.ExitWriteLock();
            }

            if (render)
            {
                _logger.Debug("Rendering actions in new chain");

                // Render actions that had been behind.
                long startToRenderIndex = topmostCommon is Block <T> branchPoint
                    ? branchPoint.Index + 1
                    : 0;

                RenderBlocks(startToRenderIndex);
                _logger.Debug($"Render for {nameof(Swap)}() is completed.");
            }
        }