示例#1
0
文件: Miner.cs 项目: SpenQ/Prototype
        public bool AddTransactionToPool(AbstractTransaction tx, bool publishToNetwork)
        {
            //_logger.LogInformation("Miner received transaction: {0}", JsonConvert.SerializeObject(tx));
            try
            {
                if (_txPool.Contains(tx))
                {
                    throw new TransactionRejectedException("Transaction already submitted to txpool");
                }

                _transactionValidator.ValidateTransaction(tx);
                _txPool.AddTransaction(tx);
                _logger.LogInformation("Added transaction to txpool ({0})", tx.Hash);

                if (publishToNetwork) // todo move this to ConcurrentTransactionPool maybe?
                {
                    EventPublisher.GetInstance().PublishValidTransactionReceived(this, new TransactionReceivedEventArgs(tx));
                }
                return(true);
            }
            catch (TransactionRejectedException e)
            {
                var errorTx = e.Transaction ?? tx;
                _logger.LogInformation("Transaction with hash {0} was rejected: {1}", errorTx.Hash, e.Message);
                return(false);
            }
            catch (Exception e)
            {
                _logger.LogInformation("An {0} occurred: {1}", e.GetType().Name, e.Message);
                return(false);
            }
        }
示例#2
0
        // todo Chain of Responsibility pattern, make XXMessageHandler class for each command type
        // and refactor abstractmessagehandler to a regular MessageHandlerHelper
        public override async Task HandleMessage(NetworkNode node, Message msg)
        {
            try
            {
                if (msg.Command == NetworkCommand.CloseConn.ToString())
                {
                    await node.Disconnect();
                }
                else if (msg.Command == NetworkCommand.GetAddr.ToString())
                {
                    // Send our known peers
                    var addresses = new AddrPayload(_nodePool.GetAllRemoteListenEndpoints());
                    await SendMessageToNode(node, NetworkCommand.Addr, addresses);
                }
                else if (msg.Command == NetworkCommand.Addr.ToString())
                {
                    // Connect to all neighbors that the other node knows
                    var payload = (AddrPayload)msg.Payload;
                    foreach (IPEndPoint endpoint in payload.Endpoints)
                    {
                        await _networkManager.ConnectToPeer(endpoint);
                    }
                }
                else if (msg.Command == NetworkCommand.GetHeaders.ToString())
                {
                    // Send our headers
                    var payload = (GetHeadersPayload)msg.Payload;
                    try
                    {
                        var headers        = GetBlocksFromHash(payload.HighestHeightHash, payload.StoppingHash, false).Select(b => b.Header);
                        var headersPayload = new HeadersPayload(headers);
                        await SendMessageToNode(node, NetworkCommand.Headers, headersPayload);
                    }
                    catch (KeyNotFoundException)
                    {
                        // Send empty payload
                        await SendMessageToNode(node, NetworkCommand.NotFound, null);
                    }
                }
                else if (msg.Command == NetworkCommand.GetBlocks.ToString())
                {
                    var payload       = (GetBlocksPayload)msg.Payload;
                    var blocksPayload = new StateBlocksPayload();
                    if (payload.Headers.Count() > 0)
                    {
                        blocksPayload = new StateBlocksPayload(GetBlocksFromHash(payload.Headers.First(), payload.Headers.Last(), true));
                    }

                    await SendMessageToNode(node, NetworkCommand.Blocks, blocksPayload);
                }
                else if (msg.Command == NetworkCommand.Headers.ToString() && node.IsSyncingWithNode)
                {
                    node.SetSyncStatus(SyncStatus.InProgress);
                    var headersPayload = (HeadersPayload)msg.Payload;

                    if (headersPayload.Headers.Count() == 0)
                    {
                        _logger.LogInformation("Successfully synced with remote node.");
                        node.SetSyncStatus(SyncStatus.Succeeded);
                        return;
                    }

                    // Request these blocks
                    var getBlocksPayload = new GetBlocksPayload(headersPayload.Headers.Select(h => h.Hash));
                    await SendMessageToNode(node, NetworkCommand.GetBlocks, getBlocksPayload);
                }
                else if (msg.Command == NetworkCommand.NotFound.ToString() && node.IsSyncingWithNode)
                {
                    node.SetSyncStatus(SyncStatus.Failed); // Restart the syncing process with another node.
                }
                else if (msg.Command == NetworkCommand.Blocks.ToString() && node.IsSyncingWithNode)
                {
                    var blocksPayload = (StateBlocksPayload)msg.Payload;

                    // Todo rewrite this code to support multithreaded 'Blocks' messages. Combine all gathered blocks
                    // until the process has completed and all blocks are downloaded. Then, grab a block that points to the
                    // end of our chain and add it to our chain. Repeat that process until all blocks have been added.

                    var blocksProcessed = 0;

                    lock (_blockchain)
                    {
                        while (blocksPayload.Blocks.Where(b => b.Header.PreviousHash == _blockchain.Blocks.Last().Header.Hash).Any())
                        {
                            var blockToProcess = blocksPayload.Blocks.Where(b => b.Header.PreviousHash == _blockchain.Blocks.Last().Header.Hash).First();

                            if (_blockchain.CurrentHeight % 5 == 0 && _blockchain.CurrentHeight > 0)
                            {
                                _difficulty = _difficultyCalculator.CalculateCurrentDifficulty(_blockchain); // todo use CalculateCurrentDifficulty when testing is done
                            }

                            if (_difficulty < 1)
                            {
                                _difficulty = 1;
                            }
                            var currentTarget = BlockchainConstants.MaximumTarget / _difficulty;                    // todo refactor these 3 lines. They are copy-pasted from the miner.
                            _blockValidator.ValidateBlock(blockToProcess, currentTarget, _blockchain, false, true); // Rethrow when we have a Block- / TransactionRejectedException. We don't want to keep a connection with bad nodes.
                            blocksProcessed++;
                        }
                    }

                    _logger.LogDebug("Downloaded and added {0} new blocks from remote node", blocksProcessed);
                    _logger.LogDebug("Current height: {0}", _blockchain.CurrentHeight);

                    if (blocksProcessed != blocksPayload.Blocks.Count())
                    {
                        _logger.LogError("Added {0} new blocks from remote node, but expected {1}. Sync failed.", blocksProcessed, blocksPayload.Blocks.Count());
                        node.SetSyncStatus(SyncStatus.Failed);
                        return;
                    }

                    _blockchainRepo.Update(_blockchain);

                    // Block batch processed. Keep on ask for more headers.
                    var getHeadersPayload = new GetHeadersPayload(_blockchain.Blocks.Last().Header.Hash);
                    await SendMessageToNode(node, NetworkCommand.GetHeaders, getHeadersPayload);
                }
                else if (msg.Command == NetworkCommand.GetTxPool.ToString())
                {
                    var txPoolPayload = new StateTransactionsPayload(_txPool.GetAllTransactions());
                    await SendMessageToNode(node, NetworkCommand.TxPool, txPoolPayload);
                }
                else if (msg.Command == NetworkCommand.TxPool.ToString())
                {
                    var txPoolPayload = (StateTransactionsPayload)msg.Payload;
                    foreach (var tx in txPoolPayload.Transactions)
                    {
                        _txPool.AddTransaction(tx);
                    }
                }
                else if (msg.Command == NetworkCommand.NewTransaction.ToString())
                {
                    var txPayload = (SingleStateTransactionPayload)msg.Payload;
                    if (_networkManager.IsSyncing)
                    {
                        return;
                    }

                    var validationResult = EventPublisher.GetInstance().PublishUnvalidatedTransactionReceived(node, new TransactionReceivedEventArgs(txPayload.Transaction));
                    if (validationResult == false)
                    {
                        //await node.Disconnect(); // Dishonest node, buuh!
                    }
                }
                else if (msg.Command == NetworkCommand.NewBlock.ToString())
                {
                    var blockPayload = (SingleStateBlockPayload)msg.Payload;
                    if (_networkManager.IsSyncing)
                    {
                        return;
                    }

                    var validationResult = EventPublisher.GetInstance().PublishUnvalidatedBlockCreated(node, new BlockCreatedEventArgs(blockPayload.Block));
                    if (validationResult == false)
                    {
                        //await node.Disconnect(); // Dishonest node, buuh!
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("An {0} occurred during the process of handling a {1} message: {2}. Node will be disconnected.", ex.GetType().Name, msg.Command.ToString(), ex.Message);
                node?.Disconnect();
            }
        }