Beispiel #1
0
        private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTime,
                                                     ITransactionContext txContext, TieredStateCache internalStateCache,
                                                     IChainContext internalChainContext, CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            if (txContext.Trace.IsSuccessful() && txContext.Trace.InlineTransactions.Count > 0)
            {
                internalStateCache.Update(txContext.Trace.GetFlattenedWrites()
                                          .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                foreach (var inlineTx in txContext.Trace.InlineTransactions)
                {
                    var inlineTrace = await ExecuteOneAsync(depth + 1, internalChainContext, inlineTx,
                                                            currentBlockTime, cancellationToken, txContext.Origin);

                    trace.InlineTraces.Add(inlineTrace);
                    if (!inlineTrace.IsSuccessful())
                    {
                        Logger.LogError($"Method name: {inlineTx.MethodName}, {inlineTrace.Error}");
                        // Already failed, no need to execute remaining inline transactions
                        break;
                    }

                    internalStateCache.Update(inlineTrace.GetFlattenedWrites()
                                              .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                }
            }
        }
Beispiel #2
0
        private async Task <bool> ExecutePluginOnPostTransactionStageAsync(IExecutive executive,
                                                                           ITransactionContext txContext,
                                                                           Timestamp currentBlockTime,
                                                                           IChainContext internalChainContext,
                                                                           TieredStateCache internalStateCache,
                                                                           CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            foreach (var plugin in _postPlugins)
            {
                var transactions = await plugin.GetPostTransactionsAsync(executive.Descriptors, txContext);

                foreach (var postTx in transactions)
                {
                    var postTrace = await ExecuteOneAsync(0, internalChainContext, postTx, currentBlockTime,
                                                          cancellationToken, isCancellable : false);

                    trace.PostTransactions.Add(postTx);
                    trace.PostTraces.Add(postTrace);
                    if (!postTrace.IsSuccessful())
                    {
                        trace.ExecutionStatus = ExecutionStatus.Postfailed;
                        postTrace.SurfaceUpError();
                        trace.Error += postTrace.Error;
                        return(false);
                    }

                    internalStateCache.Update(postTrace.GetFlattenedWrites()
                                              .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                }
            }

            return(true);
        }
        private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTime,
                                                     ITransactionContext txContext, TieredStateCache internalStateCache,
                                                     IChainContext internalChainContext, CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            internalStateCache.Update(txContext.Trace.GetStateSets());
            foreach (var inlineTx in txContext.Trace.InlineTransactions)
            {
                var singleTxExecutingDto = new SingleTransactionExecutingDto
                {
                    Depth            = depth + 1,
                    ChainContext     = internalChainContext,
                    Transaction      = inlineTx,
                    CurrentBlockTime = currentBlockTime,
                    Origin           = txContext.Origin
                };
                var inlineTrace = await ExecuteOneAsync(singleTxExecutingDto, cancellationToken);

                if (inlineTrace == null)
                {
                    break;
                }
                trace.InlineTraces.Add(inlineTrace);
                if (!inlineTrace.IsSuccessful())
                {
                    Logger.LogWarning($"Method name: {inlineTx.MethodName}, {inlineTrace.Error}");
                    // Already failed, no need to execute remaining inline transactions
                    break;
                }

                internalStateCache.Update(inlineTrace.GetStateSets());
            }
        }
        private async Task <bool> ExecutePluginOnPreTransactionStageAsync(IExecutive executive,
                                                                          ITransactionContext txContext,
                                                                          Timestamp currentBlockTime,
                                                                          IChainContext internalChainContext,
                                                                          TieredStateCache internalStateCache,
                                                                          CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            foreach (var plugin in _prePlugins)
            {
                var transactions = await plugin.GetPreTransactionsAsync(executive.Descriptors, txContext);

                foreach (var preTx in transactions)
                {
                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth            = 0,
                        ChainContext     = internalChainContext,
                        Transaction      = preTx,
                        CurrentBlockTime = currentBlockTime
                    };
                    var preTrace = await ExecuteOneAsync(singleTxExecutingDto, cancellationToken);

                    if (preTrace == null)
                    {
                        return(false);
                    }
                    trace.PreTransactions.Add(preTx);
                    trace.PreTraces.Add(preTrace);
                    if (preTx.MethodName == "ChargeTransactionFees")
                    {
                        var txFee = new TransactionFee();
                        txFee.MergeFrom(preTrace.ReturnValue);
                        trace.TransactionFee = txFee;
                    }

                    if (!preTrace.IsSuccessful())
                    {
                        return(false);
                    }

                    var stateSets = preTrace.GetStateSets().ToList();
                    internalStateCache.Update(stateSets);
                    var parentStateCache = txContext.StateCache as TieredStateCache;
                    parentStateCache?.Update(stateSets);

                    if (trace.TransactionFee == null || !trace.TransactionFee.IsFailedToCharge)
                    {
                        continue;
                    }

                    preTrace.ExecutionStatus = ExecutionStatus.Executed;
                    return(false);
                }
            }

            return(true);
        }
