From 45f42b3ed3111eefe20e07317261028361320b95 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Tue, 19 Apr 2022 08:10:45 +0800 Subject: [PATCH] 3.2.1 (#859) * neo-cli: tune MaxTransactionsPerBlock for testnet (#850) * Add new testnet network id (#852) * typo, comment (#847) * Install plugin and dependencies. (#807) --- CHANGELOG.md | 8 + Neo.ConsoleService/CommandToken.cs | 4 +- Neo.ConsoleService/ConsoleCommandMethod.cs | 2 +- Neo.ConsoleService/ConsoleServiceBase.cs | 74 +++---- Neo.ConsoleService/ServiceProxy.cs | 8 +- neo-cli/CLI/ConsolePercent.cs | 9 +- neo-cli/CLI/MainService.Contracts.cs | 17 +- neo-cli/CLI/MainService.NEP17.cs | 18 +- neo-cli/CLI/MainService.Plugins.cs | 205 +++++++++++++++--- neo-cli/CLI/MainService.Tools.cs | 18 +- neo-cli/CLI/MainService.Vote.cs | 14 +- neo-cli/CLI/MainService.Wallet.cs | 16 +- neo-cli/CLI/MainService.cs | 57 ++--- neo-cli/config.testnet.json | 14 +- neo-cli/neo-cli.csproj | 6 +- neo-gui/neo-gui.csproj | 4 +- .../Neo.ConsoleService.Tests.csproj | 6 +- 17 files changed, 307 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa05d4e92..d12ec0cc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Changelog All notable changes to this project will be documented in this file. +## [3.2.1] + +### Changed +- ([#807](https://github.com/neo-project/neo-node/pull/807/)) Install plugin and dependencies +- ([#850](https://github.com/neo-project/neo-node/pull/850/)) Modify MaxTransactionsPerBlock for testnet +- ([#852](https://github.com/neo-project/neo-node/pull/852/)) Add new testnet network id +- ([#847](https://github.com/neo-project/neo-node/pull/847/)) typo, comment + ## [3.1.0] ### Changed diff --git a/Neo.ConsoleService/CommandToken.cs b/Neo.ConsoleService/CommandToken.cs index fedb601b2..f3bf1fa64 100644 --- a/Neo.ConsoleService/CommandToken.cs +++ b/Neo.ConsoleService/CommandToken.cs @@ -29,7 +29,7 @@ internal abstract class CommandToken /// /// Value /// - public string Value { get; protected set; } + public string Value { get; protected init; } /// /// Constructor @@ -152,7 +152,7 @@ public static void Trim(List args) // Trim end - while (args.Count > 0 && args[args.Count - 1].Type == CommandTokenType.Space) + while (args.Count > 0 && args[^1].Type == CommandTokenType.Space) { args.RemoveAt(args.Count - 1); } diff --git a/Neo.ConsoleService/ConsoleCommandMethod.cs b/Neo.ConsoleService/ConsoleCommandMethod.cs index d0949a68f..df241ce5f 100644 --- a/Neo.ConsoleService/ConsoleCommandMethod.cs +++ b/Neo.ConsoleService/ConsoleCommandMethod.cs @@ -52,7 +52,7 @@ internal class ConsoleCommandMethod /// /// Instance /// Method - /// Verbs + /// Attribute public ConsoleCommandMethod(object instance, MethodInfo method, ConsoleCommandAttribute attribute) { Method = method; diff --git a/Neo.ConsoleService/ConsoleServiceBase.cs b/Neo.ConsoleService/ConsoleServiceBase.cs index bffa0ef7d..cb62382ba 100644 --- a/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/Neo.ConsoleService/ConsoleServiceBase.cs @@ -35,11 +35,11 @@ public abstract class ConsoleServiceBase public bool ReadingPassword { get; set; } = false; private bool _running; - private readonly CancellationTokenSource _shutdownTokenSource = new CancellationTokenSource(); - private readonly CountdownEvent _shutdownAcknowledged = new CountdownEvent(1); - private readonly Dictionary> _verbs = new Dictionary>(); - private readonly Dictionary _instances = new Dictionary(); - private readonly Dictionary, bool, object>> _handlers = new Dictionary, bool, object>>(); + private readonly CancellationTokenSource _shutdownTokenSource = new(); + private readonly CountdownEvent _shutdownAcknowledged = new(1); + private readonly Dictionary> _verbs = new(); + private readonly Dictionary _instances = new(); + private readonly Dictionary, bool, object>> _handlers = new(); private bool OnCommand(string commandLine) { @@ -188,10 +188,10 @@ protected void OnHelpCommand(string key) withHelp.Sort((a, b) => { - var cate = a.HelpCategory.CompareTo(b.HelpCategory); + var cate = string.Compare(a.HelpCategory, b.HelpCategory, StringComparison.Ordinal); if (cate == 0) { - cate = a.Key.CompareTo(b.Key); + cate = string.Compare(a.Key, b.Key, StringComparison.Ordinal); } return cate; }); @@ -234,7 +234,7 @@ protected void OnHelpCommand(string key) if (lastKey != command.Key) { - Console.WriteLine($"You can call this command like this:"); + Console.WriteLine("You can call this command like this:"); lastKey = command.Key; } @@ -247,7 +247,7 @@ protected void OnHelpCommand(string key) if (!found) { - throw new ArgumentException($"Command not found."); + throw new ArgumentException("Command not found."); } } } @@ -297,8 +297,7 @@ public virtual void OnStop() public string ReadUserInput(string prompt, bool password = false) { const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; - StringBuilder sb = new StringBuilder(); - ConsoleKeyInfo key; + var sb = new StringBuilder(); if (!string.IsNullOrEmpty(prompt)) { @@ -316,6 +315,7 @@ public string ReadUserInput(string prompt, bool password = false) } else { + ConsoleKeyInfo key; do { key = Console.ReadKey(true); @@ -323,14 +323,7 @@ public string ReadUserInput(string prompt, bool password = false) if (t.IndexOf(key.KeyChar) != -1) { sb.Append(key.KeyChar); - if (password) - { - Console.Write('*'); - } - else - { - Console.Write(key.KeyChar); - } + Console.Write(password ? '*' : key.KeyChar); } else if (key.Key == ConsoleKey.Backspace && sb.Length > 0) { @@ -411,30 +404,25 @@ protected ConsoleServiceBase() { // Register self commands - RegisterCommandHander((args, canConsumeAll) => - { - return CommandToken.ReadString(args, canConsumeAll); - }); + RegisterCommandHandler(CommandToken.ReadString); - RegisterCommandHander((args, canConsumeAll) => + RegisterCommandHandler((args, canConsumeAll) => { if (canConsumeAll) { var ret = CommandToken.ToString(args); args.Clear(); - return ret.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - } - else - { - return CommandToken.ReadString(args, false).Split(',', ' '); + return ret.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); } + + return CommandToken.ReadString(args, false).Split(',', ' '); }); - RegisterCommandHander(false, (str) => byte.Parse(str)); - RegisterCommandHander(false, (str) => str == "1" || str == "yes" || str == "y" || bool.Parse(str)); - RegisterCommandHander(false, (str) => ushort.Parse(str)); - RegisterCommandHander(false, (str) => uint.Parse(str)); - RegisterCommandHander(false, (str) => IPAddress.Parse(str)); + RegisterCommandHandler(false, str => byte.Parse(str)); + RegisterCommandHandler(false, str => str == "1" || str == "yes" || str == "y" || bool.Parse(str)); + RegisterCommandHandler(false, str => ushort.Parse(str)); + RegisterCommandHandler(false, str => uint.Parse(str)); + RegisterCommandHandler(false, IPAddress.Parse); } /// @@ -442,7 +430,7 @@ protected ConsoleServiceBase() /// /// Return type /// Handler - private void RegisterCommandHander(Func, bool, object> handler) + private void RegisterCommandHandler(Func, bool, object> handler) { _handlers[typeof(TRet)] = handler; } @@ -454,9 +442,9 @@ private void RegisterCommandHander(Func, bool, object> /// Return type /// Can consume all /// Handler - public void RegisterCommandHander(bool canConsumeAll, Func handler) + public void RegisterCommandHandler(bool canConsumeAll, Func handler) { - _handlers[typeof(TRet)] = (args, cosumeAll) => + _handlers[typeof(TRet)] = (args, _) => { var value = (T)_handlers[typeof(T)](args, canConsumeAll); return handler(value); @@ -469,11 +457,11 @@ public void RegisterCommandHander(bool canConsumeAll, Func h /// Base type /// Return type /// Handler - public void RegisterCommandHander(Func handler) + public void RegisterCommandHandler(Func handler) { - _handlers[typeof(TRet)] = (args, cosumeAll) => + _handlers[typeof(TRet)] = (args, consumeAll) => { - var value = (T)_handlers[typeof(T)](args, cosumeAll); + var value = (T)_handlers[typeof(T)](args, consumeAll); return handler(value); }; } @@ -498,7 +486,7 @@ public void RegisterCommand(object instance, string name = null) if (!method.GetParameters().All(u => u.ParameterType.IsEnum || _handlers.ContainsKey(u.ParameterType))) { - throw new ArgumentException("Handler not found for the command: " + method.ToString()); + throw new ArgumentException("Handler not found for the command: " + method); } // Add command @@ -576,7 +564,7 @@ public void Run(string[] args) protected string ReadLine() { - Task readLineTask = Task.Run(() => Console.ReadLine()); + Task readLineTask = Task.Run(Console.ReadLine); try { @@ -623,7 +611,7 @@ public virtual void RunConsole() ConsoleHelper.Error("Command not found"); } } - catch (TargetInvocationException ex) + catch (TargetInvocationException ex) when (ex.InnerException is not null) { ConsoleHelper.Error(ex.InnerException.Message); } diff --git a/Neo.ConsoleService/ServiceProxy.cs b/Neo.ConsoleService/ServiceProxy.cs index a6fac7ebd..e3a8a982f 100644 --- a/Neo.ConsoleService/ServiceProxy.cs +++ b/Neo.ConsoleService/ServiceProxy.cs @@ -14,21 +14,21 @@ namespace Neo.ConsoleService { internal class ServiceProxy : ServiceBase { - private readonly ConsoleServiceBase service; + private readonly ConsoleServiceBase _service; public ServiceProxy(ConsoleServiceBase service) { - this.service = service; + this._service = service; } protected override void OnStart(string[] args) { - service.OnStart(args); + _service.OnStart(args); } protected override void OnStop() { - service.OnStop(); + _service.OnStop(); } } } diff --git a/neo-cli/CLI/ConsolePercent.cs b/neo-cli/CLI/ConsolePercent.cs index cd9f36f15..364e67221 100644 --- a/neo-cli/CLI/ConsolePercent.cs +++ b/neo-cli/CLI/ConsolePercent.cs @@ -16,7 +16,8 @@ public class ConsolePercent : IDisposable { #region Variables - private long _maxValue, _value; + private readonly long _maxValue; + private long _value; private decimal _lastFactor; private string _lastPercent; @@ -33,7 +34,7 @@ public class ConsolePercent : IDisposable /// public long Value { - get { return _value; } + get => _value; set { if (value == _value) return; @@ -48,8 +49,8 @@ public long Value /// public long MaxValue { - get { return _maxValue; } - set + get => _maxValue; + init { if (value == _maxValue) return; diff --git a/neo-cli/CLI/MainService.Contracts.cs b/neo-cli/CLI/MainService.Contracts.cs index 1a32e3f5c..74ac577e6 100644 --- a/neo-cli/CLI/MainService.Contracts.cs +++ b/neo-cli/CLI/MainService.Contracts.cs @@ -26,6 +26,7 @@ partial class MainService /// /// File path /// Manifest path + /// Extra data for deploy [ConsoleCommand("deploy", Category = "Contract Commands")] private void OnDeployCommand(string filePath, string manifestPath = null, JObject data = null) { @@ -57,8 +58,12 @@ private void OnDeployCommand(string filePath, string manifestPath = null, JObjec /// /// Process "update" command /// + /// Script hash /// File path /// Manifest path + /// Sender + /// Signer Accounts + /// Extra data for update [ConsoleCommand("update", Category = "Contract Commands")] private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifestPath, UInt160 sender, UInt160[] signerAccounts = null, JObject data = null) { @@ -68,7 +73,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes if (sender != null) { if (signerAccounts == null) - signerAccounts = new UInt160[1] { sender }; + signerAccounts = new[] { sender }; else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) { var signersList = signerAccounts.ToList(); @@ -82,13 +87,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); } - Transaction tx = new Transaction - { - Signers = signers, - Attributes = Array.Empty(), - Witnesses = Array.Empty() - }; - + Transaction tx; try { byte[] script = LoadUpdateScript(scriptHash, filePath, manifestPath, data, out var nef, out var manifest); @@ -127,7 +126,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes /// Contract parameters /// Transaction's sender /// Signer's accounts - /// Max fee for running the script + /// Max fee for running the script [ConsoleCommand("invoke", Category = "Contract Commands")] private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160 sender = null, UInt160[] signerAccounts = null, decimal maxGas = 20) { diff --git a/neo-cli/CLI/MainService.NEP17.cs b/neo-cli/CLI/MainService.NEP17.cs index 8cce43dbf..ff06974bf 100644 --- a/neo-cli/CLI/MainService.NEP17.cs +++ b/neo-cli/CLI/MainService.NEP17.cs @@ -16,7 +16,9 @@ using Neo.VM.Types; using Neo.Wallets; using System; +using System.Collections.Generic; using System.Linq; +using Array = System.Array; namespace Neo.CLI { @@ -27,7 +29,7 @@ partial class MainService /// /// Script hash /// To - /// Ammount + /// Amount /// From /// Data /// Signer's accounts @@ -58,7 +60,7 @@ private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UI Scopes = WitnessScope.CalledByEntry, Account = p }) - .ToArray() ?? new Signer[0]); + .ToArray() ?? Array.Empty()); } catch (InvalidOperationException e) { @@ -80,9 +82,11 @@ private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UI [ConsoleCommand("balanceOf", Category = "NEP17 Commands")] private void OnBalanceOfCommand(UInt160 tokenHash, UInt160 address) { - var arg = new JObject(); - arg["type"] = "Hash160"; - arg["value"] = address.ToString(); + var arg = new JObject + { + ["type"] = "Hash160", + ["value"] = address.ToString() + }; var asset = new AssetDescriptor(NeoSystem.StoreView, NeoSystem.Settings, tokenHash); @@ -113,7 +117,7 @@ private void OnNameCommand(UInt160 tokenHash) [ConsoleCommand("decimals", Category = "NEP17 Commands")] private void OnDecimalsCommand(UInt160 tokenHash) { - if (!OnInvokeWithResult(tokenHash, "decimals", out StackItem result, null)) return; + if (!OnInvokeWithResult(tokenHash, "decimals", out StackItem result)) return; ConsoleHelper.Info("Result: ", $"{((PrimitiveType)result).GetInteger()}"); } @@ -125,7 +129,7 @@ private void OnDecimalsCommand(UInt160 tokenHash) [ConsoleCommand("totalSupply", Category = "NEP17 Commands")] private void OnTotalSupplyCommand(UInt160 tokenHash) { - if (!OnInvokeWithResult(tokenHash, "totalSupply", out StackItem result, null)) return; + if (!OnInvokeWithResult(tokenHash, "totalSupply", out StackItem result)) return; var asset = new AssetDescriptor(NeoSystem.StoreView, NeoSystem.Settings, tokenHash); var totalSupply = new BigDecimal(((PrimitiveType)result).GetInteger(), asset.Decimals); diff --git a/neo-cli/CLI/MainService.Plugins.cs b/neo-cli/CLI/MainService.Plugins.cs index f61117682..9347366f8 100644 --- a/neo-cli/CLI/MainService.Plugins.cs +++ b/neo-cli/CLI/MainService.Plugins.cs @@ -8,15 +8,18 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Microsoft.Extensions.Configuration; using Neo.ConsoleService; using Neo.IO.Json; using Neo.Plugins; using System; +using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Net.Http; +using System.Security.Cryptography; using System.Threading.Tasks; namespace Neo.CLI @@ -30,16 +33,53 @@ partial class MainService [ConsoleCommand("install", Category = "Plugin Commands")] private async Task OnInstallCommandAsync(string pluginName) { + if (PluginExists(pluginName)) + { + ConsoleHelper.Warning($"Plugin already exist."); + return; + } + + await InstallPluginAsync(pluginName); + ConsoleHelper.Warning("Install successful, please restart neo-cli."); + } + + /// + /// Force to install a plugin again. This will overwrite + /// existing plugin files, in case of any file missing or + /// damage to the old version. + /// + /// name of the plugin + [ConsoleCommand("reinstall", Category = "Plugin Commands", Description = "Overwrite existing plugin by force.")] + private async Task OnReinstallCommand(string pluginName) + { + await InstallPluginAsync(pluginName, overWrite: true); + ConsoleHelper.Warning("Reinstall successful, please restart neo-cli."); + } + + /// + /// Download plugin from github release + /// The function of download and install are divided + /// for the consideration of `update` command that + /// might be added in the future. + /// + /// name of the plugin + /// Downloaded content + private async Task DownloadPluginAsync(string pluginName) + { + var url = + $"https://github.com/neo-project/neo-modules/releases/download/v{typeof(Plugin).Assembly.GetVersion()}/{pluginName}.zip"; using HttpClient http = new(); - HttpResponseMessage response = await http.GetAsync($"https://github.com/neo-project/neo-modules/releases/download/v{typeof(Plugin).Assembly.GetVersion()}/{pluginName}.zip"); + HttpResponseMessage response = await http.GetAsync(url); if (response.StatusCode == HttpStatusCode.NotFound) { response.Dispose(); - Version version_core = typeof(Plugin).Assembly.GetName().Version; - HttpRequestMessage request = new(HttpMethod.Get, "https://api.github.com/repos/neo-project/neo-modules/releases"); - request.Headers.UserAgent.ParseAdd($"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); - using HttpResponseMessage response_api = await http.SendAsync(request); - byte[] buffer = await response_api.Content.ReadAsByteArrayAsync(); + Version versionCore = typeof(Plugin).Assembly.GetName().Version; + HttpRequestMessage request = new(HttpMethod.Get, + "https://api.github.com/repos/neo-project/neo-modules/releases"); + request.Headers.UserAgent.ParseAdd( + $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); + using HttpResponseMessage responseApi = await http.SendAsync(request); + byte[] buffer = await responseApi.Content.ReadAsByteArrayAsync(); JObject releases = JObject.Parse(buffer); JObject asset = releases.GetArray() .Where(p => !p["tag_name"].GetString().Contains('-')) @@ -49,25 +89,92 @@ private async Task OnInstallCommandAsync(string pluginName) Assets = p["assets"].GetArray() }) .OrderByDescending(p => p.Version) - .First(p => p.Version <= version_core).Assets + .First(p => p.Version <= versionCore).Assets .FirstOrDefault(p => p["name"].GetString() == $"{pluginName}.zip"); if (asset is null) throw new Exception("Plugin doesn't exist."); response = await http.GetAsync(asset["browser_download_url"].GetString()); } + using (response) { - using Stream stream = await response.Content.ReadAsStreamAsync(); - using ZipArchive zip = new(stream, ZipArchiveMode.Read); - try - { - zip.ExtractToDirectory("."); - ConsoleHelper.Info("Install successful, please restart neo-cli."); - } - catch (IOException) + var totalRead = 0L; + byte[] buffer = new byte[1024]; + int read; + await using Stream stream = await response.Content.ReadAsStreamAsync(); + ConsoleHelper.Info("From ", $"{url}"); + var output = new MemoryStream(); + while ((read = await stream.ReadAsync(buffer)) > 0) { - ConsoleHelper.Warning($"Plugin already exist."); + output.Write(buffer, 0, read); + totalRead += read; + Console.Write( + $"\rDownloading {pluginName}.zip {totalRead / 1024}KB/{response.Content.Headers.ContentLength / 1024}KB {(totalRead * 100) / response.Content.Headers.ContentLength}%"); } + + Console.WriteLine(); + return output; + } + } + + /// + /// Install plugin from stream + /// + /// name of the plugin + /// Install by force for `update` + private async Task InstallPluginAsync(string pluginName, HashSet installed = null, + bool overWrite = false) + { + installed ??= new HashSet(); + if (!installed.Add(pluginName)) return; + if (!overWrite && PluginExists(pluginName)) return; + + await using MemoryStream stream = await DownloadPluginAsync(pluginName); + using (SHA256 sha256 = SHA256.Create()) + { + ConsoleHelper.Info("SHA256: ", $"{sha256.ComputeHash(stream.ToArray()).ToHexString()}"); } + + using ZipArchive zip = new(stream, ZipArchiveMode.Read); + ZipArchiveEntry entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); + if (entry is not null) + { + await using Stream es = entry.Open(); + await InstallDependenciesAsync(es, installed); + } + zip.ExtractToDirectory("./", true); + } + + /// + /// Install the dependency of the plugin + /// + /// plugin config path in temp + /// Dependency set + private async Task InstallDependenciesAsync(Stream config, HashSet installed) + { + IConfigurationSection dependency = new ConfigurationBuilder() + .AddJsonStream(config) + .Build() + .GetSection("Dependency"); + + if (!dependency.Exists()) return; + var dependencies = dependency.GetChildren().Select(p => p.Get()).ToArray(); + if (dependencies.Length == 0) return; + + foreach (string plugin in dependencies.Where(p => !PluginExists(p))) + { + ConsoleHelper.Info($"Installing dependency: {plugin}"); + await InstallPluginAsync(plugin, installed); + } + } + + /// + /// Check that the plugin has all necessary files + /// + /// Name of the plugin + /// + private static bool PluginExists(string pluginName) + { + return File.Exists($"Plugins/{pluginName}.dll"); } /// @@ -77,30 +184,77 @@ private async Task OnInstallCommandAsync(string pluginName) [ConsoleCommand("uninstall", Category = "Plugin Commands")] private void OnUnInstallCommand(string pluginName) { - var plugin = Plugin.Plugins.FirstOrDefault(p => p.Name == pluginName); - if (plugin is null) + if (!PluginExists(pluginName)) { ConsoleHelper.Warning("Plugin not found"); return; } - if (plugin is Logger) + + var plugin = Plugin.Plugins.FirstOrDefault(p => p.Name == pluginName); + if (plugin is not null) { - ConsoleHelper.Warning("You cannot uninstall a built-in plugin."); - return; + if (plugin is Logger) + { + ConsoleHelper.Warning("You cannot uninstall a built-in plugin."); + return; + } + + Plugin.Plugins.Remove(plugin); + } + + foreach (var p in Plugin.Plugins) + { + try + { + using var reader = File.OpenRead($"./Plugins/{p.Name}/config.json"); + if (new ConfigurationBuilder() + .AddJsonStream(reader) + .Build() + .GetSection("Dependency") + .GetChildren() + .Select(d => d.Get()) + .Any(v => v == pluginName)) + { + ConsoleHelper.Error( + $"Can not uninstall. Other plugins depend on this plugin, try `reinstall {pluginName}` if the plugin is broken."); + return; + } + } + catch (Exception) + { + // ignored + } } - File.Delete(plugin.Path); - File.Delete(plugin.ConfigFile); try { - Directory.Delete(Path.GetDirectoryName(plugin.ConfigFile), false); + DeleteFiles(new[] { $"Plugins/{pluginName}.dll", $"Plugins/{pluginName}/config.json" }); + Directory.Delete($"Plugins/{pluginName}", false); } catch (IOException) { } + ConsoleHelper.Info("Uninstall successful, please restart neo-cli."); } + private static void DeleteFiles(IEnumerable list) + { + foreach (var file in list) + { + try + { + if (!File.Exists(file)) continue; + ConsoleHelper.Info("Deleting ", file); + File.Delete(file); + } + catch (Exception) + { + // ignored + } + } + } + /// /// Process "plugins" command /// @@ -113,7 +267,8 @@ private void OnPluginsCommand() foreach (Plugin plugin in Plugin.Plugins) { if (plugin is Logger) continue; - ConsoleHelper.Info($"\t{plugin.Name,-20}", plugin.Description); + var name = $"{plugin.Name}@{plugin.Version}"; + Console.WriteLine($"\t{name,-25}{plugin.Description}"); } } else diff --git a/neo-cli/CLI/MainService.Tools.cs b/neo-cli/CLI/MainService.Tools.cs index 05d6df487..f5be9a648 100644 --- a/neo-cli/CLI/MainService.Tools.cs +++ b/neo-cli/CLI/MainService.Tools.cs @@ -80,13 +80,7 @@ private string HexToString(string hexString) var clearHexString = ClearHexString(hexString); var bytes = clearHexString.HexToBytes(); var utf8String = Utility.StrictUTF8.GetString(bytes); - - if (!IsPrintable(utf8String)) - { - return null; - } - - return utf8String; + return IsPrintable(utf8String) ? utf8String : null; } catch { @@ -416,14 +410,8 @@ private string Base64ToString(string bytearray) try { byte[] result = Convert.FromBase64String(bytearray); - string utf8string = Utility.StrictUTF8.GetString(result); - - if (!IsPrintable(utf8string)) - { - return null; - } - - return utf8string; + string utf8String = Utility.StrictUTF8.GetString(result); + return IsPrintable(utf8String) ? utf8String : null; } catch { diff --git a/neo-cli/CLI/MainService.Vote.cs b/neo-cli/CLI/MainService.Vote.cs index b8ffdb988..da9be9953 100644 --- a/neo-cli/CLI/MainService.Vote.cs +++ b/neo-cli/CLI/MainService.Vote.cs @@ -17,6 +17,7 @@ using Neo.VM.Types; using Neo.Wallets; using System; +using System.Linq; using System.Numerics; namespace Neo.CLI @@ -27,7 +28,6 @@ partial class MainService /// Process "register candidate" command /// /// register account scriptHash - /// Max fee for running the script [ConsoleCommand("register candidate", Category = "Vote Commands")] private void OnRegisterCandidateCommand(UInt160 account) { @@ -49,7 +49,7 @@ private void OnRegisterCandidateCommand(UInt160 account) } } - ECPoint publicKey = currentAccount?.GetKey()?.PublicKey; + ECPoint publicKey = currentAccount.GetKey()?.PublicKey; byte[] script; using (ScriptBuilder scriptBuilder = new ScriptBuilder()) { @@ -63,7 +63,7 @@ private void OnRegisterCandidateCommand(UInt160 account) /// /// Process "unregister candidate" command /// - /// unregister account scriptHash + /// unregister account scriptHash [ConsoleCommand("unregister candidate", Category = "Vote Commands")] private void OnUnregisterCandidateCommand(UInt160 account) { @@ -208,9 +208,11 @@ private void OnGetNextBlockValidatorsCommand() private void OnGetAccountState(UInt160 address) { string notice = "No vote record!"; - var arg = new JObject(); - arg["type"] = "Hash160"; - arg["value"] = address.ToString(); + var arg = new JObject + { + ["type"] = "Hash160", + ["value"] = address.ToString() + }; if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getAccountState", out StackItem result, null, new JArray(arg))) return; Console.WriteLine(); diff --git a/neo-cli/CLI/MainService.Wallet.cs b/neo-cli/CLI/MainService.Wallet.cs index 0db3eb313..f56a759ff 100644 --- a/neo-cli/CLI/MainService.Wallet.cs +++ b/neo-cli/CLI/MainService.Wallet.cs @@ -90,14 +90,14 @@ private void OnUpgradeWalletCommand(string path) ConsoleHelper.Info("Cancelled"); return; } - string path_new = Path.ChangeExtension(path, ".json"); - if (File.Exists(path_new)) + string pathNew = Path.ChangeExtension(path, ".json"); + if (File.Exists(pathNew)) { - ConsoleHelper.Warning($"File '{path_new}' already exists"); + ConsoleHelper.Warning($"File '{pathNew}' already exists"); return; } - NEP6Wallet.Migrate(path_new, path, password, NeoSystem.Settings).Save(); - Console.WriteLine($"Wallet file upgrade complete. New wallet file has been auto-saved at: {path_new}"); + NEP6Wallet.Migrate(pathNew, path, password, NeoSystem.Settings).Save(); + Console.WriteLine($"Wallet file upgrade complete. New wallet file has been auto-saved at: {pathNew}"); } /// @@ -252,7 +252,7 @@ private void OnImportMultisigAddress(ushort m, ECPoint[] publicKeys) Contract multiSignContract = Contract.CreateMultiSigContract(m, publicKeys); KeyPair keyPair = CurrentWallet.GetAccounts().FirstOrDefault(p => p.HasKey && publicKeys.Contains(p.GetKey().PublicKey))?.GetKey(); - WalletAccount account = CurrentWallet.CreateAccount(multiSignContract, keyPair); + CurrentWallet.CreateAccount(multiSignContract, keyPair); if (CurrentWallet is NEP6Wallet wallet) wallet.Save(); @@ -466,7 +466,7 @@ private void OnSignCommand(JObject jsonObjectToSign) { var snapshot = NeoSystem.StoreView; ContractParametersContext context = ContractParametersContext.Parse(jsonObjectToSign.ToString(), snapshot); - if (context.Network != neoSystem.Settings.Network) + if (context.Network != _neoSystem.Settings.Network) { ConsoleHelper.Warning("Network mismatch."); return; @@ -636,7 +636,7 @@ private void SignAndSendTx(DataCache snapshot, Transaction tx) ContractParametersContext context; try { - context = new ContractParametersContext(snapshot, tx, neoSystem.Settings.Network); + context = new ContractParametersContext(snapshot, tx, _neoSystem.Settings.Network); } catch (InvalidOperationException e) { diff --git a/neo-cli/CLI/MainService.cs b/neo-cli/CLI/MainService.cs index 6fa7853e8..89493e03d 100644 --- a/neo-cli/CLI/MainService.cs +++ b/neo-cli/CLI/MainService.cs @@ -36,6 +36,7 @@ using System.Reflection; using System.Text.RegularExpressions; using System.Threading; +using Array = System.Array; namespace Neo.CLI { @@ -45,33 +46,24 @@ public partial class MainService : ConsoleServiceBase, IWalletProvider public const long TestModeGas = 20_00000000; - private Wallet currentWallet; + private Wallet _currentWallet; public LocalNode LocalNode; public Wallet CurrentWallet { - get - { - return currentWallet; - } + get => _currentWallet; private set { - currentWallet = value; + _currentWallet = value; WalletChanged?.Invoke(this, value); } } - private NeoSystem neoSystem; + private NeoSystem _neoSystem; public NeoSystem NeoSystem { - get - { - return neoSystem; - } - private set - { - neoSystem = value; - } + get => _neoSystem; + private set => _neoSystem = value; } protected override string Prompt => "neo"; @@ -82,15 +74,15 @@ private set /// public MainService() : base() { - RegisterCommandHander(false, (str) => StringToAddress(str, NeoSystem.Settings.AddressVersion)); - RegisterCommandHander(false, (str) => UInt256.Parse(str)); - RegisterCommandHander((str) => str.Select(u => UInt256.Parse(u.Trim())).ToArray()); - RegisterCommandHander((arr) => arr.Select(str => StringToAddress(str, NeoSystem.Settings.AddressVersion)).ToArray()); - RegisterCommandHander((str) => ECPoint.Parse(str.Trim(), ECCurve.Secp256r1)); - RegisterCommandHander((str) => str.Select(u => ECPoint.Parse(u.Trim(), ECCurve.Secp256r1)).ToArray()); - RegisterCommandHander((str) => JObject.Parse(str)); - RegisterCommandHander((str) => decimal.Parse(str, CultureInfo.InvariantCulture)); - RegisterCommandHander((obj) => (JArray)obj); + RegisterCommandHandler(false, str => StringToAddress(str, NeoSystem.Settings.AddressVersion)); + RegisterCommandHandler(false, UInt256.Parse); + RegisterCommandHandler(str => str.Select(u => UInt256.Parse(u.Trim())).ToArray()); + RegisterCommandHandler(arr => arr.Select(str => StringToAddress(str, NeoSystem.Settings.AddressVersion)).ToArray()); + RegisterCommandHandler(str => ECPoint.Parse(str.Trim(), ECCurve.Secp256r1)); + RegisterCommandHandler(str => str.Select(u => ECPoint.Parse(u.Trim(), ECCurve.Secp256r1)).ToArray()); + RegisterCommandHandler(str => JObject.Parse(str)); + RegisterCommandHandler(str => decimal.Parse(str, CultureInfo.InvariantCulture)); + RegisterCommandHandler(obj => (JArray)obj); RegisterCommand(this); } @@ -483,7 +475,7 @@ public async void Start(string[] args) public void Stop() { - Interlocked.Exchange(ref neoSystem, null)?.Dispose(); + Interlocked.Exchange(ref _neoSystem, null)?.Dispose(); } private void WriteBlocks(uint start, uint count, string path, bool writeStart) @@ -548,14 +540,14 @@ private static void WriteLineWithoutFlicker(string message = "", int maxWidth = /// Max fee for running the script private void SendTransaction(byte[] script, UInt160 account = null, long gas = TestModeGas) { - Signer[] signers = System.Array.Empty(); + Signer[] signers = Array.Empty(); var snapshot = NeoSystem.StoreView; if (account != null) { signers = CurrentWallet.GetAccounts() .Where(p => !p.Lock && !p.WatchOnly && p.ScriptHash == account && NativeContract.GAS.BalanceOf(snapshot, p.ScriptHash).Sign > 0) - .Select(p => new Signer() { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) + .Select(p => new Signer { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) .ToArray(); } @@ -580,10 +572,7 @@ private void SendTransaction(byte[] script, UInt160 account = null, long gas = T catch (InvalidOperationException e) { ConsoleHelper.Error(GetExceptionMessage(e)); - return; } - - return; } /// @@ -592,12 +581,12 @@ private void SendTransaction(byte[] script, UInt160 account = null, long gas = T /// Script hash /// Operation /// Result - /// Transaction + /// Transaction /// Contract parameters /// Show result stack if it is true /// Max fee for running the script /// Return true if it was successful - private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable verificable = null, JArray contractParameters = null, bool showStack = true, long gas = TestModeGas) + private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable verifiable = null, JArray contractParameters = null, bool showStack = true, long gas = TestModeGas) { List parameters = new List(); @@ -635,12 +624,12 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI ConsoleHelper.Info("Invoking script with: ", $"'{script.ToBase64String()}'"); } - if (verificable is Transaction tx) + if (verifiable is Transaction tx) { tx.Script = script; } - using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verificable, settings: NeoSystem.Settings, gas: gas); + using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: gas); PrintExecutionOutput(engine, showStack); result = engine.State == VMState.FAULT ? null : engine.ResultStack.Peek(); return engine.State != VMState.FAULT; diff --git a/neo-cli/config.testnet.json b/neo-cli/config.testnet.json index f151c2625..7ee048897 100644 --- a/neo-cli/config.testnet.json +++ b/neo-cli/config.testnet.json @@ -23,10 +23,10 @@ } }, "ProtocolConfiguration": { - "Network": 877933390, + "Network": 894710606, "AddressVersion": 53, "MillisecondsPerBlock": 15000, - "MaxTransactionsPerBlock": 512, + "MaxTransactionsPerBlock": 5000, "MemoryPoolMaxTransactions": 50000, "MaxTraceableBlocks": 2102400, "InitialGasDistribution": 5200000000000000, @@ -55,11 +55,11 @@ "03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9" ], "SeedList": [ - "seed1t4.neo.org:20333", - "seed2t4.neo.org:20333", - "seed3t4.neo.org:20333", - "seed4t4.neo.org:20333", - "seed5t4.neo.org:20333" + "seed1t5.neo.org:20333", + "seed2t5.neo.org:20333", + "seed3t5.neo.org:20333", + "seed4t5.neo.org:20333", + "seed5t5.neo.org:20333" ] } } diff --git a/neo-cli/neo-cli.csproj b/neo-cli/neo-cli.csproj index 208fd90e4..9993e5ef9 100644 --- a/neo-cli/neo-cli.csproj +++ b/neo-cli/neo-cli.csproj @@ -1,9 +1,9 @@ - 2016-2021 The Neo Project + 2016-2022 The Neo Project Neo.CLI - 3.1.0 + 3.2.1 The Neo Project net6.0 neo-cli @@ -23,7 +23,7 @@ - + diff --git a/neo-gui/neo-gui.csproj b/neo-gui/neo-gui.csproj index 13a14e02b..94a56ec90 100644 --- a/neo-gui/neo-gui.csproj +++ b/neo-gui/neo-gui.csproj @@ -1,9 +1,9 @@ - 2016-2021 The Neo Project + 2016-2022 The Neo Project Neo.GUI - 3.1.0 + 3.2.1 The Neo Project WinExe net6.0-windows diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 0e94b37d0..48273aad7 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -6,9 +6,9 @@ - - - + + +