Example #1
0
        public virtual void BlocksBeingAppended()
        {
            var  blockLogs     = new List <(Block <DumbAction> OldTip, Block <DumbAction> NewTip)>();
            uint reorgs        = 0;
            var  innerRenderer = new AnonymousRenderer <DumbAction>
            {
                BlockRenderer = (oldTip, newTip) => blockLogs.Add((oldTip, newTip)),
                ReorgRenderer = (oldTip, newTip, bp) =>
                {
                    // Note that this callback should not be invoked in this test case.
                    reorgs++;
                },
            };
            var renderer = new DelayedRenderer <DumbAction>(
                innerRenderer,
                _canonicalChainComparer,
                _store,
                _ => HashAlgorithmType.Of <SHA256>(),  // thunk getter; doesn't matter here
                confirmations: 3
                );

            Assert.Null(renderer.Tip);
            Assert.Empty(blockLogs);
            Assert.Equal(0U, reorgs);

            // #0 -> 1 confirm; #1 -> no confirms; #2 -> no confirms
            renderer.RenderBlock(_chainA[0], _chainA[1]);
            Assert.Null(renderer.Tip);
            Assert.Empty(blockLogs);
            Assert.Equal(0U, reorgs);

            // #0 -> 2 confirms; #1 -> 1 confirm; #2 -> no confirms
            renderer.RenderBlock(_chainA[1], _chainA[2]);
            Assert.Null(renderer.Tip);
            Assert.Empty(blockLogs);
            Assert.Equal(0U, reorgs);

            // #0 -> 3 confirms; #1 -> 2 confirms; #2 -> 1 confirm; tip changed -> #0
            renderer.RenderBlock(_chainA[2], _chainA[3]);
            Assert.Equal(_chainA[0], renderer.Tip);
            Assert.Empty(blockLogs);
            Assert.Equal(0U, reorgs);

            // #0 -> gone; #1 -> 3 confirms; #2 -> 2 confirms; tip changed -> #1; render(#0, #1)
            renderer.RenderBlock(_chainA[3], _chainA[4]);
            Assert.Equal(_chainA[1], renderer.Tip);
            Assert.Single(blockLogs);
            Assert.Equal((_chainA[0], _chainA[1]), blockLogs[0]);
            Assert.Equal(0U, reorgs);

            // #0 -> gone; #1 -> gone; #2 -> 3 confirms; tip changed -> #2; render(#1, #2)
            renderer.RenderBlock(_chainA[4], _chainA[5]);
            Assert.Equal(_chainA[2], renderer.Tip);
            Assert.Equal(2, blockLogs.Count);
            Assert.Equal((_chainA[0], _chainA[1]), blockLogs[0]);
            Assert.Equal((_chainA[1], _chainA[2]), blockLogs[1]);
            Assert.Equal(0U, reorgs);
        }
Example #2
0
 public BlockChainService(
     BlockChain <NCAction> blockChain,
     Swarm <NCAction> swarm,
     RpcContext context,
     LibplanetNodeServiceProperties <NCAction> libplanetNodeServiceProperties
     )
 {
     _blockChain      = blockChain;
     _delayedRenderer = blockChain.GetDelayedRenderer();
     _swarm           = swarm;
     _context         = context;
     _codec           = new Codec();
     _libplanetNodeServiceProperties = libplanetNodeServiceProperties;
 }
Example #3
0
 public BlockChainService(
     BlockChain <NineChroniclesActionType> blockChain,
     Swarm <NineChroniclesActionType> swarm,
     RpcContext context,
     LibplanetNodeServiceProperties <NineChroniclesActionType> libplanetNodeServiceProperties
     )
 {
     _blockChain      = blockChain;
     _delayedRenderer = blockChain.Renderers
                        .OfType <DelayedRenderer <NineChroniclesActionType> >()
                        .FirstOrDefault();
     _swarm   = swarm;
     _context = context;
     _codec   = new Codec();
     _libplanetNodeServiceProperties = libplanetNodeServiceProperties;
 }