Beispiel #5
0
        private async Task <bool> ExecutePluginOnPostTransactionStageAsync(IExecutive executive,
                                                                           ITransactionContext txContext,
                                                                           Timestamp currentBlockTime,
                                                                           IChainContext internalChainContext,
                                                                           TieredStateCache internalStateCache,
                                                                           CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            if (!trace.IsSuccessful())
            {
                // If failed to execute this tx, at least we need to commit pre traces.
                internalStateCache = new TieredStateCache(txContext.StateCache);
                foreach (var preTrace in txContext.Trace.PreTraces)
                {
                    var stateSets = preTrace.GetStateSets();
                    internalStateCache.Update(stateSets);
                }

                internalChainContext.StateCache = internalStateCache;
            }

            foreach (var plugin in _postPlugins)
            {
                var transactions = await plugin.GetPostTransactionsAsync(executive.Descriptors, txContext);

                foreach (var postTx in transactions)
                {
                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth               = 0,
                        ChainContext        = internalChainContext,
                        Transaction         = postTx,
                        CurrentBlockTime    = currentBlockTime,
                        OriginTransactionId = txContext.OriginTransactionId
                    };
                    var postTrace = await ExecuteOneAsync(singleTxExecutingDto, cancellationToken);

                    if (postTrace == null)
                    {
                        return(false);
                    }
                    trace.PostTransactions.Add(postTx);
                    trace.PostTraces.Add(postTrace);

                    if (!postTrace.IsSuccessful())
                    {
                        return(false);
                    }

                    internalStateCache.Update(postTrace.GetStateSets());
                }
            }

            return(true);
        }
Beispiel #6
0
        private async Task <bool> ExecutePluginOnPreTransactionStageAsync(IExecutive executive,
                                                                          ITransactionContext txContext,
                                                                          Timestamp currentBlockTime,
                                                                          IChainContext internalChainContext,
                                                                          TieredStateCache internalStateCache,
                                                                          CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            foreach (var plugin in _prePlugins)
            {
                var transactions = await plugin.GetPreTransactionsAsync(executive.Descriptors, txContext);

                foreach (var preTx in transactions)
                {
                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth               = 0, //TODO: this 0 means it is possible that pre/post txs could have own pre/post txs
                        ChainContext        = internalChainContext,
                        Transaction         = preTx,
                        CurrentBlockTime    = currentBlockTime,
                        OriginTransactionId = txContext.OriginTransactionId
                    };
                    var preTrace = await ExecuteOneAsync(singleTxExecutingDto, cancellationToken);

                    if (preTrace == null)
                    {
                        return(false);
                    }
                    trace.PreTransactions.Add(preTx);
                    trace.PreTraces.Add(preTrace);

                    if (!preTrace.IsSuccessful())
                    {
                        return(false);
                    }

                    var stateSets = preTrace.GetStateSets().ToList();
                    internalStateCache.Update(stateSets);
                    var parentStateCache = txContext.StateCache as TieredStateCache;
                    parentStateCache?.Update(stateSets);

                    if (!plugin.IsStopExecuting(preTrace.ReturnValue, out var error))
                    {
                        continue;
                    }

                    // If pre-tx fails, still commit the changes, but return false to notice outside to stop the execution.
                    preTrace.Error           = error;
                    preTrace.ExecutionStatus = ExecutionStatus.Executed;
                    return(false);
                }
            }

            return(true);
        }
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(BlockHeader blockHeader,
                                                                    List <Transaction> transactions, CancellationToken cancellationToken, bool throwException)
        {
            var groupStateCache   = new TieredStateCache();
            var groupChainContext = new ChainContextWithTieredStateCache(blockHeader.PreviousBlockHash,
                                                                         blockHeader.Height - 1, groupStateCache);

            var returnSets = new List <ExecutionReturnSet>();

            foreach (var transaction in transactions)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                var trace = await ExecuteOneAsync(0, groupChainContext, transaction, blockHeader.Time.ToDateTime(),
                                                  cancellationToken);

                if (!trace.IsSuccessful())
                {
                    if (throwException)
                    {
                        Logger.LogError(trace.StdErr);
                    }

                    trace.SurfaceUpError();
                }
                else
                {
                    groupStateCache.Update(trace.GetFlattenedWrite()
                                           .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                }

                if (trace.StdErr != string.Empty)
                {
                    Logger.LogError(trace.StdErr);
                }

                var result = GetTransactionResult(trace, blockHeader.Height);

                if (result != null)
                {
                    await _transactionResultService.AddTransactionResultAsync(result, blockHeader);
                }

                var returnSet = GetReturnSet(trace, result);
                returnSets.Add(returnSet);
            }

            return(returnSets);
        }
