private BlockStateSet CreateBlockStateSet(Hash previousBlockHash, long blockHeight,
                                                  ExecutionReturnSetCollection executionReturnSetCollection)
        {
            var blockStateSet = new BlockStateSet
            {
                BlockHeight  = blockHeight,
                PreviousHash = previousBlockHash
            };

            foreach (var returnSet in executionReturnSetCollection.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);
                }
            }

            return(blockStateSet);
        }
        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)
            });
        }
        private async Task <List <TransactionResult> > SetTransactionResultsAsync(ExecutionReturnSetCollection executionReturnSetCollection, BlockHeader blockHeader)
        {
            //save all transaction results
            var results = executionReturnSetCollection.GetExecutionReturnSetList()
                          .Select(p =>
            {
                p.TransactionResult.BlockHash   = blockHeader.GetHash();
                p.TransactionResult.BlockNumber = blockHeader.Height;
                return(p.TransactionResult);
            }).ToList();

            await _transactionResultService.AddTransactionResultsAsync(results, blockHeader);

            return(results);
        }
Exemple #4
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 mergeResult = await ExecuteParallelizableTransactionsAsync(groupedTransactions.Parallelizables,
                                                                           blockHeader, transactionExecutingDto.PartialBlockStateSet, cancellationToken);

            returnSets.AddRange(mergeResult.ExecutionReturnSets);
            var conflictingSets = mergeResult.ConflictingReturnSets;

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

            var nonParallelizableReturnSets = await ExecuteNonParallelizableTransactionsAsync(groupedTransactions.NonParallelizables, blockHeader,
                                                                                              updatedPartialBlockStateSet, cancellationToken);

            returnSets.AddRange(nonParallelizableReturnSets);

            var transactionWithoutContractReturnSets = ProcessTransactionsWithoutContract(
                groupedTransactions.TransactionsWithoutContract);

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

            if (conflictingSets.Count > 0 &&
                returnSets.Count + conflictingSets.Count == transactionExecutingDto.Transactions.Count())
            {
                ProcessConflictingSets(conflictingSets);
                returnSets.AddRange(conflictingSets);
            }

            return(returnSets);
        }
Exemple #5
0
        private BlockStateSet GetUpdatedBlockStateSet(ExecutionReturnSetCollection executionReturnSetCollection,
                                                      TransactionExecutingDto transactionExecutingDto)
        {
            var updatedPartialBlockStateSet = executionReturnSetCollection.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);
        }
        protected override async Task CleanUpReturnSetCollectionAsync(BlockHeader blockHeader, ExecutionReturnSetCollection executionReturnSetCollection)
        {
            await base.CleanUpReturnSetCollectionAsync(blockHeader, executionReturnSetCollection);

            if (executionReturnSetCollection.Conflict.Count > 0)
            {
                await EventBus.PublishAsync(new ConflictingTransactionsFoundInParallelGroupsEvent(
                                                blockHeader, executionReturnSetCollection.Executed.ToList(),
                                                executionReturnSetCollection.Conflict
                                                ));
            }
        }
 protected virtual Task CleanUpReturnSetCollectionAsync(BlockHeader blockHeader, ExecutionReturnSetCollection executionReturnSetCollection)
 {
     return(Task.CompletedTask);
 }
        private Task <Block> FillBlockAfterExecutionAsync(BlockHeader header,
                                                          IEnumerable <Transaction> transactions, ExecutionReturnSetCollection executionReturnSetCollection, BlockStateSet blockStateSet)
        {
            Logger.LogTrace("Start block field filling after execution.");
            var bloom = new Bloom();

            foreach (var returnSet in executionReturnSetCollection.Executed)
            {
                bloom.Combine(new[] { new Bloom(returnSet.Bloom.ToByteArray()) });
            }

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

            var block = new Block
            {
                Header = new BlockHeader(header)
                {
                    Bloom = ByteString.CopyFrom(bloom.Data),
                    MerkleTreeRootOfWorldState        = CalculateWorldStateMerkleTreeRoot(blockStateSet),
                    MerkleTreeRootOfTransactionStatus = CalculateTransactionStatusMerkleTreeRoot(orderedReturnSets),
                    MerkleTreeRootOfTransactions      = CalculateTransactionMerkleTreeRoot(allExecutedTransactionIds)
                },
                Body = new BlockBody
                {
                    TransactionIds = { allExecutedTransactionIds }
                }
            };

            Logger.LogTrace("Finish block field filling after execution.");
            return(Task.FromResult(block));
        }