Save proof-of-stake kernel hash.
[NovacoinLibrary.git] / Novacoin / CBlockStore.cs
index f4342a2..f0c830f 100644 (file)
@@ -208,6 +208,9 @@ namespace Novacoin
 
                 // Load data about the top node.
                 ChainParams = dbConn.Table<ChainState>().First();
+
+                genesisBlockCursor = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] where [Hash] = ?", (byte[])NetInfo.nHashGenesisBlock).First();
+                bestBlockCursor = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] where [Hash] = ?", ChainParams.HashBestChain).First();
             }
         }
 
@@ -274,6 +277,11 @@ namespace Novacoin
                     {
                         var outPoint = txin.prevout;
 
+                        if (inputs.ContainsKey(outPoint))
+                        {
+                            continue; // We have already seen this input.
+                        }
+
                         if (!queued.ContainsKey(outPoint))
                         {
                             return false; // No such transaction
@@ -371,6 +379,7 @@ namespace Novacoin
 
                 itemTemplate.prevoutStake = block.vtx[1].vin[0].prevout;
                 itemTemplate.nStakeTime = block.vtx[1].nTime;
+                itemTemplate.hashProofOfStake = mapProofOfStake[blockHash];
             }
 
             if (!itemTemplate.WriteToFile(ref fStreamReadWrite, ref block))
@@ -467,6 +476,11 @@ namespace Novacoin
             nTimeBestReceived = Interop.GetTime();
             nTransactionsUpdated++;
 
+            if (!UpdateTopChain(cursor))
+            {
+                return false; // unable to set top chain node.
+            }
+
             return true;
         }
 
@@ -608,7 +622,13 @@ namespace Novacoin
             }
 
             // Add to current best branch
-            cursor.prev.next = cursor;
+            var prevCursor = cursor.prev;
+            prevCursor.next = cursor;
+
+            if (!UpdateDBCursor(ref prevCursor))
+            {
+                return false; // unable to update
+            }
 
             // Delete redundant memory transactions
             foreach (var tx in block.vtx)
@@ -836,10 +856,8 @@ namespace Novacoin
 
         private bool ConnectInputs(CTransaction tx, ref Dictionary<COutPoint, TxOutItem> inputs, ref Dictionary<COutPoint, TxOutItem> queued, ref CBlockStoreItem cursorBlock, bool fBlock, bool fScriptChecks, scriptflag scriptFlags)
         {
-            // Take over previous transactions' spent pointers
+            // Take over previous transactions' spent items
             // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
-            // fMiner is true when called from the internal bitcoin miner
-            // ... both are false when called from CTransaction::AcceptToMemoryPool
 
             if (!tx.IsCoinBase)
             {
@@ -852,26 +870,44 @@ namespace Novacoin
                     var input = inputs[prevout];
 
                     CBlockStoreItem parentBlockCursor;
-                    var merkleItem = GetMerkleCursor(input, out parentBlockCursor);
 
-                    if (merkleItem == null)
+                    if (input.nMerkleNodeID == -1)
                     {
-                        return false; // Unable to find merkle node
-                    }
+                        // This input seems as is confirmed by the same block.
 
-                    // If prev is coinbase or coinstake, check that it's matured
-                    if (merkleItem.IsCoinBase || merkleItem.IsCoinStake)
-                    {
-                        if (cursorBlock.nHeight - parentBlockCursor.nHeight < NetInfo.nGeneratedMaturity)
+                        if (!queued.ContainsKey(prevout))
                         {
-                            return false; // tried to spend non-matured generation input.
+                            return false; // No such output has been queued by this block.
                         }
-                    }
 
-                    // check transaction timestamp
-                    if (merkleItem.nTime > tx.nTime)
+                        // TODO: Ensure that neither coinbase nor coinstake outputs are 
+                        //    available for spending in the generation block.
+                    }
+                    else
                     {
-                        return false; // transaction timestamp earlier than input transaction
+                        // This input has been confirmed by one of the earlier accepted blocks.
+
+                        var merkleItem = GetMerkleCursor(input, out parentBlockCursor);
+
+                        if (merkleItem == null)
+                        {
+                            return false; // Unable to find merkle node
+                        }
+
+                        // If prev is coinbase or coinstake, check that it's matured
+                        if (merkleItem.IsCoinBase || merkleItem.IsCoinStake)
+                        {
+                            if (cursorBlock.nHeight - parentBlockCursor.nHeight < NetInfo.nGeneratedMaturity)
+                            {
+                                return false; // tried to spend non-matured generation input.
+                            }
+                        }
+
+                        // check transaction timestamp
+                        if (merkleItem.nTime > tx.nTime)
+                        {
+                            return false; // transaction timestamp earlier than input transaction
+                        }
                     }
 
                     // Check for negative or overflow input values
@@ -917,7 +953,16 @@ namespace Novacoin
                     // Write back
                     if (fBlock)
                     {
-                        queued.Add(prevout, input);
+                        if (input.nMerkleNodeID != -1)
+                        {
+                            // Input has been confirmed earlier.
+                            queued.Add(prevout, input);
+                        }
+                        else
+                        {
+                            // Input has been confirmed by current block.
+                            queued[prevout] = input;
+                        }
                     }
                 }
 
@@ -1078,14 +1123,19 @@ namespace Novacoin
         /// <param name="block">Block reference</param>
         /// <param name="nBlockPos">Block position reference</param>
         /// <returns>Result of operation</returns>
-        public bool GetBlockByTransactionID(uint256 TxID, ref CBlock block, ref long nBlockPos)
+        public bool GetBlockByTransactionID(uint256 TxID, out CBlock block, out long nBlockPos)
         {
+            block = null;
+            nBlockPos = -1;
+
             var queryResult = dbConn.Query<CBlockStoreItem>("select b.* from [BlockStorage] b left join [MerkleNodes] m on (b.[ItemID] = m.[nParentBlockID]) where m.[TransactionHash] = ?", (byte[])TxID);
 
             if (queryResult.Count == 1)
             {
                 CBlockStoreItem blockCursor = queryResult[0];
 
+                nBlockPos = blockCursor.nBlockPos;
+
                 return blockCursor.ReadFromFile(ref fStreamReadWrite, out block);
             }
 
@@ -1243,7 +1293,7 @@ namespace Novacoin
                 // TODO: proof-of-stake validation
 
                 uint256 hashProofOfStake = 0, targetProofOfStake = 0;
-                if (!StakeModifier.CheckProofOfStake(block.vtx[1], block.header.nBits, ref hashProofOfStake, ref targetProofOfStake))
+                if (!StakeModifier.CheckProofOfStake(block.vtx[1], block.header.nBits, out hashProofOfStake, out targetProofOfStake))
                 {
                     return false; // do not error here as we expect this during initial block download
                 }
@@ -1362,7 +1412,7 @@ namespace Novacoin
                 }
 
                 int nCount = blockMap.Count;
-                Console.WriteLine("nCount={0}, Hash={1}, Time={2}", nCount, block.header.Hash, DateTime.Now); // Commit on each 100th block
+                Console.WriteLine("nCount={0}, Hash={1}, NumTx={2}, Time={3}", nCount, block.header.Hash, block.vtx.Length, DateTime.Now); // Commit on each 100th block
 
                 /*
                 if (nCount % 100 == 0 && nCount != 0)