From bcf6eab8e90cf294741ab2623e430a82f6895dc2 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 31 Dec 2023 17:26:13 +0800 Subject: [PATCH 1/2] Fix: fix equal (#3028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix equal * fix format * remove redundent * make it more strick * expand the equal to jnumber and jstring * Apply suggestions from code review * Update src/Neo.Json/JNumber.cs --------- Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- src/Neo.Json/JBoolean.cs | 36 +++++++++++++++-- src/Neo.Json/JNumber.cs | 53 +++++++++++++++++++++++-- src/Neo.Json/JString.cs | 39 ++++++++++++++++-- tests/Neo.Json.UnitTests/UT_JBoolean.cs | 9 +++++ tests/Neo.Json.UnitTests/UT_JNumber.cs | 11 ++++- tests/Neo.Json.UnitTests/UT_JString.cs | 9 +++++ 6 files changed, 144 insertions(+), 13 deletions(-) diff --git a/src/Neo.Json/JBoolean.cs b/src/Neo.Json/JBoolean.cs index 9398270aae..feb3d16b1d 100644 --- a/src/Neo.Json/JBoolean.cs +++ b/src/Neo.Json/JBoolean.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, +// +// The Neo.Json is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -71,5 +71,33 @@ public static implicit operator JBoolean(bool value) { return new JBoolean(value); } + + public static bool operator ==(JBoolean left, JBoolean right) + { + return left.Value.Equals(right.Value); + } + + public static bool operator !=(JBoolean left, JBoolean right) + { + return !left.Value.Equals(right.Value); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + if (obj is JBoolean other) + { + return this.Value.Equals(other.Value); + } + return false; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } } diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 7e58b72567..65f4991cd8 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, +// +// The Neo.Json is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -117,5 +117,50 @@ public static implicit operator JNumber(double value) { return new JNumber(value); } + + public static implicit operator JNumber(long value) + { + return new JNumber(value); + } + + public static bool operator ==(JNumber left, JNumber? right) + { + if (right is null) return false; + return ReferenceEquals(left, right) || left.Value.Equals(right.Value); + } + + public static bool operator !=(JNumber left, JNumber right) + { + return !(left == right); + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + + var other = obj switch + { + JNumber jNumber => jNumber, + uint u => new JNumber(u), + int i => new JNumber(i), + ulong ul => new JNumber(ul), + long l => new JNumber(l), + byte b => new JNumber(b), + sbyte sb => new JNumber(sb), + short s => new JNumber(s), + ushort us => new JNumber(us), + decimal d => new JNumber((double)d), + float f => new JNumber(f), + double d => new JNumber(d), + _ => throw new ArgumentOutOfRangeException(nameof(obj), obj, null) + }; + return other == this; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } } diff --git a/src/Neo.Json/JString.cs b/src/Neo.Json/JString.cs index 714ff85928..42bc63937c 100644 --- a/src/Neo.Json/JString.cs +++ b/src/Neo.Json/JString.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, +// +// The Neo.Json is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -92,5 +92,36 @@ public static implicit operator JString(Enum value) { return value == null ? null : new JString(value); } + + public static bool operator ==(JString left, JString? right) + { + if (right is null) return false; + return ReferenceEquals(left, right) || left.Value.Equals(right.Value); + } + + public static bool operator !=(JString left, JString right) + { + return !(left == right); + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj is JString other) + { + return this == other; + } + if (obj is string str) + { + return this.Value == str; + } + return false; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JBoolean.cs b/tests/Neo.Json.UnitTests/UT_JBoolean.cs index 679c9b622d..e03654f8b9 100644 --- a/tests/Neo.Json.UnitTests/UT_JBoolean.cs +++ b/tests/Neo.Json.UnitTests/UT_JBoolean.cs @@ -19,5 +19,14 @@ public void TestAsNumber() jFalse.AsNumber().Should().Be(0); jTrue.AsNumber().Should().Be(1); } + + [TestMethod] + public void TestEqual() + { + Assert.IsTrue(jTrue.Equals(new JBoolean(true))); + Assert.IsTrue(jTrue == new JBoolean(true)); + Assert.IsTrue(jFalse.Equals(new JBoolean())); + Assert.IsTrue(jFalse == new JBoolean()); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 6156bc1cb5..8435e0ad47 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -49,9 +49,18 @@ public void TestGetEnum() new JNumber(1).GetEnum().Should().Be(Woo.Jerry); new JNumber(2).GetEnum().Should().Be(Woo.James); new JNumber(3).AsEnum().Should().Be(Woo.Tom); - Action action = () => new JNumber(3).GetEnum(); action.Should().Throw(); } + + [TestMethod] + public void TestEqual() + { + Assert.IsTrue(maxInt.Equals(JNumber.MAX_SAFE_INTEGER)); + Assert.IsTrue(maxInt == JNumber.MAX_SAFE_INTEGER); + Assert.IsTrue(minInt.Equals(JNumber.MIN_SAFE_INTEGER)); + Assert.IsTrue(minInt == JNumber.MIN_SAFE_INTEGER); + Assert.IsTrue(zero == new JNumber()); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JString.cs b/tests/Neo.Json.UnitTests/UT_JString.cs index 3188bf0e59..54e87ad49f 100644 --- a/tests/Neo.Json.UnitTests/UT_JString.cs +++ b/tests/Neo.Json.UnitTests/UT_JString.cs @@ -48,5 +48,14 @@ public void TestGetEnum() woo = s.AsEnum(Woo.Jerry, false); Assert.AreEqual(Woo.Jerry, woo); } + [TestMethod] + public void TestEqual() + { + var str = "hello world"; + var jString = new JString(str); + Assert.IsTrue(jString.Equals(str)); + Assert.IsTrue(jString == str); + Assert.IsTrue(jString != "hello world2"); + } } } From 447b149e117589a1ceed0e754d5616917e555f52 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 31 Dec 2023 01:29:37 -0800 Subject: [PATCH 2/2] Set project as nullable (#3042) * Set project as nullable * Clean code * format * Remove more nullables * ConsoleService nullable * More changes * Clean CLI warnings * Only CLI and Console Service * Clean changes --------- Co-authored-by: Jimmy --- src/Neo.CLI/CLI/ConsolePercent.cs | 6 +- src/Neo.CLI/CLI/MainService.Blockchain.cs | 22 ++-- src/Neo.CLI/CLI/MainService.Contracts.cs | 12 +-- src/Neo.CLI/CLI/MainService.Logger.cs | 10 +- src/Neo.CLI/CLI/MainService.NEP17.cs | 5 +- src/Neo.CLI/CLI/MainService.Native.cs | 1 - src/Neo.CLI/CLI/MainService.Plugins.cs | 29 ++--- src/Neo.CLI/CLI/MainService.Tools.cs | 26 ++--- src/Neo.CLI/CLI/MainService.Vote.cs | 34 +++--- src/Neo.CLI/CLI/MainService.Wallet.cs | 60 ++++++----- src/Neo.CLI/CLI/MainService.cs | 101 ++++++++++++------ src/Neo.CLI/Extensions.cs | 6 +- src/Neo.CLI/Neo.CLI.csproj | 1 + src/Neo.CLI/Settings.cs | 20 ++-- src/Neo.ConsoleService/CommandStringToken.cs | 2 +- src/Neo.ConsoleService/CommandToken.cs | 13 ++- .../ConsoleCommandAttribute.cs | 4 +- src/Neo.ConsoleService/ConsoleServiceBase.cs | 69 +++++++----- .../Neo.ConsoleService.csproj | 1 + 19 files changed, 244 insertions(+), 178 deletions(-) diff --git a/src/Neo.CLI/CLI/ConsolePercent.cs b/src/Neo.CLI/CLI/ConsolePercent.cs index 09077f2503..8c5e2a137d 100644 --- a/src/Neo.CLI/CLI/ConsolePercent.cs +++ b/src/Neo.CLI/CLI/ConsolePercent.cs @@ -19,11 +19,11 @@ public class ConsolePercent : IDisposable private readonly long _maxValue; private long _value; private decimal _lastFactor; - private string _lastPercent; + private string? _lastPercent; private readonly int _x, _y; - private bool _inputRedirected; + private readonly bool _inputRedirected; #endregion @@ -99,7 +99,7 @@ public ConsolePercent(long value = 0, long maxValue = 100) /// public void Invalidate() { - var factor = Math.Round((Percent / 100M), 1); + var factor = Math.Round(Percent / 100M, 1); var percent = Percent.ToString("0.0").PadLeft(5, ' '); if (_lastFactor == factor && _lastPercent == percent) diff --git a/src/Neo.CLI/CLI/MainService.Blockchain.cs b/src/Neo.CLI/CLI/MainService.Blockchain.cs index 3e5fc90a9b..f85368ec37 100644 --- a/src/Neo.CLI/CLI/MainService.Blockchain.cs +++ b/src/Neo.CLI/CLI/MainService.Blockchain.cs @@ -26,7 +26,7 @@ partial class MainService /// Number of blocks /// Path [ConsoleCommand("export blocks", Category = "Blockchain Commands")] - private void OnExportBlocksStartCountCommand(uint start, uint count = uint.MaxValue, string path = null) + private void OnExportBlocksStartCountCommand(uint start, uint count = uint.MaxValue, string? path = null) { uint height = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView); if (height < start) @@ -50,12 +50,12 @@ private void OnShowBlockCommand(string indexOrHash) { lock (syncRoot) { - Block block = null; + Block? block = null; if (uint.TryParse(indexOrHash, out var index)) - block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, index); + block = NativeContract.Ledger.GetBlock(NeoSystem.StoreView, index); else if (UInt256.TryParse(indexOrHash, out var hash)) - block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, hash); + block = NativeContract.Ledger.GetBlock(NeoSystem.StoreView, hash); else { ConsoleHelper.Error("Enter a valid block index or hash."); @@ -81,7 +81,7 @@ private void OnShowBlockCommand(string indexOrHash) ConsoleHelper.Info("", " PrevHash: ", $"{block.PrevHash}"); ConsoleHelper.Info("", " NextConsensus: ", $"{block.NextConsensus}"); ConsoleHelper.Info("", " PrimaryIndex: ", $"{block.PrimaryIndex}"); - ConsoleHelper.Info("", " PrimaryPubKey: ", $"{NativeContract.NEO.GetCommittee(_neoSystem.GetSnapshot())[block.PrimaryIndex]}"); + ConsoleHelper.Info("", " PrimaryPubKey: ", $"{NativeContract.NEO.GetCommittee(NeoSystem.GetSnapshot())[block.PrimaryIndex]}"); ConsoleHelper.Info("", " Version: ", $"{block.Version}"); ConsoleHelper.Info("", " Size: ", $"{block.Size} Byte(s)"); ConsoleHelper.Info(); @@ -116,7 +116,7 @@ public void OnShowTransactionCommand(UInt256 hash) { lock (syncRoot) { - var tx = NativeContract.Ledger.GetTransactionState(_neoSystem.StoreView, hash); + var tx = NativeContract.Ledger.GetTransactionState(NeoSystem.StoreView, hash); if (tx is null) { @@ -124,7 +124,7 @@ public void OnShowTransactionCommand(UInt256 hash) return; } - var block = NativeContract.Ledger.GetHeader(_neoSystem.StoreView, tx.BlockIndex); + var block = NativeContract.Ledger.GetHeader(NeoSystem.StoreView, tx.BlockIndex); DateTime transactionDatetime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); transactionDatetime = transactionDatetime.AddMilliseconds(block.Timestamp).ToLocalTime(); @@ -228,16 +228,16 @@ public void OnShowContractCommand(string nameOrHash) { lock (syncRoot) { - ContractState contract = null; + ContractState? contract = null; if (UInt160.TryParse(nameOrHash, out var scriptHash)) - contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, scriptHash); + contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); else { var nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Name.Equals(nameOrHash, StringComparison.InvariantCultureIgnoreCase)); if (nativeContract != null) - contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, nativeContract.Hash); + contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, nativeContract.Hash); } if (contract is null) @@ -257,7 +257,7 @@ public void OnShowContractCommand(string nameOrHash) ConsoleHelper.Info("", " Compiler: ", $"{contract.Nef.Compiler}"); ConsoleHelper.Info("", " SourceCode: ", $"{contract.Nef.Source}"); ConsoleHelper.Info("", " Trusts: ", $"[{string.Join(", ", contract.Manifest.Trusts.Select(s => s.ToJson()?.GetString()))}]"); - if (contract.Manifest.Extra is null) + if (contract.Manifest.Extra is not null) { foreach (var extra in contract.Manifest.Extra.Properties) { diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs index 77b4a77219..f60faddf04 100644 --- a/src/Neo.CLI/CLI/MainService.Contracts.cs +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -28,14 +28,14 @@ partial class MainService /// Manifest path /// Extra data for deploy [ConsoleCommand("deploy", Category = "Contract Commands")] - private void OnDeployCommand(string filePath, string manifestPath = null, JObject data = null) + private void OnDeployCommand(string filePath, string? manifestPath = null, JObject? data = null) { if (NoWallet()) return; byte[] script = LoadDeploymentScript(filePath, manifestPath, data, out var nef, out var manifest); Transaction tx; try { - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, script); } catch (InvalidOperationException e) { @@ -65,7 +65,7 @@ private void OnDeployCommand(string filePath, string manifestPath = null, JObjec /// 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) + private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifestPath, UInt160 sender, UInt160[]? signerAccounts = null, JObject? data = null) { Signer[] signers = Array.Empty(); @@ -91,7 +91,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes try { byte[] script = LoadUpdateScript(scriptHash, filePath, manifestPath, data, out var nef, out var manifest); - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script, sender, signers); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, script, sender, signers); } catch (InvalidOperationException e) { @@ -128,7 +128,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes /// Signer's accounts /// 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) + private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contractParameters = null, UInt160? sender = null, UInt160[]? signerAccounts = null, decimal maxGas = 20) { var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); Signer[] signers = Array.Empty(); @@ -161,7 +161,7 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contra if (NoWallet()) return; try { - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); } catch (InvalidOperationException e) { diff --git a/src/Neo.CLI/CLI/MainService.Logger.cs b/src/Neo.CLI/CLI/MainService.Logger.cs index 6624f931a6..47a813d7e2 100644 --- a/src/Neo.CLI/CLI/MainService.Logger.cs +++ b/src/Neo.CLI/CLI/MainService.Logger.cs @@ -112,9 +112,9 @@ private void OnLog(string source, LogLevel level, object message) Console.Write($"{logLevel} {log} \t{messages[0],-20}"); for (var i = 1; i < messages.Length; i++) { - if (messages[i].Length > 20) + if (messages[i]?.Length > 20) { - messages[i] = $"{messages[i][..10]}...{messages[i][(messages[i].Length - 10)..]}"; + messages[i] = $"{messages[i]![..10]}...{messages[i]![(messages[i]!.Length - 10)..]}"; } Console.Write(i % 2 == 0 ? $"={messages[i]} " : $" {messages[i]}"); } @@ -162,7 +162,11 @@ private static string[] Parse(string message) { messages.Add(string.Join(" ", d)); } - messages.Add(parts.LastOrDefault()); + var last = parts.LastOrDefault(); + if (last is not null) + { + messages.Add(last); + } } return messages.ToArray(); diff --git a/src/Neo.CLI/CLI/MainService.NEP17.cs b/src/Neo.CLI/CLI/MainService.NEP17.cs index 34de5e58e5..17d62ff4d2 100644 --- a/src/Neo.CLI/CLI/MainService.NEP17.cs +++ b/src/Neo.CLI/CLI/MainService.NEP17.cs @@ -16,7 +16,6 @@ using Neo.VM.Types; using Neo.Wallets; using System; -using System.Collections.Generic; using System.Linq; using Array = System.Array; @@ -34,7 +33,7 @@ partial class MainService /// Data /// Signer's accounts [ConsoleCommand("transfer", Category = "NEP17 Commands")] - private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UInt160 from = null, string data = null, UInt160[] signersAccounts = null) + private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UInt160? from = null, string? data = null, UInt160[]? signersAccounts = null) { var snapshot = NeoSystem.StoreView; var asset = new AssetDescriptor(snapshot, NeoSystem.Settings, tokenHash); @@ -45,7 +44,7 @@ private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UI Transaction tx; try { - tx = CurrentWallet.MakeTransaction(snapshot, new[] + tx = CurrentWallet!.MakeTransaction(snapshot, new[] { new TransferOutput { diff --git a/src/Neo.CLI/CLI/MainService.Native.cs b/src/Neo.CLI/CLI/MainService.Native.cs index 189168b73e..0cdf1ca45c 100644 --- a/src/Neo.CLI/CLI/MainService.Native.cs +++ b/src/Neo.CLI/CLI/MainService.Native.cs @@ -10,7 +10,6 @@ using Neo.ConsoleService; using Neo.SmartContract.Native; -using System; using System.Linq; namespace Neo.CLI diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index f126eef996..169df18a25 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -72,26 +72,27 @@ private async Task DownloadPluginAsync(string pluginName) if (response.StatusCode == HttpStatusCode.NotFound) { response.Dispose(); - Version versionCore = typeof(Plugin).Assembly.GetName().Version; + 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(); - var releases = JObject.Parse(buffer); - var asset = ((JArray)releases) - .Where(p => !p["tag_name"].GetString().Contains('-')) + if (JToken.Parse(buffer) is not JArray arr) throw new Exception("Plugin doesn't exist."); + var asset = arr + .Where(p => p?["tag_name"] is not null && p?["assets"] is not null) + .Where(p => !p!["tag_name"]!.GetString().Contains('-')) .Select(p => new { - Version = Version.Parse(p["tag_name"].GetString().TrimStart('v')), - Assets = (JArray)p["assets"] + Version = Version.Parse(p!["tag_name"]!.GetString().TrimStart('v')), + Assets = p["assets"] as JArray }) .OrderByDescending(p => p.Version) - .First(p => p.Version <= versionCore).Assets - .FirstOrDefault(p => p["name"].GetString() == $"{pluginName}.zip"); + .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()); + response = await http.GetAsync(asset["browser_download_url"]?.GetString()); } using (response) @@ -121,7 +122,7 @@ private async Task DownloadPluginAsync(string pluginName) /// Name of the plugin /// Dependency set /// Install by force for `update` - private async Task InstallPluginAsync(string pluginName, HashSet installed = null, + private async Task InstallPluginAsync(string pluginName, HashSet? installed = null, bool overWrite = false) { installed ??= new HashSet(); @@ -135,7 +136,7 @@ private async Task InstallPluginAsync(string pluginName, HashSet install } using ZipArchive zip = new(stream, ZipArchiveMode.Read); - ZipArchiveEntry entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); + ZipArchiveEntry? entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); if (entry is not null) { await using Stream es = entry.Open(); @@ -160,10 +161,10 @@ private async Task InstallDependenciesAsync(Stream config, HashSet insta var dependencies = dependency.GetChildren().Select(p => p.Get()).ToArray(); if (dependencies.Length == 0) return; - foreach (string plugin in dependencies.Where(p => !PluginExists(p))) + foreach (string? plugin in dependencies.Where(p => p is not null && !PluginExists(p))) { ConsoleHelper.Info($"Installing dependency: {plugin}"); - await InstallPluginAsync(plugin, installed); + await InstallPluginAsync(plugin!, installed); } } @@ -201,7 +202,7 @@ private void OnUnInstallCommand(string pluginName) .GetSection("Dependency") .GetChildren() .Select(d => d.Get()) - .Any(v => v.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) + .Any(v => v is not null && v.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) { ConsoleHelper.Error( $"Can not uninstall. Other plugins depend on this plugin, try `reinstall {pluginName}` if the plugin is broken."); diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs index 0136617729..870f0261a9 100644 --- a/src/Neo.CLI/CLI/MainService.Tools.cs +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -26,7 +26,7 @@ partial class MainService [ConsoleCommand("parse", Category = "Base Commands", Description = "Parse a value to its possible conversions.")] private void OnParseCommand(string value) { - var parseFunctions = new Dictionary>() + var parseFunctions = new Dictionary>() { { "Address to ScriptHash", AddressToScripthash }, { "Address to Base64", AddressToBase64 }, @@ -73,7 +73,7 @@ private void OnParseCommand(string value) /// string or when the converted string is not printable; otherwise, returns /// the string represented by the hexadecimal value /// - private string HexToString(string hexString) + private string? HexToString(string hexString) { try { @@ -98,7 +98,7 @@ private string HexToString(string hexString) /// Returns null when is not possible to parse the hex value to big integer value; /// otherwise, returns the string that represents the converted big integer. /// - private string HexToNumber(string hexString) + private string? HexToNumber(string hexString) { try { @@ -169,7 +169,7 @@ private string ClearHexString(string hexString) /// Returns null when it is not possible to parse the string value to a hexadecimal /// value; otherwise returns the hexadecimal value that represents the converted string /// - private string StringToHex(string strParam) + private string? StringToHex(string strParam) { try { @@ -195,7 +195,7 @@ private string StringToHex(string strParam) /// /// Throw . /// - private string StringToBase64(string strParam) + private string? StringToBase64(string strParam) { try { @@ -220,7 +220,7 @@ private string StringToBase64(string strParam) /// it is not possible to parse the big integer value to hexadecimal; otherwise, /// returns the string that represents the converted hexadecimal value /// - private string NumberToHex(string strParam) + private string? NumberToHex(string strParam) { try { @@ -247,7 +247,7 @@ private string NumberToHex(string strParam) /// it is not possible to parse the big integer value to Base64 value; otherwise, /// returns the string that represents the converted Base64 value /// - private string NumberToBase64(string strParam) + private string? NumberToBase64(string strParam) { try { @@ -277,7 +277,7 @@ private string NumberToBase64(string strParam) /// it is not possible to parse the address to scripthash; otherwise returns /// the string that represents the converted scripthash /// - private string AddressToScripthash(string address) + private string? AddressToScripthash(string address) { try { @@ -302,7 +302,7 @@ private string AddressToScripthash(string address) /// not possible to parse the address to Base64 value; otherwise returns /// the string that represents the converted Base64 value. /// - private string AddressToBase64(string address) + private string? AddressToBase64(string address) { try { @@ -327,7 +327,7 @@ private string AddressToBase64(string address) /// Returns null when the string does not represent an scripthash; /// otherwise, returns the string that represents the converted address /// - private string ScripthashToAddress(string script) + private string? ScripthashToAddress(string script) { try { @@ -372,7 +372,7 @@ private string ScripthashToAddress(string script) /// it is not possible to parse the Base64 value to address; otherwise, /// returns the string that represents the converted address /// - private string Base64ToAddress(string bytearray) + private string? Base64ToAddress(string bytearray) { try { @@ -405,7 +405,7 @@ private string Base64ToAddress(string bytearray) /// string is not printable; otherwise, returns the string that represents /// the Base64 value. /// - private string Base64ToString(string bytearray) + private string? Base64ToString(string bytearray) { try { @@ -430,7 +430,7 @@ private string Base64ToString(string bytearray) /// it is not possible to parse the Base64 value to big integer value; otherwise /// returns the string that represents the converted big integer /// - private string Base64ToNumber(string bytearray) + private string? Base64ToNumber(string bytearray) { try { diff --git a/src/Neo.CLI/CLI/MainService.Vote.cs b/src/Neo.CLI/CLI/MainService.Vote.cs index aa23562eb9..67f37b648e 100644 --- a/src/Neo.CLI/CLI/MainService.Vote.cs +++ b/src/Neo.CLI/CLI/MainService.Vote.cs @@ -17,7 +17,6 @@ using Neo.VM.Types; using Neo.Wallets; using System; -using System.Linq; using System.Numerics; namespace Neo.CLI @@ -33,7 +32,7 @@ private void OnRegisterCandidateCommand(UInt160 account) { var testGas = NativeContract.NEO.GetRegisterPrice(NeoSystem.StoreView) + (BigInteger)Math.Pow(10, NativeContract.GAS.Decimals) * 10; if (NoWallet()) return; - WalletAccount currentAccount = CurrentWallet.GetAccount(account); + WalletAccount currentAccount = CurrentWallet!.GetAccount(account); if (currentAccount == null) { @@ -49,9 +48,9 @@ private void OnRegisterCandidateCommand(UInt160 account) } } - ECPoint publicKey = currentAccount.GetKey()?.PublicKey; + ECPoint? publicKey = currentAccount.GetKey()?.PublicKey; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "registerCandidate", publicKey); script = scriptBuilder.ToArray(); @@ -68,7 +67,7 @@ private void OnRegisterCandidateCommand(UInt160 account) private void OnUnregisterCandidateCommand(UInt160 account) { if (NoWallet()) return; - WalletAccount currentAccount = CurrentWallet.GetAccount(account); + WalletAccount currentAccount = CurrentWallet!.GetAccount(account); if (currentAccount == null) { @@ -84,9 +83,9 @@ private void OnUnregisterCandidateCommand(UInt160 account) } } - ECPoint publicKey = currentAccount?.GetKey()?.PublicKey; + ECPoint? publicKey = currentAccount?.GetKey()?.PublicKey; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "unregisterCandidate", publicKey); script = scriptBuilder.ToArray(); @@ -105,7 +104,7 @@ private void OnVoteCommand(UInt160 senderAccount, ECPoint publicKey) { if (NoWallet()) return; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "vote", senderAccount, publicKey); script = scriptBuilder.ToArray(); @@ -123,7 +122,7 @@ private void OnUnvoteCommand(UInt160 senderAccount) { if (NoWallet()) return; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "vote", senderAccount, null); script = scriptBuilder.ToArray(); @@ -150,9 +149,10 @@ private void OnGetCandidatesCommand() foreach (var item in resJArray) { var value = (VM.Types.Array)item; + if (value is null) continue; - Console.Write(((ByteString)value?[0])?.GetSpan().ToHexString() + "\t"); - Console.WriteLine(((Integer)value?[1]).GetInteger()); + Console.Write(((ByteString)value[0])?.GetSpan().ToHexString() + "\t"); + Console.WriteLine(((Integer)value[1]).GetInteger()); } } } @@ -222,6 +222,12 @@ private void OnGetAccountState(UInt160 address) return; } var resJArray = (VM.Types.Array)result; + if (resJArray is null) + { + ConsoleHelper.Warning(notice); + return; + } + foreach (StackItem value in resJArray) { if (value.IsNull) @@ -230,10 +236,10 @@ private void OnGetAccountState(UInt160 address) return; } } - var publickey = ECPoint.Parse(((ByteString)resJArray?[2])?.GetSpan().ToHexString(), ECCurve.Secp256r1); + var publickey = ECPoint.Parse(((ByteString)resJArray[2])?.GetSpan().ToHexString(), ECCurve.Secp256r1); ConsoleHelper.Info("Voted: ", Contract.CreateSignatureRedeemScript(publickey).ToScriptHash().ToAddress(NeoSystem.Settings.AddressVersion)); - ConsoleHelper.Info("Amount: ", new BigDecimal(((Integer)resJArray?[0]).GetInteger(), NativeContract.NEO.Decimals).ToString()); - ConsoleHelper.Info("Block: ", ((Integer)resJArray?[1]).GetInteger().ToString()); + ConsoleHelper.Info("Amount: ", new BigDecimal(((Integer)resJArray[0]).GetInteger(), NativeContract.NEO.Decimals).ToString()); + ConsoleHelper.Info("Block: ", ((Integer)resJArray[1]).GetInteger().ToString()); } } } diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index f916ea1bbc..48531f1f4e 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -124,7 +124,7 @@ private void OnCreateAddressCommand(ushort count = 1) { Parallel.For(0, count, (i) => { - WalletAccount account = CurrentWallet.CreateAccount(); + WalletAccount account = CurrentWallet!.CreateAccount(); lock (addresses) { addresses.Add(account.Address); @@ -151,7 +151,7 @@ private void OnDeleteAddressCommand(UInt160 address) if (ReadUserInput($"Warning: Irrevocable operation!\nAre you sure to delete account {address.ToAddress(NeoSystem.Settings.AddressVersion)}? (no|yes)").IsYes()) { - if (CurrentWallet.DeleteAccount(address)) + if (CurrentWallet!.DeleteAccount(address)) { if (CurrentWallet is NEP6Wallet wallet) { @@ -172,7 +172,7 @@ private void OnDeleteAddressCommand(UInt160 address) /// Path /// ScriptHash [ConsoleCommand("export key", Category = "Wallet Commands")] - private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) + private void OnExportKeyCommand(string? path = null, UInt160? scriptHash = null) { if (NoWallet()) return; if (path != null && File.Exists(path)) @@ -186,7 +186,7 @@ private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) ConsoleHelper.Info("Cancelled"); return; } - if (!CurrentWallet.VerifyPassword(password)) + if (!CurrentWallet!.VerifyPassword(password)) { ConsoleHelper.Error("Incorrect password"); return; @@ -210,7 +210,7 @@ private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) /// Process "create wallet" command /// [ConsoleCommand("create wallet", Category = "Wallet Commands")] - private void OnCreateWalletCommand(string path, string wifOrFile = null) + private void OnCreateWalletCommand(string path, string? wifOrFile = null) { string password = ReadUserInput("password", true); if (password.Length == 0) @@ -231,7 +231,7 @@ private void OnCreateWalletCommand(string path, string wifOrFile = null) } bool createDefaultAccount = wifOrFile is null; CreateWallet(path, password, createDefaultAccount); - if (!createDefaultAccount) OnImportKeyCommand(wifOrFile); + if (!createDefaultAccount) OnImportKeyCommand(wifOrFile!); } /// @@ -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(); + KeyPair? keyPair = CurrentWallet!.GetAccounts().FirstOrDefault(p => p.HasKey && publicKeys.Contains(p.GetKey().PublicKey))?.GetKey(); CurrentWallet.CreateAccount(multiSignContract, keyPair); if (CurrentWallet is NEP6Wallet wallet) @@ -268,7 +268,7 @@ private void OnImportMultisigAddress(ushort m, ECPoint[] publicKeys) private void OnImportKeyCommand(string wifOrFile) { if (NoWallet()) return; - byte[] prikey = null; + byte[]? prikey = null; try { prikey = Wallet.GetPrivateKeyFromWIF(wifOrFile); @@ -301,7 +301,7 @@ private void OnImportKeyCommand(string wifOrFile) prikey = lines[i].HexToBytes(); else prikey = Wallet.GetPrivateKeyFromWIF(lines[i]); - CurrentWallet.CreateAccount(prikey); + CurrentWallet!.CreateAccount(prikey); Array.Clear(prikey, 0, prikey.Length); percent.Value++; } @@ -309,7 +309,7 @@ private void OnImportKeyCommand(string wifOrFile) } else { - WalletAccount account = CurrentWallet.CreateAccount(prikey); + WalletAccount account = CurrentWallet!.CreateAccount(prikey); Array.Clear(prikey, 0, prikey.Length); ConsoleHelper.Info("Address: ", account.Address); ConsoleHelper.Info(" Pubkey: ", account.GetKey().PublicKey.EncodePoint(true).ToHexString()); @@ -325,7 +325,7 @@ private void OnImportKeyCommand(string wifOrFile) private void OnImportWatchOnlyCommand(string addressOrFile) { if (NoWallet()) return; - UInt160 address = null; + UInt160? address = null; try { address = StringToAddress(addressOrFile, NeoSystem.Settings.AddressVersion); @@ -355,14 +355,14 @@ private void OnImportWatchOnlyCommand(string addressOrFile) for (int i = 0; i < lines.Length; i++) { address = StringToAddress(lines[i], NeoSystem.Settings.AddressVersion); - CurrentWallet.CreateAccount(address); + CurrentWallet!.CreateAccount(address); percent.Value++; } } } else { - WalletAccount account = CurrentWallet.GetAccount(address); + WalletAccount account = CurrentWallet!.GetAccount(address); if (account is not null) { ConsoleHelper.Warning("This address is already in your wallet"); @@ -385,7 +385,7 @@ private void OnListAddressCommand() { if (NoWallet()) return; var snapshot = NeoSystem.StoreView; - foreach (var account in CurrentWallet.GetAccounts()) + foreach (var account in CurrentWallet!.GetAccounts()) { var contract = account.Contract; var type = "Nonstandard"; @@ -420,7 +420,7 @@ private void OnListAssetCommand() { var snapshot = NeoSystem.StoreView; if (NoWallet()) return; - foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) + foreach (UInt160 account in CurrentWallet!.GetAccounts().Select(p => p.ScriptHash)) { Console.WriteLine(account.ToAddress(NeoSystem.Settings.AddressVersion)); ConsoleHelper.Info("NEO: ", $"{CurrentWallet.GetBalance(snapshot, NativeContract.NEO.Hash, account)}"); @@ -441,7 +441,7 @@ private void OnListAssetCommand() private void OnListKeyCommand() { if (NoWallet()) return; - foreach (WalletAccount account in CurrentWallet.GetAccounts().Where(p => p.HasKey)) + foreach (WalletAccount account in CurrentWallet!.GetAccounts().Where(p => p.HasKey)) { ConsoleHelper.Info(" Address: ", account.Address); ConsoleHelper.Info("ScriptHash: ", account.ScriptHash.ToString()); @@ -468,12 +468,12 @@ 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; } - else if (!CurrentWallet.Sign(context)) + else if (!CurrentWallet!.Sign(context)) { ConsoleHelper.Warning("Non-existent private key in wallet."); return; @@ -496,7 +496,7 @@ private void OnSignCommand(JObject jsonObjectToSign) /// Data /// Signer's accounts [ConsoleCommand("send", Category = "Wallet Commands")] - private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 from = null, string data = null, UInt160[] signerAccounts = null) + private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160? from = null, string? data = null, UInt160[]? signerAccounts = null) { if (NoWallet()) return; string password = ReadUserInput("password", true); @@ -505,7 +505,7 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 fro ConsoleHelper.Info("Cancelled"); return; } - if (!CurrentWallet.VerifyPassword(password)) + if (!CurrentWallet!.VerifyPassword(password)) { ConsoleHelper.Error("Incorrect password"); return; @@ -567,8 +567,10 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 fro /// Transaction's sender /// Signer's accounts [ConsoleCommand("cancel", Category = "Wallet Commands")] - private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] signerAccounts = null) + private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? signerAccounts = null) { + if (NoWallet()) return; + TransactionState state = NativeContract.Ledger.GetTransactionState(NeoSystem.StoreView, txid); if (state != null) { @@ -578,7 +580,7 @@ private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] sign var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } }; Signer[] signers = Array.Empty(); - if (!NoWallet() && sender != null) + if (sender != null) { if (signerAccounts == null) signerAccounts = new UInt160[1] { sender }; @@ -595,7 +597,7 @@ private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] sign signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.None }).ToArray(); } - Transaction tx = new Transaction + Transaction tx = new() { Signers = signers, Attributes = conflict, @@ -606,7 +608,7 @@ private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] sign { using ScriptBuilder scriptBuilder = new(); scriptBuilder.Emit(OpCode.RET); - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, scriptBuilder.ToArray(), sender, signers, conflict); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, scriptBuilder.ToArray(), sender, signers, conflict); } catch (InvalidOperationException e) { @@ -652,7 +654,7 @@ private void OnShowGasCommand() BigInteger gas = BigInteger.Zero; var snapshot = NeoSystem.StoreView; uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; - foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) + foreach (UInt160 account in CurrentWallet!.GetAccounts().Select(p => p.ScriptHash)) gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); ConsoleHelper.Info("Unclaimed gas: ", new BigDecimal(gas, NativeContract.GAS.Decimals).ToString()); } @@ -670,7 +672,7 @@ private void OnChangePasswordCommand() ConsoleHelper.Info("Cancelled"); return; } - if (!CurrentWallet.VerifyPassword(oldPassword)) + if (!CurrentWallet!.VerifyPassword(oldPassword)) { ConsoleHelper.Error("Incorrect password"); return; @@ -717,17 +719,19 @@ private void OnChangePasswordCommand() private void SignAndSendTx(DataCache snapshot, Transaction tx) { + if (NoWallet()) return; + ContractParametersContext context; try { - context = new ContractParametersContext(snapshot, tx, _neoSystem.Settings.Network); + context = new ContractParametersContext(snapshot, tx, NeoSystem.Settings.Network); } catch (InvalidOperationException e) { ConsoleHelper.Error("Failed creating contract params: " + GetExceptionMessage(e)); throw; } - CurrentWallet.Sign(context); + CurrentWallet!.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 7beea39310..c097176340 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -40,14 +40,13 @@ namespace Neo.CLI { public partial class MainService : ConsoleServiceBase, IWalletProvider { - public event EventHandler WalletChanged; + public event EventHandler? WalletChanged = null; public const long TestModeGas = 20_00000000; - private Wallet _currentWallet; - public LocalNode LocalNode; + private Wallet? _currentWallet; - public Wallet CurrentWallet + public Wallet? CurrentWallet { get => _currentWallet; private set @@ -57,13 +56,21 @@ private set } } - private NeoSystem _neoSystem; + private NeoSystem? _neoSystem; public NeoSystem NeoSystem { - get => _neoSystem; + get => _neoSystem!; private set => _neoSystem = value; } + private LocalNode? _localNode; + + public LocalNode LocalNode + { + get => _localNode!; + private set => _localNode = value; + } + protected override string Prompt => "neo"; public override string ServiceName => "NEO-CLI"; @@ -78,8 +85,8 @@ public MainService() : base() 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 => JToken.Parse(str)); - RegisterCommandHandler(str => (JObject)JToken.Parse(str)); + RegisterCommandHandler(str => JToken.Parse(str)!); + RegisterCommandHandler(str => (JObject)JToken.Parse(str)!); RegisterCommandHandler(str => decimal.Parse(str, CultureInfo.InvariantCulture)); RegisterCommandHandler(obj => (JArray)obj); @@ -108,7 +115,7 @@ internal static UInt160 StringToAddress(string input, byte version) return input.ToScriptHash(version); } - Wallet IWalletProvider.GetWallet() + Wallet? IWalletProvider.GetWallet() { return CurrentWallet; } @@ -117,9 +124,9 @@ public override void RunConsole() { Console.ForegroundColor = ConsoleColor.DarkGreen; - var cliV = Assembly.GetAssembly(typeof(Program)).GetVersion(); - var neoV = Assembly.GetAssembly(typeof(NeoSystem)).GetVersion(); - var vmV = Assembly.GetAssembly(typeof(ExecutionEngine)).GetVersion(); + var cliV = Assembly.GetAssembly(typeof(Program))!.GetVersion(); + var neoV = Assembly.GetAssembly(typeof(NeoSystem))!.GetVersion(); + var vmV = Assembly.GetAssembly(typeof(ExecutionEngine))!.GetVersion(); Console.WriteLine($"{ServiceName} v{cliV} - NEO v{neoV} - NEO-VM v{vmV}"); Console.WriteLine(); @@ -172,17 +179,22 @@ private IEnumerable GetBlocksFromFile() { const string pathAcc = "chain.acc"; if (File.Exists(pathAcc)) - using (FileStream fs = new FileStream(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (FileStream fs = new(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) foreach (var block in GetBlocks(fs)) yield return block; const string pathAccZip = pathAcc + ".zip"; if (File.Exists(pathAccZip)) - using (FileStream fs = new FileStream(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(pathAcc).Open()) - foreach (var block in GetBlocks(zs)) - yield return block; + using (FileStream fs = new(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new(fs, ZipArchiveMode.Read)) + using (Stream? zs = zip.GetEntry(pathAcc)?.Open()) + { + if (zs is not null) + { + foreach (var block in GetBlocks(zs)) + yield return block; + } + } var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new { @@ -196,13 +208,18 @@ private IEnumerable GetBlocksFromFile() { if (path.Start > height + 1) break; if (path.IsCompressed) - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) - foreach (var block in GetBlocks(zs, true)) - yield return block; + using (FileStream fs = new(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new(fs, ZipArchiveMode.Read)) + using (Stream? zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName))?.Open()) + { + if (zs is not null) + { + foreach (var block in GetBlocks(zs, true)) + yield return block; + } + } else - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (FileStream fs = new(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) foreach (var block in GetBlocks(fs, true)) yield return block; } @@ -215,7 +232,7 @@ private bool NoWallet() return true; } - private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, JObject data, out NefFile nef, out ContractManifest manifest) + private byte[] LoadDeploymentScript(string nefFilePath, string? manifestFilePath, JObject? data, out NefFile nef, out ContractManifest manifest) { if (string.IsNullOrEmpty(manifestFilePath)) { @@ -242,7 +259,7 @@ private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, nef = File.ReadAllBytes(nefFilePath).AsSerializable(); - ContractParameter dataParameter = null; + ContractParameter? dataParameter = null; if (data is not null) try { @@ -268,7 +285,7 @@ private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, } } - private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string manifestFilePath, JObject data, out NefFile nef, out ContractManifest manifest) + private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string manifestFilePath, JObject? data, out NefFile nef, out ContractManifest manifest) { if (string.IsNullOrEmpty(manifestFilePath)) { @@ -295,7 +312,7 @@ private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string m nef = File.ReadAllBytes(nefFilePath).AsSerializable(); - ContractParameter dataParameter = null; + ContractParameter? dataParameter = null; if (data is not null) try { @@ -402,6 +419,15 @@ public async void Start(string[] args) { try { + if (Settings.Default.UnlockWallet.Path is null) + { + throw new InvalidOperationException("UnlockWallet.Path must be defined"); + } + else if (Settings.Default.UnlockWallet.Password is null) + { + throw new InvalidOperationException("UnlockWallet.Password must be defined"); + } + OpenWallet(Settings.Default.UnlockWallet.Path, Settings.Default.UnlockWallet.Password); } catch (FileNotFoundException) @@ -485,14 +511,16 @@ private static void WriteLineWithoutFlicker(string message = "", int maxWidth = /// script /// sender /// Max fee for running the script - private void SendTransaction(byte[] script, UInt160 account = null, long gas = TestModeGas) + private void SendTransaction(byte[] script, UInt160? account = null, long gas = TestModeGas) { + if (NoWallet()) return; + Signer[] signers = Array.Empty(); var snapshot = NeoSystem.StoreView; if (account != null) { - signers = CurrentWallet.GetAccounts() + 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 }) .ToArray(); @@ -500,7 +528,7 @@ private void SendTransaction(byte[] script, UInt160 account = null, long gas = T try { - Transaction tx = CurrentWallet.MakeTransaction(snapshot, script, account, signers, maxGas: gas); + Transaction tx = CurrentWallet!.MakeTransaction(snapshot, script, account, signers, maxGas: gas); ConsoleHelper.Info("Invoking script with: ", $"'{Convert.ToBase64String(tx.Script.Span)}'"); using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: gas)) @@ -533,15 +561,18 @@ private void SendTransaction(byte[] script, UInt160 account = null, long gas = T /// 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 verifiable = 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(); + List parameters = new(); if (contractParameters != null) { foreach (var contractParameter in contractParameters) { - parameters.Add(ContractParameter.FromJson((JObject)contractParameter)); + if (contractParameter is not null) + { + parameters.Add(ContractParameter.FromJson((JObject)contractParameter)); + } } } @@ -578,7 +609,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI 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(); + result = engine.State == VMState.FAULT ? StackItem.Null : engine.ResultStack.Peek(); return engine.State != VMState.FAULT; } diff --git a/src/Neo.CLI/Extensions.cs b/src/Neo.CLI/Extensions.cs index d3dd1aa5ed..dec28a8e0d 100644 --- a/src/Neo.CLI/Extensions.cs +++ b/src/Neo.CLI/Extensions.cs @@ -20,9 +20,9 @@ internal static class Extensions { public static string GetVersion(this Assembly assembly) { - CustomAttributeData attribute = assembly.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(AssemblyInformationalVersionAttribute)); - if (attribute == null) return assembly.GetName().Version.ToString(3); - return (string)attribute.ConstructorArguments[0].Value; + CustomAttributeData? attribute = assembly.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(AssemblyInformationalVersionAttribute)); + if (attribute == null) return assembly.GetName().Version?.ToString(3) ?? string.Empty; + return (string)attribute.ConstructorArguments[0].Value!; } } } diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index 19f92a92cc..cd1b75fbc0 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -8,6 +8,7 @@ Neo Neo.CLI neo.ico + enable diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index ace4cb4863..df67a91237 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -21,7 +21,7 @@ public class Settings public P2PSettings P2P { get; } public UnlockWalletSettings UnlockWallet { get; } - static Settings _default; + static Settings? _default; static bool UpdateDefault(IConfiguration configuration) { @@ -44,7 +44,7 @@ public static Settings Default Initialize(config); } - return _default; + return _default!; } } @@ -65,7 +65,7 @@ public class LoggerSettings public LoggerSettings(IConfigurationSection section) { - this.Path = section.GetValue("Path", "Logs"); + this.Path = section.GetValue("Path", "Logs")!; this.ConsoleOutput = section.GetValue("ConsoleOutput", false); this.Active = section.GetValue("Active", false); } @@ -78,8 +78,8 @@ public class StorageSettings public StorageSettings(IConfigurationSection section) { - this.Engine = section.GetValue("Engine", "LevelDBStore"); - this.Path = section.GetValue("Path", "Data_LevelDB_{0}"); + this.Engine = section.GetValue("Engine", "LevelDBStore")!; + this.Path = section.GetValue("Path", "Data_LevelDB_{0}")!; } } @@ -93,8 +93,8 @@ public class P2PSettings public P2PSettings(IConfigurationSection section) { - this.Port = ushort.Parse(section.GetValue("Port", "10333")); - this.WsPort = ushort.Parse(section.GetValue("WsPort", "10334")); + this.Port = ushort.Parse(section.GetValue("Port", "10333")!); + this.WsPort = ushort.Parse(section.GetValue("WsPort", "10334")!); this.MinDesiredConnections = section.GetValue("MinDesiredConnections", Peer.DefaultMinDesiredConnections); this.MaxConnections = section.GetValue("MaxConnections", Peer.DefaultMaxConnections); this.MaxConnectionsPerAddress = section.GetValue("MaxConnectionsPerAddress", 3); @@ -103,8 +103,8 @@ public P2PSettings(IConfigurationSection section) public class UnlockWalletSettings { - public string Path { get; } - public string Password { get; } + public string? Path { get; } + public string? Password { get; } public bool IsActive { get; } public UnlockWalletSettings(IConfigurationSection section) @@ -113,7 +113,7 @@ public UnlockWalletSettings(IConfigurationSection section) { this.Path = section.GetValue("Path", ""); this.Password = section.GetValue("Password", ""); - this.IsActive = bool.Parse(section.GetValue("IsActive", "false")); + this.IsActive = bool.Parse(section.GetValue("IsActive", "false")!); } } } diff --git a/src/Neo.ConsoleService/CommandStringToken.cs b/src/Neo.ConsoleService/CommandStringToken.cs index c22d989996..f4ee1e6c97 100644 --- a/src/Neo.ConsoleService/CommandStringToken.cs +++ b/src/Neo.ConsoleService/CommandStringToken.cs @@ -39,7 +39,7 @@ public CommandStringToken(int offset, string value) : base(CommandTokenType.Stri /// Index /// Quote (could be null) /// CommandSpaceToken - internal static CommandStringToken Parse(string commandLine, ref int index, CommandQuoteToken quote) + internal static CommandStringToken Parse(string commandLine, ref int index, CommandQuoteToken? quote) { int end; int offset = index; diff --git a/src/Neo.ConsoleService/CommandToken.cs b/src/Neo.ConsoleService/CommandToken.cs index a8b8a47fd6..d4088e8c9b 100644 --- a/src/Neo.ConsoleService/CommandToken.cs +++ b/src/Neo.ConsoleService/CommandToken.cs @@ -29,7 +29,7 @@ internal abstract class CommandToken /// /// Value /// - public string Value { get; protected init; } + public string Value { get; protected init; } = string.Empty; /// /// Constructor @@ -49,7 +49,7 @@ protected CommandToken(CommandTokenType type, int offset) /// public static IEnumerable Parse(string commandLine) { - CommandToken lastToken = null; + CommandToken? lastToken = null; for (int index = 0, count = commandLine.Length; index < count;) { @@ -79,7 +79,10 @@ public static IEnumerable Parse(string commandLine) lastToken = CommandStringToken.Parse(commandLine, ref index, lastToken is CommandQuoteToken quote ? quote : null); - yield return lastToken; + if (lastToken is not null) + { + yield return lastToken; + } break; } } @@ -96,7 +99,7 @@ public static string[] ToArguments(IEnumerable tokens, bool remove { var list = new List(); - CommandToken lastToken = null; + CommandToken? lastToken = null; foreach (var token in tokens) { @@ -164,7 +167,7 @@ public static void Trim(List args) /// Args /// Consume all if not quoted /// String - public static string ReadString(List args, bool consumeAll) + public static string? ReadString(List args, bool consumeAll) { Trim(args); diff --git a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs index b880c03bec..0d18a5d1db 100644 --- a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs +++ b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs @@ -26,12 +26,12 @@ public class ConsoleCommandAttribute : Attribute /// /// Category /// - public string Category { get; set; } + public string Category { get; set; } = string.Empty; /// /// Description /// - public string Description { get; set; } + public string Description { get; set; } = string.Empty; /// /// Constructor diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index ae55b5fd76..8b4a54bdf3 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -26,7 +26,7 @@ namespace Neo.ConsoleService { public abstract class ConsoleServiceBase { - protected virtual string Depends => null; + protected virtual string? Depends => null; protected virtual string Prompt => "service"; public abstract string ServiceName { get; } @@ -48,9 +48,9 @@ private bool OnCommand(string commandLine) return true; } - string possibleHelp = null; + string? possibleHelp = null; var commandArgs = CommandToken.Parse(commandLine).ToArray(); - var availableCommands = new List<(ConsoleCommandMethod Command, object[] Arguments)>(); + var availableCommands = new List<(ConsoleCommandMethod Command, object?[] Arguments)>(); foreach (var entries in _verbs.Values) { @@ -58,7 +58,7 @@ private bool OnCommand(string commandLine) { if (command.IsThisCommand(commandArgs, out var consumedArgs)) { - var arguments = new List(); + var arguments = new List(); var args = commandArgs.Skip(consumedArgs).ToList(); CommandSpaceToken.Trim(args); @@ -114,7 +114,7 @@ private bool OnCommand(string commandLine) case 1: { var (command, arguments) = availableCommands[0]; - object result = command.Method.Invoke(command.Instance, arguments); + object? result = command.Method.Invoke(command.Instance, arguments); if (result is Task task) task.Wait(); return true; } @@ -127,7 +127,7 @@ private bool OnCommand(string commandLine) } } - private bool TryProcessValue(Type parameterType, List args, bool canConsumeAll, out object value) + private bool TryProcessValue(Type parameterType, List args, bool canConsumeAll, out object? value) { if (args.Count > 0) { @@ -140,8 +140,11 @@ private bool TryProcessValue(Type parameterType, List args, bool c if (parameterType.IsEnum) { var arg = CommandToken.ReadString(args, canConsumeAll); - value = Enum.Parse(parameterType, arg.Trim(), true); - return true; + if (arg is not null) + { + value = Enum.Parse(parameterType, arg.Trim(), true); + return true; + } } } @@ -198,7 +201,7 @@ protected void OnHelpCommand(string key) if (string.IsNullOrEmpty(key) || key.Equals("help", StringComparison.InvariantCultureIgnoreCase)) { - string last = null; + string? last = null; foreach (var command in withHelp) { if (last != command.HelpCategory) @@ -218,8 +221,8 @@ protected void OnHelpCommand(string key) { // Show help for this specific command - string last = null; - string lastKey = null; + string? last = null; + string? lastKey = null; bool found = false; foreach (var command in withHelp.Where(u => u.Key == key)) @@ -267,7 +270,7 @@ protected void OnClear() [ConsoleCommand("version", Category = "Base Commands", Description = "Show the current version.")] protected void OnVersion() { - Console.WriteLine(Assembly.GetEntryAssembly().GetName().Version); + Console.WriteLine(Assembly.GetEntryAssembly()!.GetName().Version); } /// @@ -391,7 +394,7 @@ private void SigTermEventHandler(AssemblyLoadContext obj) TriggerGracefulShutdown(); } - private void CancelHandler(object sender, ConsoleCancelEventArgs e) + private void CancelHandler(object? sender, ConsoleCancelEventArgs e) { e.Cancel = true; TriggerGracefulShutdown(); @@ -404,7 +407,7 @@ protected ConsoleServiceBase() { // Register self commands - RegisterCommandHandler(CommandToken.ReadString); + RegisterCommandHandler((args, canConsumeAll) => CommandToken.ReadString(args, canConsumeAll) ?? ""); RegisterCommandHandler((args, canConsumeAll) => { @@ -415,7 +418,7 @@ protected ConsoleServiceBase() return ret.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); } - return CommandToken.ReadString(args, false).Split(',', ' '); + return (CommandToken.ReadString(args, false)?.Split(',', ' ')) ?? Array.Empty(); }); RegisterCommandHandler(false, str => byte.Parse(str)); @@ -471,7 +474,7 @@ public void RegisterCommandHandler(Func handler) /// /// Instance /// Name - public void RegisterCommand(object instance, string name = null) + public void RegisterCommand(object instance, string? name = null) { if (!string.IsNullOrEmpty(name)) { @@ -516,20 +519,27 @@ public void Run(string[] args) ConsoleHelper.Warning("Only support for installing services on Windows."); return; } - string arguments = string.Format("create {0} start= auto binPath= \"{1}\"", ServiceName, Process.GetCurrentProcess().MainModule.FileName); + string arguments = string.Format("create {0} start= auto binPath= \"{1}\"", ServiceName, Process.GetCurrentProcess().MainModule!.FileName); if (!string.IsNullOrEmpty(Depends)) { arguments += string.Format(" depend= {0}", Depends); } - Process process = Process.Start(new ProcessStartInfo + Process? process = Process.Start(new ProcessStartInfo { Arguments = arguments, FileName = Path.Combine(Environment.SystemDirectory, "sc.exe"), RedirectStandardOutput = true, UseShellExecute = false }); - process.WaitForExit(); - Console.Write(process.StandardOutput.ReadToEnd()); + if (process is null) + { + ConsoleHelper.Error("Error installing the service with sc.exe."); + } + else + { + process.WaitForExit(); + Console.Write(process.StandardOutput.ReadToEnd()); + } } else if (args.Length > 0 && args[0] == "/uninstall") { @@ -538,15 +548,22 @@ public void Run(string[] args) ConsoleHelper.Warning("Only support for installing services on Windows."); return; } - Process process = Process.Start(new ProcessStartInfo + Process? process = Process.Start(new ProcessStartInfo { Arguments = string.Format("delete {0}", ServiceName), FileName = Path.Combine(Environment.SystemDirectory, "sc.exe"), RedirectStandardOutput = true, UseShellExecute = false }); - process.WaitForExit(); - Console.Write(process.StandardOutput.ReadToEnd()); + if (process is null) + { + ConsoleHelper.Error("Error installing the service with sc.exe."); + } + else + { + process.WaitForExit(); + Console.Write(process.StandardOutput.ReadToEnd()); + } } else { @@ -562,9 +579,9 @@ public void Run(string[] args) } } - protected string ReadLine() + protected string? ReadLine() { - Task readLineTask = Task.Run(Console.ReadLine); + Task readLineTask = Task.Run(Console.ReadLine); try { @@ -600,7 +617,7 @@ public virtual void RunConsole() } Console.ForegroundColor = ConsoleColor.Yellow; - string line = ReadLine()?.Trim(); + string? line = ReadLine()?.Trim(); if (line == null) break; Console.ForegroundColor = ConsoleColor.White; diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 173e3be4e0..5c2fd653ad 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -2,6 +2,7 @@ Neo.ConsoleService + enable