Example #4
0
        public virtual void BlocksBeingAppendedInParallel()
        {
            var blockLogs = new List <(Block <DumbAction> OldTip, Block <DumbAction> NewTip)>();
            var reorgLogs = new List <(
                                          Block <DumbAction> OldTip,
                                          Block <DumbAction> NewTip,
                                          Block <DumbAction> Branchpoint
                                          )>();
            var innerRenderer = new AnonymousRenderer <DumbAction>
            {
                BlockRenderer = (oldTip, newTip) => blockLogs.Add((oldTip, newTip)),
                ReorgRenderer = (oldTip, newTip, bp) => reorgLogs.Add((oldTip, newTip, bp)),
            };
            var delayedRenderer = new DelayedRenderer <DumbAction>(
                innerRenderer,
                _canonicalChainComparer,
                _store,
                confirmations: 3
                );
            var renderer = new LoggedRenderer <DumbAction>(
                delayedRenderer,
                _logger,
                LogEventLevel.Verbose
                );

            Assert.Null(delayedRenderer.Tip);
            Assert.Empty(blockLogs);
            Assert.Empty(reorgLogs);

            // Some explanation on the fixture: there are two chains that shares a certain block
            // as a branchpoint: _chainA and _chainB.  The topmost mutual block, i.e., branchpoint,
            // between _chainA and _chainB is _chainA[4] (== _chainB[4]).
            // In this test, we tries to simulate blocks from two parallel chains being "appended"
            // (discovered) to a peer.  The order of discovery can be drawn as below (the prime
            // [apostrophe] after the block index number like #N' shows it's from _chainB; the bare
            // block index without that like #N means it's from _chainA):
            //
            //          #4 (1st)
            //            |
            //          /   \
            //    #5 (2nd)  #5' (3rd)
            //        |       |
            //    #6 (3rd)  #6' (4th)
            //        |       |
            //    #7 (5th)  #7' (6th)
            //        |       |
            //    #8 (7th)  #8' (8th)
            //                |
            //              #9' (9th)

            // #4  -> 1 confirm
            // #5  -> no confirms
            // #5' -> no confirms
            renderer.RenderBlock(_chainA[4], _chainA[5]);
            var expectedBlockLogs = new List <(Block <DumbAction> OldTip, Block <DumbAction> NewTip)>
            {
                (_chainA[1], _chainA[2]),
            };

            Assert.Equal(_chainA[2], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // #4  -> 1 confirms
            // #5  -> no confirms
            // #5' -> no confirms
            renderer.RenderReorg(_chainA[5], _chainB[5], _branchpoint);
            renderer.RenderBlock(_chainA[5], _chainB[5]);
            renderer.RenderReorgEnd(_chainA[5], _chainB[5], _branchpoint);
            Assert.Equal(_chainA[2], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // #4  -> 2 confirms; tip changed -> #3
            // #5  -> 1 confirm;  #6 -> no confirm
            // #5' -> no confirms
            renderer.RenderReorg(_chainB[5], _chainA[6], _branchpoint);
            renderer.RenderBlock(_chainB[5], _chainA[6]);
            renderer.RenderReorgEnd(_chainB[5], _chainA[6], _branchpoint);
            expectedBlockLogs.Add((_chainA[2], _chainA[3]));
            Assert.Equal(_chainA[3], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // #4  -> 2 confirms
            // #5  -> 1 confirm; #6  -> no confirm
            // #5' -> 1 confirm; #6' -> no confirm
            renderer.RenderReorg(_chainA[6], _chainB[6], _branchpoint);
            renderer.RenderBlock(_chainA[6], _chainB[6]);
            renderer.RenderReorgEnd(_chainA[6], _chainB[6], _branchpoint);
            Assert.Equal(_chainA[3], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // #4  -> 3 confirms; tip changed -> #4
            // #5  -> 2 confirms; #6  -> 1 confirm; #7 -> no confirm
            // #5' -> 1 confirm;  #6' -> no confirm
            renderer.RenderReorg(_chainB[6], _chainA[7], _branchpoint);
            renderer.RenderBlock(_chainB[6], _chainA[7]);
            renderer.RenderReorgEnd(_chainB[6], _chainA[7], _branchpoint);
            expectedBlockLogs.Add((_chainA[3], _chainA[4]));
            Assert.Equal(_chainA[4], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // #4  -> gone but still is tip
            // #5  -> 2 confirms; #6  -> 1 confirm; #7  -> no confirm
            // #5' -> 2 confirms; #6' -> 1 confirm; #7' -> no confirm
            renderer.RenderReorg(_chainA[7], _chainB[7], _branchpoint);
            renderer.RenderBlock(_chainA[7], _chainB[7]);
            renderer.RenderReorgEnd(_chainA[7], _chainB[7], _branchpoint);
            Assert.Equal(_chainA[4], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // #4  -> gone; tip changed -> #5; render(#4, #5)
            // #5  -> 3 confirms; #6  -> 2 confirms; #7  -> 1 confirm; #8 -> no confirm
            // #5' -> 2 confirms; #6' -> 1 confirm;  #7' -> no confirm
            renderer.RenderReorg(_chainB[7], _chainA[8], _branchpoint);
            renderer.RenderBlock(_chainB[7], _chainA[8]);
            renderer.RenderReorgEnd(_chainB[7], _chainA[8], _branchpoint);
            expectedBlockLogs.Add((_chainA[4], _chainA[5]));
            Assert.Equal(_chainA[5], delayedRenderer.Tip);
            Assert.Empty(reorgLogs);
            Assert.Equal(expectedBlockLogs, blockLogs);

            // tip changed -> #5'; render(#5, #5'); reorg(#5, #5', #4)
            // #5  -> 3 confirms; #6  -> 2 confirms; #7  -> 1 confirm; #8  -> no confirm
            // #5' -> 3 confirms; #6' -> 2 confirms; #7' -> 1 confirm; #8' -> no confirm
            renderer.RenderReorg(_chainA[8], _chainB[8], _branchpoint);
            renderer.RenderBlock(_chainA[8], _chainB[8]);
            renderer.RenderReorgEnd(_chainA[8], _chainB[8], _branchpoint);
            expectedBlockLogs.Add((_chainA[5], _chainB[5]));
            Assert.Equal(_chainB[5], delayedRenderer.Tip);
            Assert.Equal(new[] { (_chainA[5], _chainB[5], _branchpoint) }, reorgLogs);
        public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration configuration)
        {
            bool useSecretToken = configuration[GraphQLService.SecretTokenKey] is { };

            Field <NonNullGraphType <StateQuery> >(name: "stateQuery", arguments: new QueryArguments(
                                                       new QueryArgument <ByteStringType>
            {
                Name        = "hash",
                Description = "Offset block hash for query.",
            }),
                                                   resolve: context =>
            {
                BlockHash?blockHash = context.GetArgument <byte[]>("hash") switch
                {
                    byte[] bytes => new BlockHash(bytes),
                    null => null,
                };

                if (standaloneContext.BlockChain is { } blockChain)
                {
                    DelayedRenderer <NCAction>?delayedRenderer = blockChain.GetDelayedRenderer();
                    blockHash = delayedRenderer?.Tip?.Hash;
                }

                return(standaloneContext.BlockChain?.ToAccountStateGetter(blockHash),
                       standaloneContext.BlockChain?.ToAccountBalanceGetter(blockHash));
            }
                                                   );

            Field <ByteStringType>(
                name: "state",
                arguments: new QueryArguments(
                    new QueryArgument <NonNullGraphType <AddressType> > {
                Name = "address", Description = "The address of state to fetch from the chain."
            },
                    new QueryArgument <ByteStringType> {
                Name = "hash", Description = "The hash of the block used to fetch state from chain."
            }
                    ),
                resolve: context =>
            {
                if (!(standaloneContext.BlockChain is BlockChain <PolymorphicAction <ActionBase> > blockChain))
                {
                    throw new ExecutionError(
                        $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!");
                }

                var address            = context.GetArgument <Address>("address");
                var blockHashByteArray = context.GetArgument <byte[]>("hash");
                var blockHash          = blockHashByteArray is null
                        ? blockChain.Tip.Hash
                        : new BlockHash(blockHashByteArray);

                var state = blockChain.GetState(address, blockHash);

                return(new Codec().Encode(state));
            }
                );

            Field <NonNullGraphType <ListGraphType <NonNullGraphType <TransferNCGHistoryType> > > >(
                "transferNCGHistories",
                arguments: new QueryArguments(
                    new QueryArgument <NonNullGraphType <ByteStringType> >
            {
                Name = "blockHash"
            },
                    new QueryArgument <AddressType>
            {
                Name = "recipient"
            }
                    ), resolve: context =>
            {
                BlockHash blockHash = new BlockHash(context.GetArgument <byte[]>("blockHash"));

                if (!(standaloneContext.Store is { } store))
                {
                    throw new InvalidOperationException();
                }

                if (!(store.GetBlock <NCAction>(blockHash) is { } block))
                {
                    throw new ArgumentException("blockHash");
                }

                var recipient = context.GetArgument <Address?>("recipient");

                var filteredTransactions = block.Transactions.Where(tx =>
                                                                    tx.Actions.Count == 1 &&
                                                                    tx.Actions.First().InnerAction is TransferAsset transferAsset &&
                                                                    (!recipient.HasValue || transferAsset.Recipient == recipient) &&
                                                                    transferAsset.Amount.Currency.Ticker == "NCG" &&
                                                                    store.GetTxExecution(blockHash, tx.Id) is TxSuccess);

                TransferNCGHistory ToTransferNCGHistory(TxSuccess txSuccess, string memo)
                {
                    var rawTransferNcgHistories = txSuccess.FungibleAssetsDelta.Select(pair =>
                                                                                       (pair.Key, pair.Value.Values.First(fav => fav.Currency.Ticker == "NCG")))
                                                  .ToArray();
                    var((senderAddress, _), (recipientAddress, amount)) =
                        rawTransferNcgHistories[0].Item2.RawValue > rawTransferNcgHistories[1].Item2.RawValue
                                ? (rawTransferNcgHistories[1], rawTransferNcgHistories[0])
                                : (rawTransferNcgHistories[0], rawTransferNcgHistories[1]);
                    return(new TransferNCGHistory(
                               txSuccess.BlockHash,
                               txSuccess.TxId,
                               senderAddress,
                               recipientAddress,
                               amount,
                               memo));
                }

                var histories = filteredTransactions.Select(tx =>
                                                            ToTransferNCGHistory((TxSuccess)store.GetTxExecution(blockHash, tx.Id),
                                                                                 tx.Actions.Single().InnerAction.As <TransferAsset>().Memo));

                return(histories);
            });