public async Task <BlockExecutedSet> ExecuteBlockAsync(BlockHeader blockHeader,
                                                               IEnumerable <Transaction> nonCancellableTransactions, IEnumerable <Transaction> cancellableTransactions,
                                                               CancellationToken cancellationToken)
        {
            Logger.LogTrace("Entered ExecuteBlockAsync");
            var nonCancellable           = nonCancellableTransactions.ToList();
            var cancellable              = cancellableTransactions.ToList();
            var nonCancellableReturnSets =
                await _transactionExecutingService.ExecuteAsync(
                    new TransactionExecutingDto { BlockHeader = blockHeader, Transactions = nonCancellable },
                    CancellationToken.None);

            Logger.LogTrace("Executed non-cancellable txs");

            var returnSetCollection = new ExecutionReturnSetCollection(nonCancellableReturnSets);
            List <ExecutionReturnSet> cancellableReturnSets = new List <ExecutionReturnSet>();

            if (!cancellationToken.IsCancellationRequested && cancellable.Count > 0)
            {
                cancellableReturnSets = await _transactionExecutingService.ExecuteAsync(
                    new TransactionExecutingDto
                {
                    BlockHeader          = blockHeader,
                    Transactions         = cancellable,
                    PartialBlockStateSet = returnSetCollection.ToBlockStateSet()
                },
                    cancellationToken);

                returnSetCollection.AddRange(cancellableReturnSets);
                Logger.LogTrace("Executed cancellable txs");
            }

            var executedCancellableTransactions = new HashSet <Hash>(cancellableReturnSets.Select(x => x.TransactionId));
            var allExecutedTransactions         =
                nonCancellable.Concat(cancellable.Where(x => executedCancellableTransactions.Contains(x.GetHash())))
                .ToList();
            var blockStateSet =
                CreateBlockStateSet(blockHeader.PreviousBlockHash, blockHeader.Height, returnSetCollection);
            var block = await FillBlockAfterExecutionAsync(blockHeader, allExecutedTransactions, returnSetCollection,
                                                           blockStateSet);

            // set txn results
            var transactionResults = await SetTransactionResultsAsync(returnSetCollection, block.Header);

            // set blocks state
            blockStateSet.BlockHash = block.GetHash();
            Logger.LogTrace("Set block state set.");
            await _blockchainStateService.SetBlockStateSetAsync(blockStateSet);

            // handle execution cases
            await CleanUpReturnSetCollectionAsync(block.Header, returnSetCollection);

            return(new BlockExecutedSet
            {
                Block = block,
                TransactionMap = allExecutedTransactions.ToDictionary(p => p.GetHash(), p => p),
                TransactionResultMap = transactionResults.ToDictionary(p => p.TransactionId, p => p)
            });
        }
