private Message HandleMessage(Peer peer, Message msg) { if (msg.IsSigned && msg.Address != Address.Null) { peer.SetAddress(msg.Address); } 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)) { 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)) { 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, null); foreach (var hash in block.TransactionHashes) { var events = block.GetEventsForTransaction(hash); foreach (var evt in events) { AddEvent(evt); } } } 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: { 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); }
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; } } 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) { _knownHeights[chain.Name] = entry.height; } } } } 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); } if (block.Height > chain.Height) { 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 void SetupCommands(CommandDispatcher dispatcher) { ModuleLogger.Init(logger, gui); var minimumFee = this.mempool != null ? mempool.MinimumFee : 1; dispatcher.RegisterCommand("quit", "Stops the node and exits", (args) => Terminate()); if (gui != null) { dispatcher.RegisterCommand("gui.log", "Switches the gui to log view", (args) => gui.ShowLog(args)); dispatcher.RegisterCommand("gui.graph", "Switches the gui to graph view", (args) => gui.ShowGraph(args)); } dispatcher.RegisterCommand("help", "Lists available commands", (args) => dispatcher.Commands.ToList().ForEach(x => logger.Message($"{x.Name}\t{x.Description}"))); foreach (var method in nexusApi.Methods) { dispatcher.RegisterCommand("api." + method.Name, "API CALL", (args) => ExecuteAPI(method.Name, args)); } dispatcher.RegisterCommand("script.assemble", "Assembles a .asm file into Phantasma VM script format", (args) => ScriptModule.AssembleFile(args)); dispatcher.RegisterCommand("script.disassemble", $"Disassembles a {ScriptFormat.Extension} file into readable Phantasma assembly", (args) => ScriptModule.DisassembleFile(args)); dispatcher.RegisterCommand("script.compile", "Compiles a .sol file into Phantasma VM script format", (args) => ScriptModule.CompileFile(args)); dispatcher.RegisterCommand("wallet.open", "Opens a wallet from a WIF key", (args) => WalletModule.Open(args)); dispatcher.RegisterCommand("wallet.create", "Creates new a wallet", (args) => WalletModule.Create(args)); dispatcher.RegisterCommand("wallet.balance", "Shows the current wallet balance", (args) => WalletModule.Balance(nexusApi, restPort, neoScanAPI, args)); dispatcher.RegisterCommand("wallet.transfer", "Generates a new transfer transaction", (args) => WalletModule.Transfer(nexusApi, minimumFee, neoAPI, args)); dispatcher.RegisterCommand("wallet.stake", $"Stakes {DomainSettings.StakingTokenSymbol}", (args) => WalletModule.Stake(nexusApi, args)); dispatcher.RegisterCommand("wallet.airdrop", "Does a batch transfer from a .csv", (args) => WalletModule.Airdrop(args, nexusApi, minimumFee)); dispatcher.RegisterCommand("wallet.migrate", "Migrates a validator to another address ", (args) => { WalletModule.Migrate(args, nexusApi, minimumFee); if (mempool != null) { mempool.SetKeys(WalletModule.Keys); } }); dispatcher.RegisterCommand("file.upload", "Uploads a file into Phantasma", (args) => FileModule.Upload(WalletModule.Keys, nexusApi, args)); dispatcher.RegisterCommand("oracle.read", "Read transaction from oracle", (args) => { var hash = Hash.Parse(args[0]); var reader = nexus.CreateOracleReader(); var tx = reader.ReadTransaction("neo", "neo", hash); logger.Message(tx.Transfers[0].interopAddress.Text); }); if (mempool != null) { dispatcher.RegisterCommand("mempool.list", "Shows mempool pending transaction list", (args) => { var txs = mempool.GetTransactions(); foreach (var tx in txs) { logger.Message(tx.ToString()); } }); } dispatcher.RegisterCommand("neo.deploy", "Deploys a contract into NEO", (args) => { if (args.Length != 2) { throw new CommandException("Expected: WIF avm_path"); } var avmPath = args[1]; if (!File.Exists(avmPath)) { throw new CommandException("path for avm not found"); } var keys = Neo.Core.NeoKeys.FromWIF(args[0]); var script = File.ReadAllBytes(avmPath); var scriptHash = Neo.Utils.CryptoUtils.ToScriptHash(script); logger.Message("Deploying contract " + scriptHash); try { var tx = neoAPI.DeployContract(keys, script, Base16.Decode("0710"), 0x05, Neo.Core.ContractProperties.HasStorage | Neo.Core.ContractProperties.Payable, "Contract", "1.0", "Author", "*****@*****.**", "Description"); logger.Success("Deployed contract via transaction: " + tx.Hash); } catch (Exception e) { logger.Error("Failed to deploy contract: " + e.Message); } }); dispatcher.RegisterCommand("exit", "Terminates the node", (args) => { this.Terminate(); }); if (useSimulator) { dispatcher.RegisterCommand("simulator.timeskip", $"Skips minutse in simulator", (args) => { if (args.Length != 1) { throw new CommandException("Expected: minutes"); } var minutes = int.Parse(args[0]); simulator.CurrentTime += TimeSpan.FromMinutes(minutes); logger.Success($"Simulator time advanced by {minutes}"); }); } }
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 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)); 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; } var startBlock = entry.Value; if (startBlock > chain.Height) { continue; } answer.AddBlockRange(chain, startBlock, 1); } } 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, BigInteger>(); 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) { blockFetches[entry.name] = chain.Height + 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; 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); } if (chain.Height + 1 < block.Height) { _blockCache.Add(block.Height, Tuple.Create(block, transactions)); } else { addedBlocks = HandleBlock(chain, block, transactions); } } //Thread.Sleep(10000); } // check if we have any cached blocks TODO: needs to be revisited when we have multiple chains if (_blockCache.ContainsKey(chain.Height + 1)) { foreach (var entry in _blockCache.OrderBy(x => x.Key)) { if (entry.Key == chain.Height + 1) { addedBlocks = HandleBlock(chain, entry.Value.Item1 /*Block*/, entry.Value.Item2 /*Transactions*/); } } } 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; 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"); } 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); }