Use GetProofOfStakeHash
[NovacoinLibrary.git] / Novacoin / StakeModifier.cs
index 7f45eb8..882a699 100644 (file)
@@ -144,7 +144,7 @@ namespace Novacoin
             selectedCursor = null;
             foreach (var item in sortedByTimestamp)
             {
-                CBlockStoreItem cursor = CBlockStore.Instance.GetCursor(item.Item2);
+                CBlockStoreItem cursor = CBlockStore.Instance.GetMapCursor(item.Item2);
 
                 if (cursor == null)
                 {
@@ -280,7 +280,7 @@ namespace Novacoin
                 }
 
                 // write the entropy bit of the selected block
-                nStakeModifierNew |= ((cursor.StakeEntropyBit) << nRound);
+                nStakeModifierNew |= (((long)cursor.StakeEntropyBit) << nRound);
 
                 // add the selected block from candidates to selected list
                 mapSelectedBlocks.Add(cursor.Hash, cursor);
@@ -295,10 +295,13 @@ namespace Novacoin
         /// The stake modifier used to hash for a stake kernel is chosen as the stake
         /// modifier about a selection interval later than the coin generating the kernel
         /// </summary>
-        static bool GetKernelStakeModifier(uint256 hashBlockFrom, ref long nStakeModifier, ref uint nStakeModifierHeight, ref uint nStakeModifierTime)
+        static bool GetKernelStakeModifier(uint256 hashBlockFrom, out long nStakeModifier, out uint nStakeModifierHeight, out uint nStakeModifierTime)
         {
             nStakeModifier = 0;
-            var cursorFrom = CBlockStore.Instance.GetCursor(hashBlockFrom);
+            nStakeModifierTime = 0;
+            nStakeModifierHeight = 0;
+
+            var cursorFrom = CBlockStore.Instance.GetMapCursor(hashBlockFrom);
             if (cursorFrom == null)
             {
                 return false; // Block not indexed
@@ -330,16 +333,18 @@ namespace Novacoin
             return true;
         }
 
-        public static bool GetKernelStakeModifier(uint256 hashBlockFrom, ref long nStakeModifier)
+        public static bool GetKernelStakeModifier(uint256 hashBlockFrom, out long nStakeModifier)
         {
             uint nStakeModifierHeight = 0;
             uint nStakeModifierTime = 0;
 
-            return GetKernelStakeModifier(hashBlockFrom, ref nStakeModifier, ref nStakeModifierHeight, ref nStakeModifierTime);
+            return GetKernelStakeModifier(hashBlockFrom, out nStakeModifier, out nStakeModifierHeight, out nStakeModifierTime);
         }
 
-        public static bool CheckStakeKernelHash(uint nBits, uint256 hashBlockFrom, uint nTimeBlockFrom, uint nTxPrevOffset, CTransaction txPrev, COutPoint prevout, uint nTimeTx, ref uint256 hashProofOfStake, ref uint256 targetProofOfStake)
+        public static bool CheckStakeKernelHash(uint nBits, uint256 hashBlockFrom, uint nTimeBlockFrom, uint nTxPrevOffset, CTransaction txPrev, COutPoint prevout, uint nTimeTx, out uint256 hashProofOfStake, out uint256 targetProofOfStake)
         {
+            hashProofOfStake = targetProofOfStake = 0;
+
             if (nTimeTx < txPrev.nTime)
             {
                 return false; // Transaction timestamp violation
@@ -359,10 +364,10 @@ namespace Novacoin
             targetProofOfStake = nCoinDayWeight * nTargetPerCoinDay;
 
             // Calculate hash
-            long nStakeModifier = 0;
-            uint nStakeModifierHeight = 0;
-            uint nStakeModifierTime = 0;
-            if (!GetKernelStakeModifier(hashBlockFrom, ref nStakeModifier, ref nStakeModifierHeight, ref nStakeModifierTime))
+            long nStakeModifier;
+            uint nStakeModifierTime;
+            uint nStakeModifierHeight;
+            if (!GetKernelStakeModifier(hashBlockFrom, out nStakeModifier, out nStakeModifierHeight, out nStakeModifierTime))
             {
                 return false;
             }
@@ -399,9 +404,9 @@ namespace Novacoin
             return Math.Min(nIntervalEnd - nIntervalBeginning - nStakeMinAge, nStakeMaxAge);
         }
 
-        internal static uint GetStakeModifierChecksum(CBlockStoreItem itemTemplate)
+        internal static uint GetStakeModifierChecksum(ref CBlockStoreItem itemTemplate)
         {
-            Contract.Assert(itemTemplate.prev != null || (uint256)itemTemplate.Hash == NetUtils.nHashGenesisBlock);
+            Contract.Assert(itemTemplate.prev != null || (uint256)itemTemplate.Hash == NetInfo.nHashGenesisBlock);
 
             // Hash previous checksum with flags, hashProofOfStake and nStakeModifier
             MemoryStream ss = new MemoryStream();
@@ -432,8 +437,10 @@ namespace Novacoin
             return (uint)hashChecksum.Low64;
         }
 
-        internal static bool CheckProofOfStake(CTransaction tx, uint nBits, ref uint256 hashProofOfStake, ref uint256 targetProofOfStake)
+        public static bool CheckProofOfStake(CTransaction tx, uint nBits, out uint256 hashProofOfStake, out uint256 targetProofOfStake)
         {
+            hashProofOfStake = targetProofOfStake = 0;
+
             if (!tx.IsCoinStake)
             {
                 return false; // called on non-coinstake
@@ -443,17 +450,40 @@ namespace Novacoin
             CTxIn txin = tx.vin[0];
 
             // Read block header
-            
-            CBlock block = null;
-            CTransaction txPrev = null;
-            long nBlockPos = 0, nTxPos = 0;
-            
-            if (!CBlockStore.Instance.GetByTransactionID(txin.prevout.hash, ref block, ref txPrev, ref nBlockPos, ref nTxPos))
+
+            long nBlockPos;
+            CBlock block;
+            if (!CBlockStore.Instance.GetBlockByTransactionID(txin.prevout.hash, out block, out nBlockPos))
             {
                 return false; // unable to read block of previous transaction
             }
 
-            if (!CheckStakeKernelHash(nBits, block.header.Hash, block.header.nTime, (uint)(nTxPos - nBlockPos), txPrev, txin.prevout, tx.nTime, ref hashProofOfStake, ref targetProofOfStake))
+            long nTxPos = 0;
+            CTransaction txPrev = null;
+
+            // Iterate through vtx array
+            for (var i = 0; i < block.vtx.Length; i++)
+            {
+                if (block.vtx[i].Hash == txin.prevout.hash)
+                {
+                    txPrev = block.vtx[i];
+                    nTxPos = nBlockPos + block.GetTxOffset(i);
+
+                    break;
+                }
+            }
+
+            if (txPrev == null)
+            {
+                return false; // No such transaction found in the block
+            }
+
+            if (!ScriptCode.VerifyScript(txin.scriptSig, txPrev.vout[txin.prevout.n].scriptPubKey, tx, 0, (int)scriptflag.SCRIPT_VERIFY_P2SH, 0))
+            {
+                return false; // vin[0] signature check failed
+            }
+
+            if (!CheckStakeKernelHash(nBits, block.header.Hash, block.header.nTime, (uint)(nTxPos - nBlockPos), txPrev, txin.prevout, tx.nTime, out hashProofOfStake, out targetProofOfStake))
             {
                 return false; // check kernel failed on coinstake 
             }