Simplest implementation of CKeyStore
authorCryptoManiac <balthazar@yandex.ru>
Tue, 25 Aug 2015 23:47:29 +0000 (02:47 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Tue, 25 Aug 2015 23:47:29 +0000 (02:47 +0300)
Novacoin/CKeyStore.cs
Novacoin/CNovacoinAddress.cs
Novacoin/Novacoin.csproj
NovacoinTest/Program.cs

index 59c3fbd..e90b103 100644 (file)
-\feffusing System;
-using System.Collections.Generic;
+\feff/**
+ *  Novacoin classes library
+ *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
+
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using SQLite.Net;
+using SQLite.Net.Attributes;
+using SQLite.Net.Interop;
+using SQLite.Net.Platform.Generic;
+using System.IO;
 using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace Novacoin
 {
+    /// <summary>
+    /// Key storage item and structure
+    /// </summary>
+    [Table("KeyStorage")]
+    class KeyStorageItem
+    {
+        /// <summary>
+        /// Key item number
+        /// </summary>
+        [PrimaryKey, AutoIncrement]
+        public int ItemId { get; set; }
+
+        /// <summary>
+        /// Hash160 of pubkey in base58 form
+        /// </summary>
+        public string KeyID { get; set; }
+
+        /// <summary>
+        /// Public key in base58 form
+        /// </summary>
+        public string PublicKey { get; set; }
+
+        /// <summary>
+        /// Private key in base58 form
+        /// </summary>
+        public string PrivateKey { get; set; }
+
+        /// <summary>
+        /// Compressed key flag
+        /// </summary>
+        public bool IsCompressed { get; set; }
+
+        /// <summary>
+        /// Is this key a part of KeyPool?
+        /// </summary>
+        [Indexed]
+        public bool IsUsed { get; set; }
+    }
+
+    /// <summary>
+    /// Script storage item and structure
+    /// </summary>
+    [Table("ScriptStorage")]
+    class ScriptStorageItem
+    {
+        /// <summary>
+        /// Script item number
+        /// </summary>
+        [PrimaryKey, AutoIncrement]
+        public int ItemId { get; set; }
+
+        /// <summary>
+        /// Hash160 of script in base58 form
+        /// </summary>
+        public string ScriptID { get; set; }
+
+        /// <summary>
+        /// Script code bytes in hex form
+        /// </summary>
+        public string ScriptCode { get; set; }
+
+    }
+
+    /// <summary>
+    /// select count(...) as Count from ... where ...
+    /// </summary>
+    class CountQuery
+    {
+        public int Count { get; set; }
+    }
+
     public class CKeyStore
     {
-        public CKeyStore(string strDatabasePath="Wallet.db")
+        private object LockObj = new object();
+        private SQLiteConnection dbConn = null;
+
+        public CKeyStore(string strDatabasePath="KeyStore.db")
         {
+            bool firstInit = File.Exists(strDatabasePath);
+
+            dbConn = new SQLiteConnection(new SQLitePlatformGeneric(), strDatabasePath);
+
+            if (!firstInit)
+            {
+                lock(LockObj)
+                {
+                    dbConn.CreateTable<KeyStorageItem>(CreateFlags.AutoIncPK);
+                    dbConn.CreateTable<ScriptStorageItem>(CreateFlags.AutoIncPK);
+
+                    // Generate keys
+                    for (int i = 0; i < 100; i++)
+                    {
+                        var keyPair = new CKeyPair();
+
+                        var res = dbConn.Insert(new KeyStorageItem()
+                        {
+                            KeyID = keyPair.KeyID.ToString(),       // Use string serializarion of binary values, 
+                            PublicKey = keyPair.PubKey.ToString(),  //  otherwise sqlite corrupts them.
+                            PrivateKey = keyPair.ToString(),
+                            IsCompressed = keyPair.IsCompressed,
+                            IsUsed = false
+                        });
+
+                        // TODO: Additional initialization
+                    }
+                }
+            }
         }
 
         ~CKeyStore()
         {
+            if (dbConn != null)
+            {
+                dbConn.Close();
+                dbConn = null;
+            }
         }
 
+        /// <summary>
+        /// Insert key data into table
+        /// </summary>
+        /// <param name="keyPair">CKeyPair instance</param>
+        /// <returns>Result</returns>
         public bool AddKey(CKeyPair keyPair)
         {
-            // TODO
+            lock(LockObj)
+            {
+                var res = dbConn.Insert(new KeyStorageItem()
+                {
+                    KeyID = keyPair.KeyID.ToString(),
+                    PublicKey = keyPair.PubKey.ToString(),
+                    PrivateKey = keyPair.ToString(),
+                    IsCompressed = keyPair.IsCompressed,
+                    IsUsed = true
+                });
+
+                if (res == 0)
+                {
+                    return false;
+                }
+            }
 
             return true;
         }
 
         public bool HaveKey(CKeyID keyID)
         {
-            // TODO
+            var QueryCount = dbConn.Query<CountQuery>("select count([ItemID]) as [Count] from [KeyStorage] where [KeyID] = ?", keyID.ToString());
 
-            return true;
+
+            return QueryCount.First().Count == 1;
         }
 
+        /// <summary>
+        /// Get the key pair object.
+        /// </summary>
+        /// <param name="keyID">Hash of public key.</param>
+        /// <param name="keyPair">Instance of CKeyPair or null.</param>
+        /// <returns>Result</returns>
         public bool GetKey(CKeyID keyID, out CKeyPair keyPair)
         {
-            keyPair = new CKeyPair();
+            var QueryGet = dbConn.Query<KeyStorageItem>("select * from [KeyStorage] where [KeyID] = ?", keyID.ToString());
 
+            if (QueryGet.Count() == 1)
+            {
+                keyPair = new CKeyPair(QueryGet.First().PrivateKey);
+                return true;
+            }
+
+            keyPair = null;
             return false;
         }
 
         public bool AddScript(CScript script)
         {
-            // TODO
+            lock (LockObj)
+            {
+                var res = dbConn.Insert(new ScriptStorageItem()
+                {
+                    ScriptID = script.ScriptID.ToString(),
+                    ScriptCode = Interop.ToHex(script.Bytes)
+                });
+
+                if (res == 0)
+                {
+                    return false;
+                }
+            }
 
             return true;
         }
 
         public bool HaveScript(CScriptID scriptID)
         {
-            // TODO
+            var QueryGet = dbConn.Query<CountQuery>("select count([ItemID]) from [ScriptStorage] where [ScriptID] = ?", scriptID.ToString());
 
-            return true;
+            return QueryGet.First().Count == 1;
         }
 
         public bool GetScript(CScriptID scriptID, out CScript script)
         {
-            // TODO
+            var QueryGet = dbConn.Query<ScriptStorageItem>("select * from [ScriptStorage] where [ScriptID] = ?", scriptID.ToString());
 
-            script = new CScript();
+            if (QueryGet.Count() == 1)
+            {
+                script = new CScript(Interop.HexToArray(QueryGet.First().ScriptCode));
+                return true;
+            }
 
-            return true;
+            script = null;
+            return false;
         }
 
 
index 22e94ae..e443b88 100644 (file)
@@ -79,6 +79,11 @@ namespace Novacoin
             addrData = new List<byte>(scriptID.hashBytes);
         }
 
+        public Hash160 Hash
+        {
+            get { return new Hash160(addrData.ToArray()); }
+        }
+
         /// <summary>
         /// Basic sanity checking
         /// </summary>
index fc561f8..141a992 100644 (file)
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="SQLite.Net, Version=3.0.5.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\SQLite.Net-PCL.3.0.5\lib\net40\SQLite.Net.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="SQLite.Net.Platform.Generic, Version=3.0.5.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\SQLite.Net-PCL.3.0.5\lib\net40\SQLite.Net.Platform.Generic.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="SQLite.Net.Platform.Win32, Version=3.0.5.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\SQLite.Net-PCL.3.0.5\lib\net4\SQLite.Net.Platform.Win32.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Numerics" />
     <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123">
index 0fc0176..708747d 100644 (file)
@@ -231,12 +231,12 @@ namespace NovacoinTest
 
             Hash256 merkleroot = null;
 
-            Console.WriteLine("\nRinning 1000 iterations of merkle tree computation for very big block...");
+            Console.WriteLine("\nRinning 100 iterations of merkle tree computation for very big block...");
 
             watch = Stopwatch.StartNew();
             // the code that you want to measure comes here
 
-            for (int i = 0; i < 1000; i++)
+            for (int i = 0; i < 100; i++)
             {
                 merkleroot = veryBigBlock.hashMerkleRoot;
             }
@@ -246,6 +246,25 @@ namespace NovacoinTest
             Console.WriteLine("Calculation time: {0} ms\n", elapsedMs);
             Console.WriteLine("Merkle tree is OK: {0}", merkleroot.hashBytes.SequenceEqual(veryBigBlock.header.merkleRoot.hashBytes));
 
+            // Initialization of key store
+
+            Console.Write("Initialization of key store...");
+            var keyStore = new CKeyStore();
+
+            Console.WriteLine("Adding and querying new key pair");
+            var kp1 = new CKeyPair();
+            keyStore.AddKey(kp1);
+
+
+            CKeyPair kp2;
+            var queryRes = keyStore.GetKey(kp1.KeyID, out kp2);
+            Console.WriteLine("KeyID={0} exists in database: {1}", kp1.KeyID.ToString(), queryRes);
+
+            if (queryRes)
+            {
+                Console.WriteLine("KeyID={0} is identical to inserted one: {1}", kp2.KeyID.ToString(), kp2.KeyID.ToString() == kp1.KeyID.ToString());
+            }
+
             Console.ReadLine();
         }
     }