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