Beispiel #1
0
        /// <inheritdoc/>
        public async Task <BlockExecutionResult> ExecuteBlock(IBlock block)
        {
            if (_isMining)
            {
                _logger?.Trace($"Prevent block {block.BlockHashToHex} from entering block execution," +
                               "for this node is doing mining.");
                return(BlockExecutionResult.Mining);
            }

            _current = block.BlockHashToHex;

            var result = Prepare(block);

            if (result.IsFailed())
            {
                _current = null;
                return(result);
            }

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            _executing = true;
            if (_terminated)
            {
                return(BlockExecutionResult.Terminated);
            }

            var txnRes   = new List <TransactionResult>();
            var readyTxs = new List <Transaction>();
            var cts      = new CancellationTokenSource();

            var res = BlockExecutionResult.Fatal;

            try
            {
                // get txn from pool
                var tuple = CollectTransactions(block);
                result   = tuple.Item1;
                readyTxs = tuple.Item2;
                if (result.IsFailed() || readyTxs.Count == 0)
                {
                    _logger?.Warn($"Collect transaction from block failed: {result}, block height: {block.Header.Index}, " +
                                  $"block hash: {block.BlockHashToHex}.");
                    res = result;
                    return(res);
                }

                double distanceToTimeSlot = 0;
                if (_isLimitExecutionTime)
                {
                    distanceToTimeSlot = await _dpoSInfoProvider.GetDistanceToTimeSlotEnd();

                    cts.CancelAfter(TimeSpan.FromMilliseconds(distanceToTimeSlot * NodeConfig.Instance.RatioSynchronize));
                }

                var trs = await _txHub.GetReceiptsForAsync(readyTxs, cts);

                if (cts.IsCancellationRequested)
                {
                    return(BlockExecutionResult.ExecutionCancelled);
                }

                foreach (var tr in trs)
                {
                    if (!tr.IsExecutable)
                    {
                        throw new InvalidBlockException($"Transaction is not executable, transaction: {tr}, " +
                                                        $"block height: {block.Header.Index}, block hash: {block.BlockHashToHex}, SignatureSt:{tr.SignatureSt},RefBlockSt:{tr.RefBlockSt},Status:{tr.Status}");
                    }
                }

                txnRes = await ExecuteTransactions(readyTxs, block.Header.ChainId, block.Header.GetDisambiguationHash(), cts);

                if (cts.IsCancellationRequested)
                {
                    _logger?.Trace($"Execution Cancelled and rollback: block hash: {block.BlockHashToHex}, execution time: {distanceToTimeSlot * NodeConfig.Instance.RatioSynchronize} ms.");
                    Rollback(block, txnRes).ConfigureAwait(false);
                    return(BlockExecutionResult.ExecutionCancelled);
                }

                txnRes = SortToOriginalOrder(txnRes, readyTxs);

                var blockChain = _chainService.GetBlockChain(Hash.LoadHex(ChainConfig.Instance.ChainId));
                if (await blockChain.GetBlockByHashAsync(block.GetHash()) != null)
                {
                    res = BlockExecutionResult.AlreadyAppended;
                    return(res);
                }

                result = UpdateWorldState(block, txnRes);
                if (result.IsFailed())
                {
                    res = result;
                    return(res);
                }

                await UpdateCrossChainInfo(block, txnRes);

                // BlockExecuting -> BlockAppending
                // ExecutingLoop -> BlockAppending
                MessageHub.Instance.Publish(StateEvent.StateUpdated);

                await AppendBlock(block);

                InsertTxs(txnRes, block);

                await _txHub.OnNewBlock((Block)block);

                res = BlockExecutionResult.Success;
                return(res);
            }
            catch (Exception e)
            {
                _logger?.Error(e, $"Exception while execute block {block.BlockHashToHex}.");
                // TODO, no wait may need improve
                Rollback(block, txnRes).ConfigureAwait(false);

                return(res);
            }
            finally
            {
                _current   = null;
                _executing = false;
                cts.Dispose();
                if (_prepareTerminated)
                {
                    _terminated = true;
                    MessageHub.Instance.Publish(new TerminatedModule(TerminatedModuleEnum.BlockExecutor));
                }

                stopwatch.Stop();
                if (res.CanExecuteAgain())
                {
                    _logger?.Warn($"Block {block.BlockHashToHex} can execute again.");
                }

                _logger?.Info($"Executed block {block.BlockHashToHex} with result {res}, {block.Body.Transactions.Count} txns, " +
                              $"duration {stopwatch.ElapsedMilliseconds} ms.");
            }
        }
Beispiel #2
0
        /// <inheritdoc />
        /// <summary>
        /// Mine process.
        /// </summary>
        /// <returns></returns>
        public async Task <IBlock> Mine()
        {
            try
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();
                await GenerateTransactionWithParentChainBlockInfo();

                var txs = await _txHub.GetReceiptsOfExecutablesAsync();

                var txGrp  = txs.GroupBy(tr => tr.IsSystemTxn).ToDictionary(x => x.Key, x => x.ToList());
                var traces = new List <TransactionTrace>();
                //ParentChainBlockInfo pcb = null;
                if (txGrp.TryGetValue(true, out var sysRcpts))
                {
                    var sysTxs = sysRcpts.Select(x => x.Transaction).ToList();
                    _txFilter.Execute(sysTxs);

                    _logger?.Trace($"Start executing {sysTxs.Count} system transactions.");
                    traces = await ExecuteTransactions(sysTxs, true);

                    _logger?.Trace($"Finish executing {sysTxs.Count} system transactions.");

                    // need check result of cross chain transaction
                    //FindCrossChainInfo(sysTxs, traces, out pcb);
                }
                if (txGrp.TryGetValue(false, out var regRcpts))
                {
                    var regTxs = regRcpts.Select(x => x.Transaction).ToList();
                    _logger?.Trace($"Start executing {regTxs.Count} regular transactions.");
                    traces.AddRange(await ExecuteTransactions(regTxs));
                    _logger?.Trace($"Finish executing {regTxs.Count} regular transactions.");
                }

                ExtractTransactionResults(traces, out var results);

                // generate block
                var block = await GenerateBlockAsync(results);

                _logger?.Info($"Generated block {block.BlockHashToHex} at height {block.Header.Index} with {block.Body.TransactionsCount} txs.");

                // validate block before appending
                var chainContext = await _chainContextService.GetChainContextAsync(Hash.LoadHex(ChainConfig.Instance.ChainId));

                var blockValidationResult = await _blockValidationService.ValidateBlockAsync(block, chainContext);

                if (blockValidationResult != BlockValidationResult.Success)
                {
                    _logger?.Warn($"Found the block generated before invalid: {blockValidationResult}.");
                    return(null);
                }
                // append block
                await _blockChain.AddBlocksAsync(new List <IBlock> {
                    block
                });

                MessageHub.Instance.Publish(new BlockMined(block));

                // insert to db
                Update(results, block);

                /*if (pcb != null)
                 * {
                 *  await _chainManagerBasic.UpdateCurrentBlockHeightAsync(pcb.ChainId, pcb.Height);
                 * }*/
                await _txHub.OnNewBlock((Block)block);

                MessageHub.Instance.Publish(new BlockMinedAndStored(block));
                stopwatch.Stop();
                _logger?.Info($"Generate block {block.BlockHashToHex} at height {block.Header.Index} " +
                              $"with {block.Body.TransactionsCount} txs, duration {stopwatch.ElapsedMilliseconds} ms.");

                return(block);
            }
            catch (Exception e)
            {
                _logger?.Error(e, "Mining failed with exception.");
                return(null);
            }
        }