From 5fe57ee6ff429bbc4e6fbca07f9244ab216f19cb Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 12 Dec 2017 07:37:28 -0600 Subject: [PATCH] NEP-6 (#66) --- neo-cli/Network/RPC/RpcServerWithWallet.cs | 12 +- neo-cli/Program.cs | 6 +- neo-cli/Services/ConsoleServiceBase.cs | 34 ++++- neo-cli/Shell/Coins.cs | 2 +- neo-cli/Shell/MainService.cs | 156 ++++++++++++--------- neo-cli/neo-cli.csproj | 4 +- 6 files changed, 136 insertions(+), 78 deletions(-) diff --git a/neo-cli/Network/RPC/RpcServerWithWallet.cs b/neo-cli/Network/RPC/RpcServerWithWallet.cs index 19b80ff43..b7533eeff 100644 --- a/neo-cli/Network/RPC/RpcServerWithWallet.cs +++ b/neo-cli/Network/RPC/RpcServerWithWallet.cs @@ -61,7 +61,7 @@ protected override JObject Process(string method, JArray _params) if (context.Completed) { tx.Scripts = context.GetScripts(); - Program.Wallet.SaveTransaction(tx); + Program.Wallet.ApplyTransaction(tx); LocalNode.Relay(tx); return tx.ToJson(); } @@ -104,7 +104,7 @@ protected override JObject Process(string method, JArray _params) if (context.Completed) { tx.Scripts = context.GetScripts(); - Program.Wallet.SaveTransaction(tx); + Program.Wallet.ApplyTransaction(tx); LocalNode.Relay(tx); return tx.ToJson(); } @@ -118,9 +118,7 @@ protected override JObject Process(string method, JArray _params) throw new RpcException(-400, "Access denied"); else { - KeyPair key = Program.Wallet.CreateKey(); - VerificationContract contract = Program.Wallet.GetContracts(key.PublicKeyHash).First(p => p.IsStandard); - return contract.Address; + return Program.Wallet.CreateAccount().Address; } case "dumpprivkey": if (Program.Wallet == null) @@ -128,8 +126,8 @@ protected override JObject Process(string method, JArray _params) else { UInt160 scriptHash = Wallet.ToScriptHash(_params[0].AsString()); - KeyPair key = Program.Wallet.GetKeyByScriptHash(scriptHash); - return key.Export(); + WalletAccount account = Program.Wallet.GetAccount(scriptHash); + return account.GetKey().Export(); } default: return base.Process(method, _params); diff --git a/neo-cli/Program.cs b/neo-cli/Program.cs index a28b15198..01c8a38a4 100644 --- a/neo-cli/Program.cs +++ b/neo-cli/Program.cs @@ -1,5 +1,5 @@ -using Neo.Implementations.Wallets.EntityFramework; -using Neo.Shell; +using Neo.Shell; +using Neo.Wallets; using System; using System.IO; @@ -7,7 +7,7 @@ namespace Neo { static class Program { - internal static UserWallet Wallet; + internal static Wallet Wallet; private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { diff --git a/neo-cli/Services/ConsoleServiceBase.cs b/neo-cli/Services/ConsoleServiceBase.cs index 83a43882d..fb2a9e51f 100644 --- a/neo-cli/Services/ConsoleServiceBase.cs +++ b/neo-cli/Services/ConsoleServiceBase.cs @@ -35,6 +35,38 @@ protected virtual bool OnCommand(string[] args) protected internal abstract void OnStop(); + public static string ReadPassword(string prompt) + { + const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + StringBuilder sb = new StringBuilder(); + ConsoleKeyInfo key; + Console.Write(prompt); + Console.Write(": "); + + Console.ForegroundColor = ConsoleColor.Yellow; + + do + { + key = Console.ReadKey(true); + if (t.IndexOf(key.KeyChar) != -1) + { + sb.Append(key.KeyChar); + Console.Write('*'); + } + else if (key.Key == ConsoleKey.Backspace && sb.Length > 0) + { + sb.Length--; + Console.Write(key.KeyChar); + Console.Write(' '); + Console.Write(key.KeyChar); + } + } while (key.Key != ConsoleKey.Enter); + + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(); + return sb.ToString(); + } + public static SecureString ReadSecureString(string prompt) { const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; @@ -117,7 +149,7 @@ private void RunConsole() } } - Console.ResetColor(); + Console.ResetColor(); } } } diff --git a/neo-cli/Shell/Coins.cs b/neo-cli/Shell/Coins.cs index 00136681e..a777243ec 100644 --- a/neo-cli/Shell/Coins.cs +++ b/neo-cli/Shell/Coins.cs @@ -101,7 +101,7 @@ private Transaction SignTransaction(Transaction tx) if (context.Completed) { context.Verifiable.Scripts = context.GetScripts(); - current_wallet.SaveTransaction(tx); + current_wallet.ApplyTransaction(tx); bool relay_result = local_node.Relay(tx); diff --git a/neo-cli/Shell/MainService.cs b/neo-cli/Shell/MainService.cs index 2bcd6e1f5..0dd09ddba 100644 --- a/neo-cli/Shell/MainService.cs +++ b/neo-cli/Shell/MainService.cs @@ -2,6 +2,7 @@ using Neo.Core; using Neo.Implementations.Blockchains.LevelDB; using Neo.Implementations.Wallets.EntityFramework; +using Neo.Implementations.Wallets.NEP6; using Neo.IO; using Neo.IO.Json; using Neo.Network; @@ -15,7 +16,7 @@ using System.IO; using System.IO.Compression; using System.Linq; -using System.Security; +using System.Security.Cryptography; using System.Threading.Tasks; namespace Neo.Shell @@ -117,12 +118,13 @@ private bool OnCreateAddressCommand(string[] args) List addresses = new List(); for (int i = 1; i <= count; i++) { - KeyPair key = Program.Wallet.CreateKey(); - VerificationContract contract = Program.Wallet.GetContracts(key.PublicKeyHash).First(p => p.IsStandard); - addresses.Add(contract.Address); + WalletAccount account = Program.Wallet.CreateAccount(); + addresses.Add(account.Address); Console.SetCursorPosition(0, Console.CursorTop); Console.Write($"[{i}/{count}]"); } + if (Program.Wallet is NEP6Wallet wallet) + wallet.Save(); Console.WriteLine(); string path = "address.txt"; Console.WriteLine($"export addresses to {path}"); @@ -137,20 +139,26 @@ private bool OnCreateWalletCommand(string[] args) Console.WriteLine("error"); return true; } - using (SecureString password = ReadSecureString("password")) - using (SecureString password2 = ReadSecureString("password")) + string path = args[2]; + if (Path.GetExtension(path) == ".db3") { - if (!password.CompareTo(password2)) - { - Console.WriteLine("error"); - return true; - } - Program.Wallet = UserWallet.Create(args[2], password); + Console.WriteLine("The wallet file in the db3 format is not supported."); + return true; + } + string password = ReadPassword("password"); + string password2 = ReadPassword("password"); + if (password != password2) + { + Console.WriteLine("error"); + return true; } - VerificationContract contract = Program.Wallet.GetContracts().First(p => p.IsStandard); - KeyPair key = Program.Wallet.GetKey(contract.PublicKeyHash); - Console.WriteLine($"address: {contract.Address}"); - Console.WriteLine($" pubkey: {key.PublicKey.EncodePoint(true).ToHexString()}"); + NEP6Wallet wallet = new NEP6Wallet(path); + wallet.Unlock(password); + WalletAccount account = wallet.CreateAccount(); + wallet.Save(); + Program.Wallet = wallet; + Console.WriteLine($"address: {account.Address}"); + Console.WriteLine($" pubkey: {account.GetKey().PublicKey.EncodePoint(true).ToHexString()}"); return true; } @@ -233,24 +241,22 @@ private bool OnExportKeyCommand(string[] args) scriptHash = Wallet.ToScriptHash(args[2]); path = args[3]; } - using (SecureString password = ReadSecureString("password")) + string password = ReadPassword("password"); + if (password.Length == 0) { - if (password.Length == 0) - { - Console.WriteLine("cancelled"); - return true; - } - if (!Program.Wallet.VerifyPassword(password)) - { - Console.WriteLine("Incorrect password"); - return true; - } + Console.WriteLine("cancelled"); + return true; + } + if (!Program.Wallet.VerifyPassword(password)) + { + Console.WriteLine("Incorrect password"); + return true; } IEnumerable keys; if (scriptHash == null) - keys = Program.Wallet.GetKeys(); + keys = Program.Wallet.GetAccounts().Where(p => p.HasKey).Select(p => p.GetKey()); else - keys = new[] { Program.Wallet.GetKeyByScriptHash(scriptHash) }; + keys = new[] { Program.Wallet.GetAccount(scriptHash).GetKey() }; if (path == null) foreach (KeyPair key in keys) Console.WriteLine(key.Export()); @@ -326,7 +332,7 @@ private bool OnImportKeyCommand(string[] args) prikey = lines[i].HexToBytes(); else prikey = Wallet.GetPrivateKeyFromWIF(lines[i]); - Program.Wallet.CreateKey(prikey); + Program.Wallet.CreateAccount(prikey); Array.Clear(prikey, 0, prikey.Length); Console.SetCursorPosition(0, Console.CursorTop); Console.Write($"[{i + 1}/{lines.Length}]"); @@ -335,12 +341,13 @@ private bool OnImportKeyCommand(string[] args) } else { - KeyPair key = Program.Wallet.CreateKey(prikey); + WalletAccount account = Program.Wallet.CreateAccount(prikey); Array.Clear(prikey, 0, prikey.Length); - VerificationContract contract = Program.Wallet.GetContracts(key.PublicKeyHash).First(p => p.IsStandard); - Console.WriteLine($"address: {contract.Address}"); - Console.WriteLine($" pubkey: {key.PublicKey.EncodePoint(true).ToHexString()}"); + Console.WriteLine($"address: {account.Address}"); + Console.WriteLine($" pubkey: {account.GetKey().PublicKey.EncodePoint(true).ToHexString()}"); } + if (Program.Wallet is NEP6Wallet wallet) + wallet.Save(); return true; } @@ -400,7 +407,7 @@ private bool OnShowGasCommand(string[] args) private bool OnListKeyCommand(string[] args) { if (Program.Wallet == null) return true; - foreach (KeyPair key in Program.Wallet.GetKeys()) + foreach (KeyPair key in Program.Wallet.GetAccounts().Where(p => p.HasKey).Select(p => p.GetKey())) { Console.WriteLine(key.PublicKey); } @@ -410,7 +417,7 @@ private bool OnListKeyCommand(string[] args) private bool OnListAddressCommand(string[] args) { if (Program.Wallet == null) return true; - foreach (VerificationContract contract in Program.Wallet.GetContracts()) + foreach (Contract contract in Program.Wallet.GetAccounts().Where(p => !p.WatchOnly).Select(p => p.Contract)) { Console.WriteLine($"{contract.Address}\t{(contract.IsStandard ? "Standard" : "Nonstandard")}"); } @@ -457,27 +464,43 @@ private bool OnOpenWalletCommand(string[] args) Console.WriteLine("error"); return true; } - if (!File.Exists(args[2])) + string path = args[2]; + if (!File.Exists(path)) { Console.WriteLine($"File does not exist"); return true; } - using (SecureString password = ReadSecureString("password")) + string password = ReadPassword("password"); + if (password.Length == 0) + { + Console.WriteLine("cancelled"); + return true; + } + if (Path.GetExtension(path) == ".db3") { - if (password.Length == 0) + try + { + Program.Wallet = UserWallet.Open(path, password); + } + catch (CryptographicException) { - Console.WriteLine("cancelled"); + Console.WriteLine($"failed to open file \"{path}\""); return true; } + } + else + { + NEP6Wallet nep6wallet = new NEP6Wallet(path); try { - Program.Wallet = UserWallet.Open(args[2], password); + nep6wallet.Unlock(password); } - catch + catch (CryptographicException) { - Console.WriteLine($"failed to open file \"{args[2]}\""); + Console.WriteLine($"failed to open file \"{path}\""); return true; } + Program.Wallet = nep6wallet; } return true; } @@ -495,8 +518,7 @@ private bool OnRebuildCommand(string[] args) private bool OnRebuildIndexCommand(string[] args) { - if (Program.Wallet == null) return true; - Program.Wallet.Rebuild(); + WalletIndexer.RebuildIndex(); return true; } @@ -530,18 +552,16 @@ private bool OnSendCommand(string[] args) Console.WriteLine("You have to open the wallet first."); return true; } - using (SecureString password = ReadSecureString("password")) + string password = ReadPassword("password"); + if (password.Length == 0) { - if (password.Length == 0) - { - Console.WriteLine("cancelled"); - return true; - } - if (!Program.Wallet.VerifyPassword(password)) - { - Console.WriteLine("Incorrect password"); - return true; - } + Console.WriteLine("cancelled"); + return true; + } + if (!Program.Wallet.VerifyPassword(password)) + { + Console.WriteLine("Incorrect password"); + return true; } UIntBase assetId; switch (args[1].ToLower()) @@ -608,7 +628,7 @@ private bool OnSendCommand(string[] args) if (context.Completed) { tx.Scripts = context.GetScripts(); - Program.Wallet.SaveTransaction(tx); + Program.Wallet.ApplyTransaction(tx); LocalNode.Relay(tx); Console.WriteLine($"TXID: {tx.Hash}"); } @@ -819,17 +839,25 @@ private bool OnUpgradeWalletCommand(string[] args) return true; } string path = args[2]; + if (Path.GetExtension(path) != ".db3") + { + Console.WriteLine("Can't upgrade the wallet file."); + return true; + } if (!File.Exists(path)) { - Console.WriteLine("File does not exist"); + Console.WriteLine("File does not exist."); + return true; + } + string password = ReadPassword("password"); + if (password.Length == 0) + { + Console.WriteLine("cancelled"); return true; } - string path_old = Path.ChangeExtension(path, ".old.db3"); - string path_new = Path.ChangeExtension(path, ".new.db3"); - UserWallet.Migrate(path, path_new); - File.Move(path, path_old); - File.Move(path_new, path); - Console.WriteLine($"Wallet file upgrade complete. Old file has been auto-saved at: {path_old}"); + string path_new = Path.ChangeExtension(path, ".json"); + NEP6Wallet.Migrate(path_new, path, password).Save(); + Console.WriteLine($"Wallet file upgrade complete. New wallet file has been auto-saved at: {path_new}"); return true; } diff --git a/neo-cli/neo-cli.csproj b/neo-cli/neo-cli.csproj index 21a347106..e3b558fe1 100644 --- a/neo-cli/neo-cli.csproj +++ b/neo-cli/neo-cli.csproj @@ -3,7 +3,7 @@ 2016-2017 The Neo Project Neo.CLI - 2.4.1 + 2.5.0 The Neo Project netcoreapp2.0 neo-cli @@ -28,7 +28,7 @@ - +