Beispiel #8
0
        private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTime,
                                                     ITransactionContext txContext, TieredStateCache internalStateCache,
                                                     IChainContext internalChainContext, CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            internalStateCache.Update(txContext.Trace.GetStateSets());
            foreach (var inlineTx in txContext.Trace.InlineTransactions)
            {
                var singleTxExecutingDto = new SingleTransactionExecutingDto
                {
                    Depth            = depth + 1,
                    ChainContext     = internalChainContext,
                    Transaction      = inlineTx,
                    CurrentBlockTime = currentBlockTime,
                    Origin           = txContext.Origin
                };

                // Only system contract can send TransferFrom tx as inline tx.
                if (!_inlineTransactionValidationService.Validate(inlineTx))
                {
                    break;
                }

                var inlineTrace = await ExecuteOneAsync(singleTxExecutingDto, cancellationToken);

                if (inlineTrace == null)
                {
                    break;
                }
                trace.InlineTraces.Add(inlineTrace);
                if (!inlineTrace.IsSuccessful())
                {
                    // Already failed, no need to execute remaining inline transactions
                    break;
                }

                internalStateCache.Update(inlineTrace.GetStateSets());
            }
        }
Beispiel #9
0
        private static bool TryUpdateStateCache(TransactionTrace trace, TieredStateCache groupStateCache)
        {
            if (trace == null)
            {
                return(false);
            }

            if (!trace.IsSuccessful())
            {
                var transactionExecutingStateSets = new List <TransactionExecutingStateSet>();

                AddToTransactionStateSets(transactionExecutingStateSets, trace.PreTraces);
                AddToTransactionStateSets(transactionExecutingStateSets, trace.PostTraces);

                groupStateCache.Update(transactionExecutingStateSets);
                trace.SurfaceUpError();
            }
            else
            {
                groupStateCache.Update(trace.GetStateSets());
            }

            return(true);
        }
