private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTime,
                                                     TransactionContext txCtxt, TieredStateCache internalStateCache,
                                                     ChainContextWithTieredStateCache internalChainContext, CancellationToken cancellationToken)
        {
            var trace = txCtxt.Trace;

            if (txCtxt.Trace.IsSuccessful() && txCtxt.Trace.InlineTransactions.Count > 0)
            {
                internalStateCache.Update(txCtxt.Trace.GetFlattenedWrites()
                                          .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, txCtxt.Origin);

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

                    internalStateCache.Update(inlineTrace.GetFlattenedWrites()
                                              .Select(x => new KeyValuePair <string, byte[]>(x.Key, x.Value.ToByteArray())));
                }
            }
        }
        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);
        }
Exemplo n.º 3
0
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(TransactionExecutingDto transactionExecutingDto,
                                                                    CancellationToken cancellationToken, bool throwException)
        {
            var groupStateCache = transactionExecutingDto.PartialBlockStateSet == null
                ? new TieredStateCache()
                : new TieredStateCache(
                new StateCacheFromPartialBlockStateSet(transactionExecutingDto.PartialBlockStateSet));
            var groupChainContext = new ChainContextWithTieredStateCache(
                transactionExecutingDto.BlockHeader.PreviousBlockHash,
                transactionExecutingDto.BlockHeader.Height - 1, groupStateCache);

            var returnSets = new List <ExecutionReturnSet>();

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

                var trace = await ExecuteOneAsync(0, groupChainContext, transaction,
                                                  transactionExecutingDto.BlockHeader.Time,
                                                  cancellationToken);

                // Will be useful when debugging MerkleTreeRootOfWorldState is different from each miner.
                Logger.LogTrace(transaction.MethodName);
                Logger.LogTrace(trace.StateSet.Writes.Values.Select(v => v.ToBase64().ComputeHash().ToHex())
                                .JoinAsString("\n"));

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

                    // Do not package this transaction if any of his inline transactions canceled.
                    if (IsTransactionCanceled(trace))
                    {
                        break;
                    }

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

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

                var result = GetTransactionResult(trace, transactionExecutingDto.BlockHeader.Height);

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

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

            return(returnSets);
        }
Exemplo n.º 4
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);
        }
Exemplo n.º 5
0
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(TransactionExecutingDto transactionExecutingDto,
                                                                    CancellationToken cancellationToken)
        {
            try
            {
                var groupStateCache = transactionExecutingDto.PartialBlockStateSet == null
                    ? new TieredStateCache()
                    : new TieredStateCache(
                    new StateCacheFromPartialBlockStateSet(transactionExecutingDto.PartialBlockStateSet));
                var groupChainContext = new ChainContextWithTieredStateCache(
                    transactionExecutingDto.BlockHeader.PreviousBlockHash,
                    transactionExecutingDto.BlockHeader.Height - 1, groupStateCache);

                var transactionResults = new List <TransactionResult>();
                var returnSets         = new List <ExecutionReturnSet>();
                foreach (var transaction in transactionExecutingDto.Transactions)
                {
                    TransactionTrace trace;
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth            = 0,
                        ChainContext     = groupChainContext,
                        Transaction      = transaction,
                        CurrentBlockTime = transactionExecutingDto.BlockHeader.Time,
                    };
                    try
                    {
                        var transactionExecutionTask = Task.Run(() => ExecuteOneAsync(singleTxExecutingDto,
                                                                                      cancellationToken), cancellationToken);

                        trace = await transactionExecutionTask.WithCancellation(cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogTrace("Transaction canceled.");
                        if (cancellationToken.IsCancellationRequested)
                        {
                            break;
                        }
                        continue;
                    }

                    if (trace == null)
                    {
                        break;
                    }

                    if (!trace.IsSuccessful())
                    {
                        // Do not package this transaction if any of his inline transactions canceled.
                        if (IsTransactionCanceled(trace))
                        {
                            break;
                        }

                        var transactionExecutingStateSets = new List <TransactionExecutingStateSet>();
                        foreach (var preTrace in trace.PreTraces)
                        {
                            if (preTrace.IsSuccessful())
                            {
                                transactionExecutingStateSets.AddRange(preTrace.GetStateSets());
                            }
                        }

                        foreach (var postTrace in trace.PostTraces)
                        {
                            if (postTrace.IsSuccessful())
                            {
                                transactionExecutingStateSets.AddRange(postTrace.GetStateSets());
                            }
                        }

                        groupStateCache.Update(transactionExecutingStateSets);
                        trace.SurfaceUpError();
                    }
                    else
                    {
                        groupStateCache.Update(trace.GetStateSets());
                    }
#if DEBUG
                    if (trace.Error != string.Empty)
                    {
                        Logger.LogError(trace.Error);
                    }
#endif
                    var result = GetTransactionResult(trace, transactionExecutingDto.BlockHeader.Height);

                    transactionResults.Add(result);

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

                await _transactionResultService.AddTransactionResultsAsync(transactionResults,
                                                                           transactionExecutingDto.BlockHeader);

                return(returnSets);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Failed while executing txs in block.");
                throw;
            }
        }
Exemplo n.º 6
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);
        }
