Replace kernel scanning function with more usable implementation.
[novacoin.git] / src / kernel.cpp
index a3ec598..12b26aa 100644 (file)
@@ -509,35 +509,24 @@ bool ScanForStakeKernelHash(MetaMap &mapMeta, uint32_t nBits, uint32_t nTime, ui
     return false;
 }
 
-// Scan given input for kernel solution
-bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits, uint32_t nSearchInterval, std::pair<uint256, uint32_t> &solution)
+// Precompute hashing state for static part of kernel
+void GetKernelMidstate(uint64_t nStakeModifier, uint32_t nBlockTime, uint32_t nTxOffset, uint32_t nInputTxTime, uint32_t nOut, SHA256_CTX &ctx)
 {
-    CTxDB txdb("r");
-
-    CBlock block;
-    CTxIndex txindex;
-
-    // Load transaction index item
-    if (!txdb.ReadTxIndex(tx.GetHash(), txindex))
-        return false;
-
-    // Read block header
-    if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
-        return false;
-
-    uint64_t nStakeModifier = 0;
-    if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier))
-        return false;
-
-    uint32_t nTime = GetTime();
-    // Only count coins meeting min age requirement
-    if (nStakeMinAge + block.nTime > nTime)
-        nTime += (nStakeMinAge + block.nTime - nTime);
+    // Build static part of kernel
+    CDataStream ssKernel(SER_GETHASH, 0);
+    ssKernel << nStakeModifier;
+    ssKernel << nBlockTime << nTxOffset << nInputTxTime << nOut;
+    CDataStream::const_iterator it = ssKernel.begin();
 
-    // Transaction offset inside block
-    uint32_t nTxOffset = txindex.pos.nTxPos - txindex.pos.nBlockPos;
-    int64_t nValueIn = tx.vout[nOut].nValue;
+    // Init sha256 context and update it 
+    //   with first 24 bytes of kernel
+    SHA256_Init(&ctx);
+    SHA256_Update(&ctx, (unsigned char*)&it[0], 8 + 16);
+}
 
+// Scan given midstate for solution
+bool ScanMidstateForward(SHA256_CTX &ctx, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair<uint32_t, uint32_t> &SearchInterval, std::pair<uint256, uint32_t> &solution)
+{
     CBigNum bnTargetPerCoinDay;
     bnTargetPerCoinDay.SetCompact(nBits);
 
@@ -545,31 +534,19 @@ bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits
     CBigNum bnMaxTargetPerCoinDay = bnTargetPerCoinDay * CBigNum(nValueIn) * nStakeMaxAge / COIN / (24 * 60 * 60);
     uint256 maxTarget = bnMaxTargetPerCoinDay.getuint256();
 
-
-    // Build static part of kernel
-    CDataStream ssKernel(SER_GETHASH, 0);
-    ssKernel << nStakeModifier;
-    ssKernel << block.nTime << nTxOffset << tx.nTime << nOut;
-    CDataStream::const_iterator it = ssKernel.begin();
-
-    // Init sha256 context and update it 
-    //   with first 16 bytes of kernel
-    SHA256_CTX ctxCurrent;
-    SHA256_Init(&ctxCurrent);
-    SHA256_Update(&ctxCurrent, (unsigned char*)&it[0], 8 + 16);
-    SHA256_CTX ctxCopy = ctxCurrent;
+    SHA256_CTX ctxCopy = ctx;
 
     // Search forward in time from the given timestamp
     // Stopping search in case of shutting down
-    for (uint32_t nTimeTx=nTime; nTimeTx<nTime+nSearchInterval && !fShutdown; nTimeTx++)
+    for (uint32_t nTimeTx=SearchInterval.first; nTimeTx<SearchInterval.second && !fShutdown; nTimeTx++)
     {
         // Complete first hashing iteration
         uint256 hash1;
-        SHA256_Update(&ctxCurrent, (unsigned char*)&nTimeTx, 4);
-        SHA256_Final((unsigned char*)&hash1, &ctxCurrent);
+        SHA256_Update(&ctxCopy, (unsigned char*)&nTimeTx, 4);
+        SHA256_Final((unsigned char*)&hash1, &ctxCopy);
 
-        // Restore old context
-        ctxCurrent = ctxCopy;
+        // Restore context
+        ctxCopy = ctx;
 
         // Finally, calculate kernel hash
         uint256 hashProofOfStake;
@@ -579,7 +556,7 @@ bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits
         if (hashProofOfStake > maxTarget)
             continue;
 
-        CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)tx.nTime, (int64_t)nTimeTx) / COIN / (24 * 60 * 60);
+        CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / (24 * 60 * 60);
         CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay;
 
         if (bnTargetProofOfStake >= CBigNum(hashProofOfStake))