Chain trust score computation.
authorCryptoManiac <balthazar@yandex.ru>
Thu, 3 Sep 2015 19:59:58 +0000 (22:59 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Thu, 3 Sep 2015 19:59:58 +0000 (22:59 +0300)
Novacoin/CBlockStore.cs
Novacoin/Interop.cs
NovacoinTest/Program.cs

index a579898..94fc2b6 100644 (file)
@@ -76,9 +76,9 @@ namespace Novacoin
         public long nStakeModifier { get; set; }
 
         /// <summary>
-        /// Stake entropy bit
+        /// Chain trust score
         /// </summary>
-        public byte nEntropyBit { get; set; }
+        public byte[] ChainTrust { get; set; }
 
         /// <summary>
         /// Proof-of-Stake hash
@@ -221,6 +221,7 @@ namespace Novacoin
         /// <summary>
         /// Previous block cursor
         /// </summary>
+        [Ignore]
         public CBlockStoreItem prev {
             get { return CBlockStore.Instance.GetCursor(prevHash); }
         }
@@ -228,25 +229,31 @@ namespace Novacoin
         /// <summary>
         /// Next block cursor
         /// </summary>
+        [Ignore]
         public CBlockStoreItem next
         {
             get { return CBlockStore.Instance.GetCursor(nextHash); }
         }
 
+        [Ignore]
         bool IsInMainChain
         {
             get { return (next != null); }
         }
 
-
-    /// <summary>
-    /// STake modifier generation flag
-    /// </summary>
-    public bool GeneratedStakeModifier
+        /// <summary>
+        /// STake modifier generation flag
+        /// </summary>
+        [Ignore]
+        public bool GeneratedStakeModifier
         {
             get { return (BlockTypeFlag & BlockType.BLOCK_STAKE_MODIFIER) != 0; }
         }
 
+        /// <summary>
+        /// Stake entropy bit
+        /// </summary>
+        [Ignore]
         public uint StakeEntropyBit
         {
             get { return ((uint)(BlockTypeFlag & BlockType.BLOCK_STAKE_ENTROPY) >> 1); }
@@ -288,19 +295,143 @@ namespace Novacoin
         /// <summary>
         /// Block has no proof-of-stake flag.
         /// </summary>
+        [Ignore]
         public bool IsProofOfWork
         {
-            get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) != 0; }
+            get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) == 0; }
         }
 
         /// <summary>
         /// Block has proof-of-stake flag set.
         /// </summary>
+        [Ignore]
         public bool IsProofOfStake 
         {
-            get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) == 0; }
+            get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) != 0; }
         }
 
+        /// <summary>
+        /// Chain trust score.
+        /// </summary>
+        [Ignore]
+        public uint256 nChainTrust {
+            get
+            {
+                if (ChainTrust.Length != 32)
+                {
+                    byte[] tmp = ChainTrust;
+                    Array.Resize(ref tmp, 32);
+                    ChainTrust = tmp;
+                }
+
+                return ChainTrust;
+            }
+            set { ChainTrust = Interop.TrimArray(value); }
+        }
+
+        /// <summary>
+        /// Block trust score.
+        /// </summary>
+        [Ignore]
+        public uint256 nBlockTrust
+        {
+            get
+            {
+                uint256 nTarget = 0;
+                nTarget.Compact = nBits;
+
+                /* Old protocol */
+                if (nTime < NetUtils.nChainChecksSwitchTime)
+                {
+                    return IsProofOfStake ? (new uint256(1) << 256) / (nTarget + 1) : 1;
+                }
+
+                /* New protocol */
+
+                // Calculate work amount for block
+                var nPoWTrust = NetUtils.nPoWBase / (nTarget + 1);
+
+                // Set nPowTrust to 1 if we are checking PoS block or PoW difficulty is too low
+                nPoWTrust = (IsProofOfStake || !nPoWTrust) ? 1 : nPoWTrust;
+
+                // Return nPoWTrust for the first 12 blocks
+                if (prev == null || prev.nHeight < 12)
+                    return nPoWTrust;
+
+                CBlockStoreItem currentIndex = prev;
+
+                if (IsProofOfStake)
+                {
+                    var nNewTrust = (new uint256(1) << 256) / (nTarget + 1);
+
+                    // Return 1/3 of score if parent block is not the PoW block
+                    if (!prev.IsProofOfWork)
+                    {
+                        return nNewTrust / 3;
+                    }
+
+                    int nPoWCount = 0;
+
+                    // Check last 12 blocks type
+                    while (prev.nHeight - currentIndex.nHeight < 12)
+                    {
+                        if (currentIndex.IsProofOfWork)
+                        {
+                            nPoWCount++;
+                        }
+                        currentIndex = currentIndex.prev;
+                    }
+
+                    // Return 1/3 of score if less than 3 PoW blocks found
+                    if (nPoWCount < 3)
+                    {
+                        return nNewTrust / 3;
+                    }
+
+                    return nNewTrust;
+                }
+                else
+                {
+                    var nLastBlockTrust = prev.nChainTrust - prev.prev.nChainTrust;
+
+                    // Return nPoWTrust + 2/3 of previous block score if two parent blocks are not PoS blocks
+                    if (!prev.IsProofOfStake || !prev.prev.IsProofOfStake)
+                    {
+                        return nPoWTrust + (2 * nLastBlockTrust / 3);
+                    }
+
+                    int nPoSCount = 0;
+
+                    // Check last 12 blocks type
+                    while (prev.nHeight - currentIndex.nHeight < 12)
+                    {
+                        if (currentIndex.IsProofOfStake)
+                        {
+                            nPoSCount++;
+                        }
+                        currentIndex = currentIndex.prev;
+                    }
+
+                    // Return nPoWTrust + 2/3 of previous block score if less than 7 PoS blocks found
+                    if (nPoSCount < 7)
+                    {
+                        return nPoWTrust + (2 * nLastBlockTrust / 3);
+                    }
+
+                    nTarget.Compact = prev.nBits;
+
+                    if (!nTarget)
+                    {
+                        return 0;
+                    }
+
+                    var nNewTrust = (new uint256(1) << 256) / (nTarget + 1);
+
+                    // Return nPoWTrust + full trust score for previous block nBits
+                    return nPoWTrust + nNewTrust;
+                }
+            }
+        }
 
     }
 