Beispiel #10
0
        private async Task <TransactionTrace> ExecuteOneAsync(int depth, IChainContext chainContext,
                                                              Transaction transaction, Timestamp currentBlockTime, CancellationToken cancellationToken,
                                                              Address origin = null, bool isCancellable = true)
        {
            if (isCancellable && cancellationToken.IsCancellationRequested)
            {
                return(new TransactionTrace
                {
                    TransactionId = transaction.GetHash(),
                    ExecutionStatus = ExecutionStatus.Canceled,
                    Error = "Execution cancelled"
                });
            }

            if (transaction.To == null || transaction.From == null)
            {
                throw new Exception($"error tx: {transaction}");
            }

            var trace = new TransactionTrace
            {
                TransactionId = transaction.GetHash()
            };

            var txContext = new TransactionContext
            {
                PreviousBlockHash = chainContext.BlockHash,
                CurrentBlockTime  = currentBlockTime,
                Transaction       = transaction,
                BlockHeight       = chainContext.BlockHeight + 1,
                Trace             = trace,
                CallDepth         = depth,
                StateCache        = chainContext.StateCache,
                Origin            = origin != null ? origin : transaction.From
            };

            var internalStateCache   = new TieredStateCache(chainContext.StateCache);
            var internalChainContext = new ChainContextWithTieredStateCache(chainContext, internalStateCache);

            IExecutive executive;

            try
            {
                executive = await _smartContractExecutiveService.GetExecutiveAsync(
                    internalChainContext,
                    transaction.To);
            }
            catch (SmartContractFindRegistrationException e)
            {
                txContext.Trace.ExecutionStatus = ExecutionStatus.ContractError;
                txContext.Trace.Error          += "Invalid contract address.\n";
                return(trace);
            }

            try
            {
                #region PreTransaction

                if (depth == 0)
                {
                    if (!await ExecutePluginOnPreTransactionStageAsync(executive, txContext, currentBlockTime,
                                                                       internalChainContext, internalStateCache, cancellationToken))
                    {
                        return(trace);
                    }
                }

                #endregion

                await executive.ApplyAsync(txContext);

                await ExecuteInlineTransactions(depth, currentBlockTime, txContext, internalStateCache,
                                                internalChainContext, cancellationToken);

                #region PostTransaction

                if (depth == 0)
                {
                    if (!await ExecutePluginOnPostTransactionStageAsync(executive, txContext, currentBlockTime,
                                                                        internalChainContext, internalStateCache, cancellationToken))
                    {
                        return(trace);
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                Logger.LogError($"Tx execution failed: {txContext}");
                txContext.Trace.ExecutionStatus = ExecutionStatus.ContractError;
                txContext.Trace.Error          += ex + "\n";
                throw;
            }
            finally
            {
                await _smartContractExecutiveService.PutExecutiveAsync(transaction.To, executive);

                await LocalEventBus.PublishAsync(new TransactionExecutedEventData
                {
                    TransactionTrace = trace
                });
            }

            return(trace);
        }
Beispiel #11
0
        private async Task <TransactionTrace> ExecuteOneAsync(SingleTransactionExecutingDto singleTxExecutingDto,
                                                              CancellationToken cancellationToken)
        {
            if (singleTxExecutingDto.IsCancellable)
            {
                cancellationToken.ThrowIfCancellationRequested();
            }

            var txContext = CreateTransactionContext(singleTxExecutingDto, out var trace);

            var internalStateCache   = new TieredStateCache(singleTxExecutingDto.ChainContext.StateCache);
            var internalChainContext = new ChainContextWithTieredStateCache(singleTxExecutingDto.ChainContext, internalStateCache);

            IExecutive executive;

            try
            {
                executive = await _smartContractExecutiveService.GetExecutiveAsync(
                    internalChainContext,
                    singleTxExecutingDto.Transaction.To);
            }
            catch (SmartContractFindRegistrationException)
            {
                txContext.Trace.ExecutionStatus = ExecutionStatus.ContractError;
                txContext.Trace.Error          += "Invalid contract address.\n";
                return(trace);
            }

            try
            {
                #region PreTransaction

                if (singleTxExecutingDto.Depth == 0)
                {
                    if (!await ExecutePluginOnPreTransactionStageAsync(executive, txContext, singleTxExecutingDto.CurrentBlockTime,
                                                                       internalChainContext, internalStateCache, cancellationToken))
                    {
                        trace.ExecutionStatus = ExecutionStatus.Prefailed;
                        return(trace);
                    }
                }

                #endregion

                await executive.ApplyAsync(txContext);

                if (txContext.Trace.IsSuccessful())
                {
                    await ExecuteInlineTransactions(singleTxExecutingDto.Depth, singleTxExecutingDto.CurrentBlockTime,
                                                    txContext, internalStateCache,
                                                    internalChainContext, cancellationToken);
                }

                #region PostTransaction

                if (singleTxExecutingDto.Depth == 0)
                {
                    if (!await ExecutePluginOnPostTransactionStageAsync(executive, txContext, singleTxExecutingDto.CurrentBlockTime,
                                                                        internalChainContext, internalStateCache, cancellationToken))
                    {
                        trace.ExecutionStatus = ExecutionStatus.Postfailed;
                        return(trace);
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Transaction execution failed.");
                txContext.Trace.ExecutionStatus = ExecutionStatus.ContractError;
                txContext.Trace.Error          += ex + "\n";
                throw;
            }
            finally
            {
                await _smartContractExecutiveService.PutExecutiveAsync(singleTxExecutingDto.ChainContext,
                                                                       singleTxExecutingDto.Transaction.To, executive);

#if DEBUG
                await LocalEventBus.PublishAsync(new TransactionExecutedEventData
                {
                    TransactionTrace = trace
                });
#endif
            }

            return(trace);
        }
        private async Task <TransactionTrace> ExecuteOneAsync(int depth, IChainContext chainContext,
                                                              Transaction transaction, DateTime currentBlockTime, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(new TransactionTrace()
                {
                    TransactionId = transaction.GetHash(),
                    ExecutionStatus = ExecutionStatus.Canceled
                });
            }

            if (transaction.To == null || transaction.From == null)
            {
                throw new Exception($"error tx: {transaction}");
            }

            var trace = new TransactionTrace
            {
                TransactionId = transaction.GetHash()
            };

            var txCtxt = new TransactionContext
            {
                PreviousBlockHash = chainContext.BlockHash,
                CurrentBlockTime  = currentBlockTime,
                Transaction       = transaction,
                BlockHeight       = chainContext.BlockHeight + 1,
                Trace             = trace,
                CallDepth         = depth,
                StateCache        = chainContext.StateCache
            };

            var internalStateCache   = new TieredStateCache(chainContext.StateCache);
            var internalChainContext = new ChainContextWithTieredStateCache(chainContext, internalStateCache);
            var executive            = await _smartContractExecutiveService.GetExecutiveAsync(
                internalChainContext,
                transaction.To);

            try
            {
                #region PreTransaction

                if (depth == 0)
                {
                    foreach (var plugin in _plugins)
                    {
                        var transactions = await plugin.GetPreTransactionsAsync(executive.Descriptors, txCtxt);

                        foreach (var preTx in transactions)
                        {
                            var preTrace = await ExecuteOneAsync(0, internalChainContext, preTx, currentBlockTime,
                                                                 cancellationToken);

                            trace.PreTransactions.Add(preTx);
                            trace.PreTraces.Add(preTrace);
                            if (!preTrace.IsSuccessful())
                            {
                                trace.ExecutionStatus = ExecutionStatus.Prefailed;
                                return(trace);
                            }

                            internalStateCache.Update(preTrace.GetFlattenedWrite()
                                                      .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                        }
                    }
                }

                #endregion

                await executive.ApplyAsync(txCtxt);

                if (txCtxt.Trace.IsSuccessful() && txCtxt.Trace.InlineTransactions.Count > 0)
                {
                    internalStateCache.Update(txCtxt.Trace.GetFlattenedWrite()
                                              .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                    foreach (var inlineTx in txCtxt.Trace.InlineTransactions)
                    {
                        var inlineTrace = await ExecuteOneAsync(depth + 1, internalChainContext, inlineTx,
                                                                currentBlockTime, cancellationToken);

                        trace.InlineTraces.Add(inlineTrace);
                        if (!inlineTrace.IsSuccessful())
                        {
                            // Fail already, no need to execute remaining inline transactions
                            break;
                        }

                        internalStateCache.Update(inlineTrace.GetFlattenedWrite()
                                                  .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                    }
                }
            }
            catch (Exception ex)
            {
                txCtxt.Trace.ExecutionStatus = ExecutionStatus.ContractError;
                txCtxt.Trace.StdErr         += ex + "\n";
                throw;
            }
            finally
            {
                await _smartContractExecutiveService.PutExecutiveAsync(transaction.To, executive);
            }

            return(trace);
        }
Beispiel #13
0
        private async Task <bool> ExecutePluginOnPostTransactionStageAsync(IExecutive executive,
                                                                           ITransactionContext txContext,
                                                                           Timestamp currentBlockTime,
                                                                           IChainContext internalChainContext,
                                                                           TieredStateCache internalStateCache,
                                                                           CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            if (!trace.IsSuccessful())
            {
                internalStateCache = new TieredStateCache(txContext.StateCache);
                foreach (var preTrace in txContext.Trace.PreTraces)
                {
                    var stateSets = preTrace.GetStateSets();
                    internalStateCache.Update(stateSets);
                }

                internalChainContext.StateCache = internalStateCache;
            }
            foreach (var plugin in _postPlugins)
            {
                var transactions = await plugin.GetPostTransactionsAsync(executive.Descriptors, txContext);

                foreach (var postTx in transactions)
                {
                    TransactionTrace postTrace;
                    try
                    {
                        var singleTxExecutingDto = new SingleTransactionExecutingDto
                        {
                            Depth            = 0,
                            ChainContext     = internalChainContext,
                            Transaction      = postTx,
                            CurrentBlockTime = currentBlockTime,
                            IsCancellable    = false
                        };
                        postTrace = await ExecuteOneAsync(singleTxExecutingDto,
                                                          cancellationToken).WithCancellation(cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogTrace("execute transaction timeout");
                        return(false);
                    }

                    if (postTrace == null)
                    {
                        return(false);
                    }
                    trace.PostTransactions.Add(postTx);
                    trace.PostTraces.Add(postTrace);
                    if (!postTrace.IsSuccessful())
                    {
                        trace.ExecutionStatus = ExecutionStatus.Postfailed;
                        postTrace.SurfaceUpError();
                        trace.Error += postTrace.Error;
                        return(false);
                    }

                    internalStateCache.Update(postTrace.GetStateSets());
                }
            }

            return(true);
        }
Beispiel #14
0
        private async Task <bool> ExecutePluginOnPreTransactionStageAsync(IExecutive executive,
                                                                          ITransactionContext txContext,
                                                                          Timestamp currentBlockTime,
                                                                          IChainContext internalChainContext,
                                                                          TieredStateCache internalStateCache,
                                                                          CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            foreach (var plugin in _prePlugins)
            {
                var transactions = await plugin.GetPreTransactionsAsync(executive.Descriptors, txContext);

                foreach (var preTx in transactions)
                {
                    TransactionTrace preTrace;
                    try
                    {
                        var singleTxExecutingDto = new SingleTransactionExecutingDto
                        {
                            Depth            = 0,
                            ChainContext     = internalChainContext,
                            Transaction      = preTx,
                            CurrentBlockTime = currentBlockTime
                        };
                        preTrace = await ExecuteOneAsync(singleTxExecutingDto,
                                                         cancellationToken).WithCancellation(cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogTrace("execute transaction timeout");
                        return(false);
                    }

                    if (preTrace == null)
                    {
                        return(false);
                    }
                    trace.PreTransactions.Add(preTx);
                    trace.PreTraces.Add(preTrace);
                    if (preTx.MethodName == "ChargeTransactionFees")
                    {
                        var txFee = new TransactionFee();
                        txFee.MergeFrom(preTrace.ReturnValue);
                        trace.TransactionFee = txFee;
                    }
                    if (!preTrace.IsSuccessful())
                    {
                        trace.ExecutionStatus = IsTransactionCanceled(preTrace)
                            ? ExecutionStatus.Canceled
                            : ExecutionStatus.Prefailed;
                        preTrace.SurfaceUpError();
                        trace.Error += preTrace.Error;
                        return(false);
                    }

                    var stateSets = preTrace.GetStateSets().ToList();
                    internalStateCache.Update(stateSets);
                    var parentStateCache = txContext.StateCache as TieredStateCache;
                    parentStateCache?.Update(stateSets);
                }
            }

            return(true);
        }
Beispiel #15
0
        private async Task <bool> ExecutePluginOnPostTransactionStageAsync(IExecutive executive,
                                                                           ITransactionContext txContext,
                                                                           Timestamp currentBlockTime,
                                                                           IChainContext internalChainContext,
                                                                           TieredStateCache internalStateCache,
                                                                           CancellationToken cancellationToken)
        {
            var trace = txContext.Trace;

            if (!trace.IsSuccessful())
            {
                internalStateCache = new TieredStateCache(txContext.StateCache);
                foreach (var preTrace in txContext.Trace.PreTraces)
                {
                    var stateSets = preTrace.GetStateSets();
                    internalStateCache.Update(stateSets);
                }

                internalChainContext.StateCache = internalStateCache;
            }

            foreach (var plugin in _postPlugins)
            {
                var transactions = await plugin.GetPostTransactionsAsync(executive.Descriptors, txContext);

                foreach (var postTx in transactions)
                {
                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth            = 0,
                        ChainContext     = internalChainContext,
                        Transaction      = postTx,
                        CurrentBlockTime = currentBlockTime
                    };
                    var postTrace = await ExecuteOneAsync(singleTxExecutingDto, cancellationToken);

                    if (postTrace == null)
                    {
                        return(false);
                    }
                    trace.PostTransactions.Add(postTx);
                    trace.PostTraces.Add(postTrace);

                    if (postTx.MethodName == "ChargeResourceToken")
                    {
                        var consumedResourceTokens = new ConsumedResourceTokens();
                        consumedResourceTokens.MergeFrom(postTrace.ReturnValue);
                        trace.ConsumedResourceTokens = consumedResourceTokens;
                    }

                    if (!postTrace.IsSuccessful())
                    {
                        return(false);
                    }

                    internalStateCache.Update(postTrace.GetStateSets());
                }
            }

            return(true);
        }