예제 #1
0
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(TransactionExecutingDto transactionExecutingDto,
                                                                    CancellationToken cancellationToken)
        {
            Logger.LogTrace("Entered parallel ExecuteAsync.");
            var transactions = transactionExecutingDto.Transactions.ToList();
            var blockHeader  = transactionExecutingDto.BlockHeader;

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

            var returnSets = new List <ExecutionReturnSet>();
            var nonParallelizableReturnSets = await _planTransactionExecutingService.ExecuteAsync(
                new TransactionExecutingDto
            {
                BlockHeader          = blockHeader,
                Transactions         = groupedTransactions.NonParallelizables,
                PartialBlockStateSet = transactionExecutingDto.PartialBlockStateSet
            },
                cancellationToken);

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

            var returnSetCollection         = new ReturnSetCollection(returnSets);
            var updatedPartialBlockStateSet = GetUpdatedBlockStateSet(returnSetCollection, transactionExecutingDto);

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

            Logger.LogTrace("Executed parallelizables.");

            returnSets.AddRange(MergeResults(results, out var conflictingSets));
            Logger.LogTrace("Merged results from parallelizables.");

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

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

            if (conflictingSets.Count > 0 &&
                returnSets.Count + conflictingSets.Count == transactionExecutingDto.Transactions.Count())
            {
                await ProcessConflictingSetsAsync(conflictingSets, blockHeader);

                returnSets.AddRange(conflictingSets);
            }

            return(returnSets);
        }
예제 #2
0
        protected virtual async Task <Block> FillBlockAfterExecutionAsync(BlockHeader blockHeader, List <Transaction> transactions,
                                                                          ReturnSetCollection returnSetCollection)
        {
            Logger.LogTrace("Start block field filling after execution.");
            var bloom         = new Bloom();
            var blockStateSet = new BlockStateSet
            {
                BlockHeight  = blockHeader.Height,
                PreviousHash = blockHeader.PreviousBlockHash
            };

            foreach (var returnSet in returnSetCollection.Executed)
            {
                foreach (var change in returnSet.StateChanges)
                {
                    blockStateSet.Changes[change.Key] = change.Value;
                    blockStateSet.Deletes.Remove(change.Key);
                }

                foreach (var delete in returnSet.StateDeletes)
                {
                    blockStateSet.Deletes.AddIfNotContains(delete.Key);
                    blockStateSet.Changes.Remove(delete.Key);
                }

                bloom.Combine(new[] { new Bloom(returnSet.Bloom.ToByteArray()) });
            }

            blockHeader.Bloom = ByteString.CopyFrom(bloom.Data);
            blockHeader.MerkleTreeRootOfWorldState = CalculateWorldStateMerkleTreeRoot(blockStateSet);

            var allExecutedTransactionIds = transactions.Select(x => x.GetHash()).ToList();
            var orderedReturnSets         = returnSetCollection.ToList().AsParallel()
                                            .OrderBy(d => allExecutedTransactionIds.IndexOf(d.TransactionId)).ToList();

            blockHeader.MerkleTreeRootOfTransactionStatus =
                CalculateTransactionStatusMerkleTreeRoot(orderedReturnSets);

            blockHeader.MerkleTreeRootOfTransactions = CalculateTransactionMerkleTreeRoot(allExecutedTransactionIds);

            var blockHash = blockHeader.GetHashWithoutCache();
            var blockBody = new BlockBody();

            blockBody.TransactionIds.AddRange(allExecutedTransactionIds);

            var block = new Block
            {
                Header = blockHeader,
                Body   = blockBody
            };

            blockStateSet.BlockHash = blockHash;
            Logger.LogTrace("Set block state set.");

            await _blockchainStateService.SetBlockStateSetAsync(blockStateSet);

            Logger.LogTrace("Finish block field filling after execution.");
            return(block);
        }
예제 #3
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);
        }
예제 #4
0
        private BlockStateSet GetUpdatedBlockStateSet(ReturnSetCollection returnSetCollection,
                                                      TransactionExecutingDto transactionExecutingDto)
        {
            var updatedPartialBlockStateSet = returnSetCollection.ToBlockStateSet();

            if (transactionExecutingDto.PartialBlockStateSet != null)
            {
                var partialBlockStateSet = transactionExecutingDto.PartialBlockStateSet.Clone();
                foreach (var change in partialBlockStateSet.Changes)
                {
                    if (updatedPartialBlockStateSet.Changes.TryGetValue(change.Key, out _))
                    {
                        continue;
                    }
                    if (updatedPartialBlockStateSet.Deletes.Contains(change.Key))
                    {
                        continue;
                    }
                    updatedPartialBlockStateSet.Changes[change.Key] = change.Value;
                }

                foreach (var delete in partialBlockStateSet.Deletes)
                {
                    if (updatedPartialBlockStateSet.Deletes.Contains(delete))
                    {
                        continue;
                    }
                    if (updatedPartialBlockStateSet.Changes.TryGetValue(delete, out _))
                    {
                        continue;
                    }
                    updatedPartialBlockStateSet.Deletes.Add(delete);
                }
            }

            return(updatedPartialBlockStateSet);
        }
        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 returnSets = new List <ExecutionReturnSet>();
            var nonParallelizableReturnSets = await _plainExecutingService.ExecuteAsync(
                new TransactionExecutingDto
            {
                BlockHeader          = blockHeader,
                Transactions         = groupedTransactions.NonParallelizables,
                PartialBlockStateSet = transactionExecutingDto.PartialBlockStateSet
            },
                cancellationToken, throwException);

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

            var returnSetCollection         = new ReturnSetCollection(returnSets);
            var updatedPartialBlockStateSet = returnSetCollection.ToBlockStateSet();

            if (transactionExecutingDto.PartialBlockStateSet != null)
            {
                var partialBlockStateSet = transactionExecutingDto.PartialBlockStateSet.Clone();
                foreach (var change in partialBlockStateSet.Changes)
                {
                    if (updatedPartialBlockStateSet.Changes.TryGetValue(change.Key, out _))
                    {
                        continue;
                    }
                    if (updatedPartialBlockStateSet.Deletes.Contains(change.Key))
                    {
                        continue;
                    }
                    updatedPartialBlockStateSet.Changes[change.Key] = change.Value;
                }

                foreach (var delete in partialBlockStateSet.Deletes)
                {
                    if (updatedPartialBlockStateSet.Deletes.Contains(delete))
                    {
                        continue;
                    }
                    if (updatedPartialBlockStateSet.Changes.TryGetValue(delete, out _))
                    {
                        continue;
                    }
                    updatedPartialBlockStateSet.Deletes.Add(delete);
                }
            }

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

            Logger.LogTrace("Executed parallelizables.");

            returnSets.AddRange(MergeResults(results, out var conflictingSets).Item1);
            Logger.LogTrace("Merged results from parallelizables.");

            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
                                                ));
                await ProcessConflictingSetsAsync(conflictingSets, returnSets, blockHeader);
            }

            return(returnSets);
        }
예제 #6
0
        protected override async Task <Block> FillBlockAfterExecutionAsync(BlockHeader blockHeader, List <Transaction> transactions, ReturnSetCollection returnSetCollection)
        {
            var block = await base.FillBlockAfterExecutionAsync(blockHeader, transactions, returnSetCollection);

            if (returnSetCollection.Conflict.Count > 0)
            {
                await EventBus.PublishAsync(new ConflictingTransactionsFoundInParallelGroupsEvent(
                                                block.Header, returnSetCollection.Executed.Concat(returnSetCollection.Unexecutable).ToList(),
                                                returnSetCollection.Conflict
                                                ));
            }
            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());
        }