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); }
private async Task <(List <ExecutionReturnSet>, HashSet <string>)> ExecuteAndPreprocessResult( TransactionExecutingDto transactionExecutingDto, CancellationToken cancellationToken, bool throwException = false) { var executionReturnSets = await _plainExecutingService.ExecuteAsync(transactionExecutingDto, cancellationToken, throwException); var keys = new HashSet <string>( executionReturnSets.SelectMany(s => s.StateChanges.Keys.Concat(s.StateAccesses.Keys))); return(executionReturnSets, keys); }
private async Task <GroupedExecutionReturnSets> ExecuteAndPreprocessResult( TransactionExecutingDto transactionExecutingDto, CancellationToken cancellationToken) { var executionReturnSets = await _planTransactionExecutingService.ExecuteAsync(transactionExecutingDto, cancellationToken); var keys = new HashSet <string>( executionReturnSets.SelectMany(s => s.StateChanges.Keys.Concat(s.StateDeletes.Keys).Concat(s.StateAccesses.Keys))); return(new GroupedExecutionReturnSets { ReturnSets = executionReturnSets, Keys = keys }); }
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); }
private async Task <GroupedExecutionReturnSets> ExecuteAndPreprocessResult( TransactionExecutingDto transactionExecutingDto, CancellationToken cancellationToken) { var executionReturnSets = await _planTransactionExecutingService.ExecuteAsync(transactionExecutingDto, cancellationToken); var changeKeys = executionReturnSets.SelectMany(s => s.StateChanges.Keys.Concat(s.StateDeletes.Keys)); var allKeys = new HashSet <string>( executionReturnSets.SelectMany(s => s.StateAccesses.Keys)); var readKeys = allKeys.Where(k => !changeKeys.Contains(k)); return(new GroupedExecutionReturnSets { ReturnSets = executionReturnSets, AllKeys = allKeys, ChangeKeys = changeKeys, ReadKeys = readKeys }); }
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); }
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); }
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()); }