private Message HandleMessage(Peer peer, Message msg) { if (msg.IsSigned && !msg.Address.IsNull) { if (msg.Address.IsUser) { peer.SetAddress(msg.Address); } else { return(new ErrorMessage(Address, this.PublicEndpoint, P2PError.InvalidAddress)); } } else { return(new ErrorMessage(Address, this.PublicEndpoint, P2PError.MessageShouldBeSigned)); } Endpoint endpoint; try { endpoint = Endpoint.FromString(msg.Host); } catch (ChainException e) { return(new ErrorMessage(Address, this.PublicEndpoint, P2PError.InvalidEndpoint)); } var peerKey = endpoint.ToString(); lock (_peers) { if (!_peers.ContainsKey(peerKey)) { Logger.Message("Added peer: " + peerKey); peer.UpdateEndpoint(endpoint); _peers[peerKey] = peer; } } Logger.Debug($"Got {msg.Opcode} message from {peerKey}"); switch (msg.Opcode) { case Opcode.EVENT: { var evtMessage = (EventMessage)msg; var evt = evtMessage.Event; Logger.Message("New event: " + evt.ToString()); return(null); } case Opcode.REQUEST: { var request = (RequestMessage)msg; if (request.NexusName != Nexus.Name) { return(new ErrorMessage(Address, this.PublicEndpoint, P2PError.InvalidNexus)); } if (request.Kind == RequestKind.None) { return(null); } var answer = new ListMessage(this.Address, this.PublicEndpoint, request.Kind); if (request.Kind.HasFlag(RequestKind.Peers)) { answer.SetPeers(this.Peers.Where(x => x != peer).Select(x => x.Endpoint.ToString())); } if (request.Kind.HasFlag(RequestKind.Chains)) { var chainList = Nexus.GetChains(Nexus.RootStorage); var chains = chainList.Select(x => Nexus.GetChainByName(x)).Select(x => new ChainInfo(x.Name, Nexus.GetParentChainByName(x.Name), x.Height)).ToArray(); answer.SetChains(chains); } if (request.Kind.HasFlag(RequestKind.Mempool) && Capabilities.HasFlag(PeerCaps.Mempool)) { var txs = _mempool.GetTransactions().Select(x => Base16.Encode(x.ToByteArray(true))); answer.SetMempool(txs); } if (request.Kind.HasFlag(RequestKind.Blocks)) { foreach (var entry in request.Blocks) { var chain = this.Nexus.GetChainByName(entry.Key); if (chain == null) { continue; } answer.AddBlockRange(chain, entry.Value); } } return(answer); } case Opcode.LIST: { var listMsg = (ListMessage)msg; var outKind = RequestKind.None; if (listMsg.Kind.HasFlag(RequestKind.Peers)) { IEnumerable <string> newPeers; lock (_peers) { newPeers = listMsg.Peers.Where(x => !_peers.ContainsKey(x)); } foreach (var entry in listMsg.Peers) { Logger.Message("New peer: " + entry.ToString()); } QueueEndpoints(newPeers); } var blockFetches = new Dictionary <string, RequestRange>(); if (listMsg.Kind.HasFlag(RequestKind.Chains)) { foreach (var entry in listMsg.Chains) { var chain = Nexus.GetChainByName(entry.name); // NOTE if we dont find this chain then it is too soon for ask for blocks from that chain if (chain != null && chain.Height < entry.height) { var start = chain.Height + 1; var end = entry.height; var limit = start + ListMessage.MaxBlocks - 1; if (end > limit) { end = limit; } blockFetches[entry.name] = new RequestRange(start, end); lock (_knownHeights) { BigInteger lastKnowHeight = _knownHeights.ContainsKey(chain.Name) ? _knownHeights[chain.Name] : 0; if (entry.height > lastKnowHeight) { _knownHeights[chain.Name] = entry.height; IsFullySynced = false; } } } } } if (listMsg.Kind.HasFlag(RequestKind.Mempool) && Capabilities.HasFlag(PeerCaps.Mempool)) { int submittedCount = 0; foreach (var txStr in listMsg.Mempool) { var bytes = Base16.Decode(txStr); var tx = Transaction.Unserialize(bytes); try { _mempool.Submit(tx); submittedCount++; } catch { } Logger.Message(submittedCount + " new transactions"); } } if (listMsg.Kind.HasFlag(RequestKind.Blocks)) { Chain chain = null; foreach (var entry in listMsg.Blocks) { chain = Nexus.GetChainByName(entry.Key); if (chain == null) { continue; } var blockRange = entry.Value; foreach (var block in blockRange.blocks) { var transactions = new List <Transaction>(); foreach (var txHash in block.TransactionHashes) { var tx = entry.Value.transactions[txHash]; transactions.Add(tx); } var maxPendingHeightExpected = chain.Height + ListMessage.MaxBlocks; if (block.Height > chain.Height && block.Height <= maxPendingHeightExpected) { var key = $"{chain.Name}.{block.Height}"; lock (_pendingBlocks) { _pendingBlocks[key] = new PendingBlock(chain.Name, block, transactions); } } } _lastRequestTime = DateTime.UtcNow; //Thread.Sleep(10000); } } if (blockFetches.Count > 0) { outKind |= RequestKind.Blocks; } if (outKind != RequestKind.None) { var answer = new RequestMessage(this.Address, this.PublicEndpoint, outKind, Nexus.Name); if (blockFetches.Count > 0) { answer.SetBlocks(blockFetches); } return(answer); } return(null); } case Opcode.MEMPOOL_Add: { if (Capabilities.HasFlag(PeerCaps.Mempool)) { var memtx = (MempoolAddMessage)msg; int submissionCount = 0; foreach (var tx in memtx.Transactions) { try { if (_mempool.Submit(tx)) { submissionCount++; } } catch { // ignore } } Logger.Message($"Added {submissionCount} txs to the mempool"); } return(null); } case Opcode.BLOCKS_List: { break; } case Opcode.ERROR: { var errorMsg = (ErrorMessage)msg; if (string.IsNullOrEmpty(errorMsg.Text)) { Logger.Error($"ERROR: {errorMsg.Code}"); } else { Logger.Error($"ERROR: {errorMsg.Code} ({errorMsg.Text})"); } return(null); } } throw new NodeException("No answer sent to request " + msg.Opcode); }
private Message HandleMessage(Peer peer, Message msg) { if (msg.IsSigned && !msg.Address.IsNull) { if (msg.Address.IsUser) { peer.SetAddress(msg.Address); } else { return(new ErrorMessage(Address, P2PError.InvalidAddress)); } } else { return(new ErrorMessage(Address, P2PError.MessageShouldBeSigned)); } switch (msg.Opcode) { case Opcode.EVENT: { var evtMessage = (EventMessage)msg; var evt = evtMessage.Event; Logger.Message("New event: " + evt.ToString()); return(null); } case Opcode.REQUEST: { var request = (RequestMessage)msg; if (request.NexusName != Nexus.Name) { return(new ErrorMessage(Address, P2PError.InvalidNexus)); } if (request.Kind == RequestKind.None) { return(null); } var answer = new ListMessage(this.Address, request.Kind); if (request.Kind.HasFlag(RequestKind.Peers)) { answer.SetPeers(this.Peers.Where(x => x != peer).Select(x => x.Endpoint)); } if (request.Kind.HasFlag(RequestKind.Chains)) { var chains = Nexus.Chains.Select(x => Nexus.FindChainByName(x)).Select(x => new ChainInfo(x.Name, Nexus.GetParentChainByName(x.Name), x.LastBlock != null ? x.LastBlock.Height : 0)); answer.SetChains(chains); } if (request.Kind.HasFlag(RequestKind.Mempool) && Capabilities.HasFlag(PeerCaps.Mempool)) { var txs = _mempool.GetTransactions().Select(x => Base16.Encode(x.ToByteArray(true))); answer.SetMempool(txs); } if (request.Kind.HasFlag(RequestKind.Blocks)) { foreach (var entry in request.Blocks) { var chain = this.Nexus.FindChainByName(entry.Key); if (chain == null) { continue; } var startBlock = entry.Value; if (startBlock > chain.BlockHeight) { continue; } var blockList = new List <string>(); var currentBlock = startBlock; while (blockList.Count < 50 && currentBlock <= chain.BlockHeight) { var block = chain.FindBlockByHeight(currentBlock); var bytes = block.ToByteArray(); var str = Base16.Encode(bytes); foreach (var tx in chain.GetBlockTransactions(block)) { var txBytes = tx.ToByteArray(true); str += "/" + Base16.Encode(txBytes); } blockList.Add(str); currentBlock++; } answer.AddBlockRange(chain.Name, startBlock, blockList); } } return(answer); } case Opcode.LIST: { var listMsg = (ListMessage)msg; var outKind = RequestKind.None; if (listMsg.Kind.HasFlag(RequestKind.Peers)) { var newPeers = listMsg.Peers.Where(x => !IsKnown(x)); foreach (var entry in listMsg.Peers) { Logger.Message("New peer: " + entry.ToString()); } QueueEndpoints(newPeers); } var blockFetches = new Dictionary <string, uint>(); if (listMsg.Kind.HasFlag(RequestKind.Chains)) { foreach (var entry in listMsg.Chains) { var chain = Nexus.FindChainByName(entry.name); // NOTE if we dont find this chain then it is too soon for ask for blocks from that chain if (chain != null && chain.BlockHeight < entry.height) { blockFetches[entry.name] = chain.BlockHeight + 1; } } } if (listMsg.Kind.HasFlag(RequestKind.Mempool) && Capabilities.HasFlag(PeerCaps.Mempool)) { int submittedCount = 0; foreach (var txStr in listMsg.Mempool) { var bytes = Base16.Decode(txStr); var tx = Transaction.Unserialize(bytes); try { _mempool.Submit(tx); submittedCount++; } catch { } Logger.Message(submittedCount + " new transactions"); } } if (listMsg.Kind.HasFlag(RequestKind.Blocks)) { bool addedBlocks = false; foreach (var entry in listMsg.Blocks) { var chain = Nexus.FindChainByName(entry.Key); if (chain == null) { continue; } var blockRange = entry.Value; var currentBlock = blockRange.startHeight; foreach (var rawBlock in blockRange.rawBlocks) { var temp = rawBlock.Split('/'); var block = Block.Unserialize(Base16.Decode(temp[0])); var transactions = new List <Transaction>(); for (int i = 1; i < temp.Length; i++) { var tx = Transaction.Unserialize(Base16.Decode(temp[i])); transactions.Add(tx); } // TODO this wont work in the future... try { chain.AddBlock(block, transactions, 1); } catch (Exception e) { throw new Exception("block add failed"); } Logger.Message($"Added block #{currentBlock} to {chain.Name}"); addedBlocks = true; currentBlock++; } } if (addedBlocks) { outKind |= RequestKind.Chains; } } if (blockFetches.Count > 0) { outKind |= RequestKind.Blocks; } if (outKind != RequestKind.None) { var answer = new RequestMessage(outKind, Nexus.Name, this.Address); if (blockFetches.Count > 0) { answer.SetBlocks(blockFetches); } return(answer); } break; } case Opcode.MEMPOOL_Add: { if (Capabilities.HasFlag(PeerCaps.Mempool)) { var memtx = (MempoolAddMessage)msg; var prevSize = _mempool.Size; foreach (var tx in memtx.Transactions) { _mempool.Submit(tx); } var count = _mempool.Size - prevSize; Logger.Message($"Added {count} txs to the mempool"); } break; } case Opcode.BLOCKS_List: { break; } case Opcode.ERROR: { var errorMsg = (ErrorMessage)msg; if (string.IsNullOrEmpty(errorMsg.Text)) { Logger.Error($"ERROR: {errorMsg.Code}"); } else { Logger.Error($"ERROR: {errorMsg.Code} ({errorMsg.Text})"); } break; } } Logger.Message("No answer sent."); return(null); }