Esempio n. 2
0
        public async Task <Block> ExecuteBlockAsync(BlockHeader blockHeader,
                                                    IEnumerable <Transaction> nonCancellableTransactions, IEnumerable <Transaction> cancellableTransactions,
                                                    CancellationToken cancellationToken)
        {
            Logger.LogTrace("Entered ExecuteBlockAsync");
            var nonCancellable = nonCancellableTransactions.ToList();
            var cancellable    = cancellableTransactions.ToList();

            var nonCancellableReturnSets =
                await _executingService.ExecuteAsync(
                    new TransactionExecutingDto { BlockHeader = blockHeader, Transactions = nonCancellable },
                    CancellationToken.None, true);

            Logger.LogTrace("Executed non-cancellable txs");

            var returnSetCollection = new ReturnSetCollection(nonCancellableReturnSets);
            List <ExecutionReturnSet> cancellableReturnSets = new List <ExecutionReturnSet>();

            if (cancellable.Count > 0)
            {
                cancellableReturnSets = await _executingService.ExecuteAsync(
                    new TransactionExecutingDto
                {
                    BlockHeader          = blockHeader,
                    Transactions         = cancellable,
                    PartialBlockStateSet = returnSetCollection.ToBlockStateSet()
                },
                    cancellationToken, false);

                returnSetCollection.AddRange(cancellableReturnSets);
            }

            Logger.LogTrace("Executed cancellable txs");

            Logger.LogTrace("Handled return set");

            if (returnSetCollection.Unexecutable.Count > 0)
            {
                await EventBus.PublishAsync(
                    new UnexecutableTransactionsFoundEvent(blockHeader, returnSetCollection.Unexecutable));
            }

            var executed = new HashSet <Hash>(cancellableReturnSets.Select(x => x.TransactionId));
            var allExecutedTransactions =
                nonCancellable.Concat(cancellable.Where(x => executed.Contains(x.GetHash()))).ToList();
            var block = await _blockGenerationService.FillBlockAfterExecutionAsync(blockHeader, allExecutedTransactions,
                                                                                   returnSetCollection.Executed);

            Logger.LogTrace("Filled block");

            return(block);
        }
        public async Task ExecuteAsync_Test()
        {
            var chain = await BlockchainService.GetChainAsync();

            (PrepareTransactions, KeyPairs) = await OsTestHelper.PrepareTokenForParallel(10);

            Block = OsTestHelper.GenerateBlock(chain.BestChainHash, chain.BestChainHeight, PrepareTransactions);
            PrepareTransactions[0].To = SampleAccount.Accounts[0].Address;
            await OsTestHelper.BroadcastTransactions(PrepareTransactions);

            var executionReturnSets = await _transactionExecutingService.ExecuteAsync(new TransactionExecutingDto
            {
                Transactions = PrepareTransactions,
                BlockHeader  = Block.Header
            }, CancellationToken.None);

            executionReturnSets.Count.ShouldBe(PrepareTransactions.Count);
            executionReturnSets.Count(set => set.TransactionResult.Status == TransactionResultStatus.Failed)
            .ShouldBe(1);
            executionReturnSets.First(set => set.TransactionResult.Status == TransactionResultStatus.Failed).TransactionResult.Error.ShouldBe("Invalid contract address.");
            executionReturnSets.Count(set => set.TransactionResult.Status == TransactionResultStatus.Mined).ShouldBe(9);

            (PrepareTransactions, KeyPairs) = await OsTestHelper.PrepareTokenForParallel(10);

            Block = OsTestHelper.GenerateBlock(Block.GetHash(), Block.Height, PrepareTransactions);
            await OsTestHelper.BroadcastTransactions(PrepareTransactions);

            var cancelTokenSource = new CancellationTokenSource();

            cancelTokenSource.Cancel();
            executionReturnSets = await _transactionExecutingService.ExecuteAsync(new TransactionExecutingDto
            {
                Transactions = PrepareTransactions,
                BlockHeader  = Block.Header
            }, cancelTokenSource.Token);

            executionReturnSets.Count.ShouldBe(0);

            (PrepareTransactions, KeyPairs) = await OsTestHelper.PrepareTokenForParallel(10);

            Block = OsTestHelper.GenerateBlock(Block.GetHash(), Block.Height, PrepareTransactions);
            _systemTransactionExtraDataProvider.SetSystemTransactionCount(1, Block.Header);
            executionReturnSets = await _transactionExecutingService.ExecuteAsync(new TransactionExecutingDto
            {
                Transactions = PrepareTransactions,
                BlockHeader  = Block.Header
            }, CancellationToken.None);

            executionReturnSets.Count.ShouldBe(PrepareTransactions.Count);
            executionReturnSets.ShouldAllBe(set => set.TransactionResult.Status == TransactionResultStatus.Mined);
        }
Esempio n. 4
0
        internal async Task MineBlockAsync(Block block)
        {
            var transactions = block.Body.TransactionIds.Count > 0
                ? await _blockchainService.GetTransactionsAsync(block.TransactionIds)
                : new List <Transaction>();

            var executionReturnSets = await _transactionExecutingService.ExecuteAsync(new TransactionExecutingDto
            {
                BlockHeader  = block.Header,
                Transactions = transactions,
            }, CancellationToken.None);

            await _transactionResultManager.AddTransactionResultsAsync(
                executionReturnSets.Select(s => s.TransactionResult).ToList(), block.GetHash());

            var blockStateSet = new BlockStateSet
            {
                BlockHash    = block.GetHash(),
                PreviousHash = block.Header.PreviousBlockHash,
                BlockHeight  = block.Height
            };

            foreach (var stateChange in executionReturnSets.SelectMany(executionReturnSet => executionReturnSet.StateChanges))
            {
                blockStateSet.Changes[stateChange.Key] = stateChange.Value;
            }

            await _blockStateSetManger.SetBlockStateSetAsync(blockStateSet);
        }