Exemplo n.º 7
0
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(TransactionExecutingDto transactionExecutingDto,
                                                                    CancellationToken cancellationToken)
        {
            try
            {
                var groupStateCache   = transactionExecutingDto.PartialBlockStateSet.ToTieredStateCache();
                var groupChainContext = new ChainContextWithTieredStateCache(
                    transactionExecutingDto.BlockHeader.PreviousBlockHash,
                    transactionExecutingDto.BlockHeader.Height - 1, groupStateCache);

                var returnSets = new List <ExecutionReturnSet>();
                foreach (var transaction in transactionExecutingDto.Transactions)
                {
                    TransactionTrace trace;
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth               = 0,
                        ChainContext        = groupChainContext,
                        Transaction         = transaction,
                        CurrentBlockTime    = transactionExecutingDto.BlockHeader.Time,
                        OriginTransactionId = transaction.GetHash()
                    };
                    try
                    {
                        var transactionExecutionTask = Task.Run(() => ExecuteOneAsync(singleTxExecutingDto,
                                                                                      cancellationToken), cancellationToken);

                        trace = await transactionExecutionTask.WithCancellation(cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogTrace("Transaction canceled.");
                        if (cancellationToken.IsCancellationRequested)
                        {
                            break;
                        }
                        continue;
                    }


                    if (!TryUpdateStateCache(trace, groupStateCache))
                    {
                        break;
                    }
#if DEBUG
                    if (!string.IsNullOrEmpty(trace.Error))
                    {
                        Logger.LogInformation(trace.Error);
                    }
#endif
                    var result = GetTransactionResult(trace, transactionExecutingDto.BlockHeader.Height);

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

                return(returnSets);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Failed while executing txs in block.");
                throw;
            }
        }
        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);
        }
        private async Task <bool> ExecutePluginOnPostTransactionStageAsync(IExecutive executive,
                                                                           ITransactionContext txCtxt,
                                                                           Timestamp currentBlockTime, ChainContextWithTieredStateCache internalChainContext,
                                                                           TieredStateCache internalStateCache,
                                                                           CancellationToken cancellationToken)
        {
            var trace = txCtxt.Trace;

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

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

                    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);
        }
Exemplo n.º 10
0
        public async Task <List <ExecutionReturnSet> > ExecuteAsync(TransactionExecutingDto transactionExecutingDto,
                                                                    CancellationToken cancellationToken, bool throwException)
        {
            try
            {
                var groupStateCache = transactionExecutingDto.PartialBlockStateSet == null
                    ? new TieredStateCache()
                    : new TieredStateCache(
                    new StateCacheFromPartialBlockStateSet(transactionExecutingDto.PartialBlockStateSet));
                var groupChainContext = new ChainContextWithTieredStateCache(
                    transactionExecutingDto.BlockHeader.PreviousBlockHash,
                    transactionExecutingDto.BlockHeader.Height - 1, groupStateCache);

                var transactionResults = new List <TransactionResult>();
                var returnSets         = new List <ExecutionReturnSet>();
                foreach (var transaction in transactionExecutingDto.Transactions)
                {
                    TransactionTrace trace;
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    var singleTxExecutingDto = new SingleTransactionExecutingDto
                    {
                        Depth            = 0,
                        ChainContext     = groupChainContext,
                        Transaction      = transaction,
                        CurrentBlockTime = transactionExecutingDto.BlockHeader.Time,
                    };
                    try
                    {
                        var task = Task.Run(() => ExecuteOneAsync(singleTxExecutingDto,
                                                                  cancellationToken), cancellationToken);
                        trace = await task.WithCancellation(cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogTrace($"transaction canceled");
                        break;
                    }

                    if (trace == null)
                    {
                        break;
                    }
                    // Will be useful when debugging MerkleTreeRootOfWorldState is different from each miner.

                    /*
                     * Logger.LogTrace(transaction.MethodName);
                     * Logger.LogTrace(trace.StateSet.Writes.Values.Select(v => v.ToBase64().ComputeHash().ToHex())
                     *  .JoinAsString("\n"));
                     */

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

                        // Do not package this transaction if any of his inline transactions canceled.
                        if (IsTransactionCanceled(trace))
                        {
                            break;
                        }

                        var transactionExecutingStateSets = new List <TransactionExecutingStateSet>();
                        foreach (var preTrace in trace.PreTraces)
                        {
                            if (preTrace.IsSuccessful())
                            {
                                transactionExecutingStateSets.AddRange(preTrace.GetStateSets());
                            }
                        }

                        foreach (var postTrace in trace.PostTraces)
                        {
                            if (postTrace.IsSuccessful())
                            {
                                transactionExecutingStateSets.AddRange(postTrace.GetStateSets());
                            }
                        }

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

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

                    var result = GetTransactionResult(trace, transactionExecutingDto.BlockHeader.Height);

                    if (result != null)
                    {
                        result.TransactionFee = trace.TransactionFee;
                        transactionResults.Add(result);
                    }

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

                await _transactionResultService.AddTransactionResultsAsync(transactionResults,
                                                                           transactionExecutingDto.BlockHeader);

                return(returnSets);
            }
            catch (Exception e)
            {
                Logger.LogTrace("Failed while executing txs in block.", e);
                throw;
            }
        }