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);
        }
        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)
            });
        }
Example #3
0
        private async Task <Block> FillBlockAfterExecutionAsync(BlockHeader blockHeader, List <Transaction> transactions,
                                                                List <ExecutionReturnSet> blockExecutionReturnSet)
        {
            var bloom         = new Bloom();
            var blockStateSet = new BlockStateSet
            {
                BlockHeight  = blockHeader.Height,
                PreviousHash = blockHeader.PreviousBlockHash
            };

            foreach (var returnSet in blockExecutionReturnSet)
            {
                foreach (var change in returnSet.StateChanges)
                {
                    blockStateSet.Changes[change.Key] = change.Value;
                }

                if (returnSet.Status == TransactionResultStatus.Mined)
                {
                    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();

            blockExecutionReturnSet = blockExecutionReturnSet.AsParallel()
                                      .OrderBy(d => allExecutedTransactionIds.IndexOf(d.TransactionId)).ToList();
            blockHeader.MerkleTreeRootOfTransactionStatus =
                CalculateTransactionStatusMerkleTreeRoot(blockExecutionReturnSet);

            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;

            await _blockchainStateService.SetBlockStateSetAsync(blockStateSet);

            return(block);
        }