Esempio n. 5
0
        public async Task <Block> ExecuteBlockAsync(BlockHeader blockHeader,
                                                    IEnumerable <Transaction> nonCancellableTransactions, IEnumerable <Transaction> cancellableTransactions,
                                                    CancellationToken cancellationToken)
        {
            var nonCancellable = nonCancellableTransactions.ToList();
            var cancellable    = cancellableTransactions.ToList();

            var nonCancellableReturnSets =
                await _executingService.ExecuteAsync(blockHeader, nonCancellable, CancellationToken.None, true);

            var cancellableReturnSets =
                await _executingService.ExecuteAsync(blockHeader, cancellable, cancellationToken, false);

            var blockReturnSet = new List <ExecutionReturnSet>();
            var unexecutable   = new List <Hash>();

            foreach (var returnSet in nonCancellableReturnSets.Concat(cancellableReturnSets))
            {
                if (returnSet.Status == TransactionResultStatus.Mined ||
                    returnSet.Status == TransactionResultStatus.Failed)
                {
                    blockReturnSet.Add(returnSet);
                }
                else if (returnSet.Status == TransactionResultStatus.Unexecutable)
                {
                    unexecutable.Add(returnSet.TransactionId);
                }
            }

            if (unexecutable.Count > 0)
            {
                await EventBus.PublishAsync(new UnexecutableTransactionsFoundEvent(blockHeader, unexecutable));
            }
            // TODO: Insert deferredTransactions to TxPool

            var executed = new HashSet <Hash>(cancellableReturnSets.Select(x => x.TransactionId));
            var allExecutedTransactions =
                nonCancellable.Concat(cancellable.Where(x => executed.Contains(x.GetHash()))).ToList();
            var block = await _blockGenerationService.FillBlockAfterExecutionAsync(blockHeader, allExecutedTransactions,
                                                                                   blockReturnSet);

            return(block);
        }
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(TransactionExecutingDto transactionExecutingDto,
                                                                    CancellationToken cancellationToken, bool throwException = false)
        {
            Logger.LogTrace($"Entered parallel ExecuteAsync.");
            var transactions = transactionExecutingDto.Transactions.ToList();
            var blockHeader  = transactionExecutingDto.BlockHeader;
            // TODO: Is it reasonable to allow throwing exception here
//            if (throwException)
//            {
//                throw new NotSupportedException(
//                    $"Throwing exception is not supported in {nameof(LocalParallelTransactionExecutingService)}.");
//            }

            var chainContext = new ChainContext
            {
                BlockHash   = blockHeader.PreviousBlockHash,
                BlockHeight = blockHeader.Height - 1
            };
            var groupedTransactions = await _grouper.GroupAsync(chainContext, transactions);

            var tasks = groupedTransactions.Parallelizables.AsParallel().Select(
                txns => ExecuteAndPreprocessResult(new TransactionExecutingDto
            {
                BlockHeader          = blockHeader,
                Transactions         = txns,
                PartialBlockStateSet = transactionExecutingDto.PartialBlockStateSet
            }, cancellationToken, throwException));
            var results = await Task.WhenAll(tasks);

            Logger.LogTrace("Executed parallelizables.");

            var returnSets          = MergeResults(results, out var conflictingSets).Item1;
            var returnSetCollection = new ReturnSetCollection(returnSets);

            var updatedPartialBlockStateSet = returnSetCollection.ToBlockStateSet();

            updatedPartialBlockStateSet.MergeFrom(transactionExecutingDto.PartialBlockStateSet?.Clone() ??
                                                  new BlockStateSet());

            Logger.LogTrace("Merged results from parallelizables.");

            var nonParallelizableReturnSets = await _plainExecutingService.ExecuteAsync(
                new TransactionExecutingDto
            {
                BlockHeader          = blockHeader,
                Transactions         = groupedTransactions.NonParallelizables,
                PartialBlockStateSet = updatedPartialBlockStateSet
            },
                cancellationToken, throwException);

            Logger.LogTrace("Merged results from non-parallelizables.");
            returnSets.AddRange(nonParallelizableReturnSets);

            var transactionWithoutContractReturnSets = await ProcessTransactionsWithoutContract(
                groupedTransactions.TransactionsWithoutContract, blockHeader);

            Logger.LogTrace("Merged results from transactions without contract.");
            returnSets.AddRange(transactionWithoutContractReturnSets);

            if (conflictingSets.Count > 0)
            {
                await EventBus.PublishAsync(new ConflictingTransactionsFoundInParallelGroupsEvent(
                                                blockHeader.Height - 1,
                                                blockHeader.PreviousBlockHash,
                                                returnSets, conflictingSets
                                                ));
            }

            var transactionOrder = transactions.Select(t => t.GetHash()).ToList();

            return(returnSets.AsParallel().OrderBy(d => transactionOrder.IndexOf(d.TransactionId)).ToList());
        }