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); }
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 <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); }
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); }
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()); }