@@ -451,6 +582,8 @@ namespace Novacoin
 
             fStreamReadWrite = File.Open(strBlockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
 
+            Instance = this;
+
             if (firstInit)
             {
                 lock (LockObj)
@@ -507,8 +640,6 @@ namespace Novacoin
                     blockMap.TryAdd(item.Hash, item);
                 }
             }
-
-            Instance = this;
         }
 
         public bool GetTransaction(uint256 TxID, ref CTransaction tx)
@@ -537,7 +668,15 @@ namespace Novacoin
                 return false;
             }
 
-            // TODO: compute chain trust, set stake entropy bit, record proof-of-stake hash value
+            // Compute chain trust score
+            itemTemplate.nChainTrust = (itemTemplate.prev != null ? itemTemplate.prev.nChainTrust : 0) + itemTemplate.nBlockTrust;
+
+            if (!itemTemplate.SetStakeEntropyBit(Entropy.GetStakeEntropyBit(itemTemplate.nHeight, blockHash)))
+            {
+                return false; // SetStakeEntropyBit() failed
+            }
+
+            // TODO: set stake entropy bit, record proof-of-stake hash value
 
             // TODO: compute stake modifier
 
@@ -635,7 +774,6 @@ namespace Novacoin
             var itemTemplate = new CBlockStoreItem()
             {
                 nHeight = nHeight,
-                nEntropyBit = Entropy.GetStakeEntropyBit(nHeight, nHash)
             };
 
             itemTemplate.FillHeader(block.header);
index 0cb7e75..55979d7 100644 (file)
@@ -82,6 +82,20 @@ namespace Novacoin
             return bytes;
         }
 
+        public static byte[] TrimArray(byte[] bytes)
+        {
+            int trimStart = bytes.Length - 1;
+            while (trimStart >= 0 && bytes[trimStart] == 0)
+            {
+                trimStart--;
+            }
+
+            byte[] result = new byte[trimStart + 1];
+            Array.Copy(bytes, 0, result, 0, trimStart + 1);
+
+            return result;
+        }
+
         public static string ToHex(byte[] bytes)
         {
             var sb = new StringBuilder();
index c8295c2..7483d4b 100644 (file)
@@ -12,6 +12,7 @@ namespace NovacoinTest
     {
         static void Main(string[] args)
         {
+#if false
             /// Transaction decoding/encoding tests
             string strUserTx = "0100000078b4c95306340d96b77ec4ee9d42b31cadc2fab911e48d48c36274d516f226d5e85bbc512c010000006b483045022100c8df1fc17b6ea1355a39b92146ec67b3b53565e636e028010d3a8a87f6f805f202203888b9b74df03c3960773f2a81b2dfd1efb08bb036a8f3600bd24d5ed694cd5a0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff364c640420de8fa77313475970bf09ce4d0b1f8eabb8f1d6ea49d90c85b202ee010000006b483045022100b651bf3a6835d714d2c990c742136d769258d0170c9aac24803b986050a8655b0220623651077ff14b0a9d61e30e30f2c15352f70491096f0ec655ae1c79a44e53aa0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff7adbd5f2e521f567bfea2cb63e65d55e66c83563fe253464b75184a5e462043d000000006a4730440220183609f2b995993acc9df241aff722d48b9a731b0cd376212934565723ed81f00220737e7ce75ef39bdc061d0dcdba3ee24e43b899696a7c96803cee0a79e1f78ecb0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff999eb03e00a41c2f9fde8865a554ceebbc48d30f4c8ba22dd88da8c9b46fa920030000006b483045022100ec1ab104ef086ba79b0f2611ebf1bfdd22a7a1020f6630fa1c6707546626e0db022056093d4048a999392185ccc735ef736a5497bd68f60b42e6c0c93ba770b54d010121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffffc0543b86be257ddd85b014a76718a70fab9eaa3c477460e4ca187094d86f369c0500000069463043021f24275c72f952043174daf01d7f713f878625f0522124a3cab48a0a2e12604202201b47742e6697b0ebdd1e4ba49c74baf142a0228ad0e0ee847488994c9dce78470121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffffe1793d4519147782293dd1db6d90e461265d91db2cc6889c37209394d42ad10d050000006a473044022018a0c3d73b2765d75380614ab36ee8e3c937080894a19166128b1e3357b208fb0220233c9609985f535547381431526867ad0255ec4969afe5c360544992ed6b3ed60121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff02e5420000000000001976a91457d84c814b14bd86bf32f106b733baa693db7dc788ac409c0000000000001976a91408c8768d5d6bf7c1d9609da4e766c3f1752247b188ac00000000";
 
@@ -313,12 +314,11 @@ namespace NovacoinTest
             1b138d5e
             0000000000136944000000000000000000000000000000000000000000000000
             */
+#endif
 
             Console.WriteLine("Reading the block file...");
             var bs = new CBlockStore();
             bs.ParseBlockFile();
-
-            Console.ReadLine();
         }
     }
 }