diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 449fa9c14b..f4abd36fff 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -13,7 +13,6 @@ using Neo.ConsoleService; using Neo.Extensions; using Neo.Json; -using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Plugins; @@ -28,13 +27,11 @@ using System.Collections.Generic; using System.Globalization; using System.IO; -using System.IO.Compression; using System.Linq; using System.Net; using System.Numerics; using System.Reflection; using System.Security.Cryptography; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Array = System.Array; @@ -171,108 +168,77 @@ private bool NoWallet() return true; } - private byte[] LoadDeploymentScript(string nefFilePath, string? manifestFilePath, JObject? data, out NefFile nef, out ContractManifest manifest) + private static ContractParameter? LoadScript(string nefFilePath, string? manifestFilePath, JObject? data, + out NefFile nef, out ContractManifest manifest) { if (string.IsNullOrEmpty(manifestFilePath)) - { manifestFilePath = Path.ChangeExtension(nefFilePath, ".manifest.json"); - } // Read manifest - var info = new FileInfo(manifestFilePath); - if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) - { - throw new ArgumentException(nameof(manifestFilePath)); - } + if (!info.Exists) + throw new ArgumentException("Manifest file not found", nameof(manifestFilePath)); + if (info.Length >= Transaction.MaxTransactionSize) + throw new ArgumentException("Manifest file is too large", nameof(manifestFilePath)); manifest = ContractManifest.Parse(File.ReadAllBytes(manifestFilePath)); // Read nef - info = new FileInfo(nefFilePath); - if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) - { - throw new ArgumentException(nameof(nefFilePath)); - } + if (!info.Exists) throw new ArgumentException("Nef file not found", nameof(nefFilePath)); + if (info.Length >= Transaction.MaxTransactionSize) + throw new ArgumentException("Nef file is too large", nameof(nefFilePath)); nef = File.ReadAllBytes(nefFilePath).AsSerializable(); - ContractParameter? dataParameter = null; + // Basic script checks + nef.Script.IsScriptValid(manifest.Abi); + if (data is not null) + { try { - dataParameter = ContractParameter.FromJson(data); + return ContractParameter.FromJson(data); } - catch + catch (Exception ex) { - throw new FormatException("invalid data"); + throw new FormatException("invalid data", ex); } + } - // Basic script checks - nef.Script.IsScriptValid(manifest.Abi); + return null; + } - // Build script + private byte[] LoadDeploymentScript(string nefFilePath, string? manifestFilePath, JObject? data, + out NefFile nef, out ContractManifest manifest) + { + var parameter = LoadScript(nefFilePath, manifestFilePath, data, out nef, out manifest); + var manifestJson = manifest.ToJson().ToString(); - using (ScriptBuilder sb = new ScriptBuilder()) + // Build script + using (var sb = new ScriptBuilder()) { - if (dataParameter is not null) - sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nef.ToArray(), manifest.ToJson().ToString(), dataParameter); + if (parameter is not null) + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nef.ToArray(), manifestJson, parameter); else - sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nef.ToArray(), manifest.ToJson().ToString()); + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nef.ToArray(), manifestJson); return sb.ToArray(); } } - 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)) - { - manifestFilePath = Path.ChangeExtension(nefFilePath, ".manifest.json"); - } - - // Read manifest - - var info = new FileInfo(manifestFilePath); - if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) - { - throw new ArgumentException(nameof(manifestFilePath)); - } - - manifest = ContractManifest.Parse(File.ReadAllBytes(manifestFilePath)); - - // Read nef - - info = new FileInfo(nefFilePath); - if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) - { - throw new ArgumentException(nameof(nefFilePath)); - } - - nef = File.ReadAllBytes(nefFilePath).AsSerializable(); - - ContractParameter? dataParameter = null; - if (data is not null) - try - { - dataParameter = ContractParameter.FromJson(data); - } - catch - { - throw new FormatException("invalid data"); - } - - // Basic script checks - nef.Script.IsScriptValid(manifest.Abi); + var parameter = LoadScript(nefFilePath, manifestFilePath, data, out nef, out manifest); + var manifestJson = manifest.ToJson().ToString(); // Build script - - using (ScriptBuilder sb = new ScriptBuilder()) + using (var sb = new ScriptBuilder()) { - if (dataParameter is null) - sb.EmitDynamicCall(scriptHash, "update", nef.ToArray(), manifest.ToJson().ToString()); + if (parameter is null) + sb.EmitDynamicCall(scriptHash, "update", nef.ToArray(), manifestJson); else - sb.EmitDynamicCall(scriptHash, "update", nef.ToArray(), manifest.ToJson().ToString(), dataParameter); + sb.EmitDynamicCall(scriptHash, "update", nef.ToArray(), manifestJson, parameter); return sb.ToArray(); } } @@ -302,21 +268,20 @@ public void OpenWallet(string path, string password) SignerManager.RegisterSigner(CurrentWallet.Name, CurrentWallet); } - public async void Start(CommandLineOptions options) + private static void ShowDllNotFoundError(DllNotFoundException ex) { - if (NeoSystem != null) return; - bool verifyImport = !(options.NoVerify ?? false); - - Utility.LogLevel = options.Verbose; - var protocol = ProtocolSettings.Load("config.json"); - CustomProtocolSettings(options, protocol); - CustomApplicationSettings(options, Settings.Default); - try + void DisplayError(string primaryMessage, string? secondaryMessage = null) { - NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, - string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + ConsoleHelper.Error(primaryMessage + Environment.NewLine + + (secondaryMessage != null ? secondaryMessage + Environment.NewLine : "") + + "Press any key to exit."); + Console.ReadKey(); + Environment.Exit(-1); } - catch (DllNotFoundException ex) when (ex.Message.Contains("libleveldb")) + + const string neoUrl = "https://github.com/neo-project/neo/releases"; + const string levelDbUrl = "https://github.com/neo-ngd/leveldb/releases"; + if (ex.Message.Contains("libleveldb")) { if (OperatingSystem.IsWindows()) { @@ -327,31 +292,47 @@ public async void Start(CommandLineOptions options) } else { - DisplayError("DLL not found, please get libleveldb.dll.", - "Download from https://github.com/neo-ngd/leveldb/releases"); + DisplayError("DLL not found, please get libleveldb.dll.", $"Download from {levelDbUrl}"); } } else if (OperatingSystem.IsLinux()) { DisplayError("Shared library libleveldb.so not found, please get libleveldb.so.", - "Use command \"sudo apt-get install libleveldb-dev\" in terminal or download from https://github.com/neo-ngd/leveldb/releases"); + $"Use command \"sudo apt-get install libleveldb-dev\" in terminal or download from {levelDbUrl}"); } else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst()) { DisplayError("Shared library libleveldb.dylib not found, please get libleveldb.dylib.", - "Use command \"brew install leveldb\" in terminal or download from https://github.com/neo-ngd/leveldb/releases"); + $"Use command \"brew install leveldb\" in terminal or download from {levelDbUrl}"); } else { - DisplayError("Neo CLI is broken, please reinstall it.", - "Download from https://github.com/neo-project/neo/releases"); + DisplayError("Neo CLI is broken, please reinstall it.", $"Download from {neoUrl}"); } - return; } - catch (DllNotFoundException) + else + { + DisplayError("Neo CLI is broken, please reinstall it.", $"Download from {neoUrl}"); + } + } + + public async void Start(CommandLineOptions options) + { + if (NeoSystem != null) return; + bool verifyImport = !(options.NoVerify ?? false); + + Utility.LogLevel = options.Verbose; + var protocol = ProtocolSettings.Load("config.json"); + CustomProtocolSettings(options, protocol); + CustomApplicationSettings(options, Settings.Default); + try + { + NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, + string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + } + catch (DllNotFoundException ex) { - DisplayError("Neo CLI is broken, please reinstall it.", - "Download from https://github.com/neo-project/neo/releases"); + ShowDllNotFoundError(ex); return; } @@ -360,15 +341,18 @@ public async void Start(CommandLineOptions options) LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; // installing plugins - var installTasks = options.Plugins?.Select(p => p).Where(p => !string.IsNullOrEmpty(p)).ToList().Select(p => InstallPluginAsync(p)); + var installTasks = options.Plugins?.Select(p => p) + .Where(p => !string.IsNullOrEmpty(p)) + .ToList() + .Select(p => InstallPluginAsync(p)); if (installTasks is not null) { await Task.WhenAll(installTasks); } + foreach (var plugin in Plugin.Plugins) { // Register plugins commands - RegisterCommand(plugin, plugin.Name); } @@ -413,17 +397,6 @@ public async void Start(CommandLineOptions options) ConsoleHelper.Error(ex.GetBaseException().Message); } } - - return; - - void DisplayError(string primaryMessage, string? secondaryMessage = null) - { - ConsoleHelper.Error(primaryMessage + Environment.NewLine + - (secondaryMessage != null ? secondaryMessage + Environment.NewLine : "") + - "Press any key to exit."); - Console.ReadKey(); - Environment.Exit(-1); - } } public void Stop() @@ -432,14 +405,6 @@ public void Stop() Interlocked.Exchange(ref _neoSystem, null)?.Dispose(); } - private static void WriteLineWithoutFlicker(string message = "", int maxWidth = 80) - { - if (message.Length > 0) Console.Write(message); - var spacesToErase = maxWidth - message.Length; - if (spacesToErase < 0) spacesToErase = 0; - Console.WriteLine(new string(' ', spacesToErase)); - } - /// /// Make and send transaction with script, sender /// @@ -450,9 +415,8 @@ private void SendTransaction(byte[] script, UInt160? account = null, long datosh { if (NoWallet()) return; - Signer[] signers = Array.Empty(); + var signers = Array.Empty(); var snapshot = NeoSystem.StoreView; - if (account != null) { signers = CurrentWallet!.GetAccounts() @@ -463,10 +427,9 @@ private void SendTransaction(byte[] script, UInt160? account = null, long datosh try { - Transaction tx = CurrentWallet!.MakeTransaction(snapshot, script, account, signers, maxGas: datoshi); + var tx = CurrentWallet!.MakeTransaction(snapshot, script, account, signers, maxGas: datoshi); ConsoleHelper.Info("Invoking script with: ", $"'{Convert.ToBase64String(tx.Script.Span)}'"); - - using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: datoshi)) + using (var engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: datoshi)) { PrintExecutionOutput(engine, true); if (engine.State == VMState.FAULT) return; @@ -496,10 +459,10 @@ private void SendTransaction(byte[] script, UInt160? account = null, long datosh /// Show result stack if it is true /// Max fee for running the script, in the unit of datoshi, 1 datoshi = 1e-8 GAS /// 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 datoshi = TestModeGas) + private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, + IVerifiable? verifiable = null, JArray? contractParameters = null, bool showStack = true, long datoshi = TestModeGas) { - List parameters = new(); - + var parameters = new List(); if (contractParameters != null) { foreach (var contractParameter in contractParameters) @@ -511,7 +474,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI } } - ContractState contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); + var contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); if (contract == null) { ConsoleHelper.Error("Contract does not exist."); @@ -529,8 +492,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI } byte[] script; - - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (var scriptBuilder = new ScriptBuilder()) { scriptBuilder.EmitDynamicCall(scriptHash, operation, parameters.ToArray()); script = scriptBuilder.ToArray(); @@ -542,7 +504,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI tx.Script = script; } - using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: datoshi); + using var engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: datoshi); PrintExecutionOutput(engine, showStack); result = engine.State == VMState.FAULT ? StackItem.Null : engine.ResultStack.Peek(); return engine.State != VMState.FAULT;