public bool GetTxOutCursor(COutPoint outpoint, out TxOutItem txOutCursor) { var queryResults = dbConn.Query<TxOutItem>("select o.* from [Outputs] o left join [MerkleNodes] m on (m.nMerkleNodeID = o.nMerkleNodeID) where m.[TransactionHash] = ?", (byte[])outpoint.hash); if (queryResults.Count == 1) { txOutCursor = queryResults[0]; return true; } // Tx not found txOutCursor = null; return false; }
private bool ConnectBlock(CBlockStoreItem cursor, ref CBlock block, bool fJustCheck = false) { // Check it again in case a previous version let a bad block in, but skip BlockSig checking if (!block.CheckBlock(!fJustCheck, !fJustCheck, false)) { return false; // Invalid block found. } bool fScriptChecks = cursor.nHeight >= HashCheckpoints.TotalBlocksEstimate; var scriptFlags = scriptflag.SCRIPT_VERIFY_NOCACHE | scriptflag.SCRIPT_VERIFY_P2SH; long nFees = 0; long nValueIn = 0; long nValueOut = 0; uint nSigOps = 0; var queuedMerkleNodes = new Dictionary<uint256, CMerkleNode>(); var queuedOutputs = new Dictionary<COutPoint, TxOutItem>(); for (var nTx = 0; nTx < block.vtx.Length; nTx++) { var tx = block.vtx[nTx]; var hashTx = tx.Hash; if (!queuedMerkleNodes.ContainsKey(hashTx)) { var nTxPos = cursor.nBlockPos + block.GetTxOffset(nTx); var mNode = new CMerkleNode(cursor.ItemID, nTxPos, tx); queuedMerkleNodes.Add(hashTx, mNode); } Dictionary<COutPoint, TxOutItem> txouts; if (GetOutputs(hashTx, out txouts)) { // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. return false; } nSigOps += tx.LegacySigOpCount; if (nSigOps > CBlock.nMaxSigOps) { return false; // too many sigops } var inputs = new Dictionary<COutPoint, TxOutItem>(); if (tx.IsCoinBase) { nValueOut += tx.nValueOut; } else { bool Invalid; if (!FetchInputs(ref tx, ref queuedOutputs, ref inputs, true, out Invalid)) { return false; // Unable to fetch some inputs. } // Add in sigops done by pay-to-script-hash inputs; // this is to prevent a "rogue miner" from creating // an incredibly-expensive-to-validate block. nSigOps += tx.GetP2SHSigOpCount(ref inputs); if (nSigOps > CBlock.nMaxSigOps) { return false; // too many sigops } long nTxValueIn = tx.GetValueIn(ref inputs); long nTxValueOut = tx.nValueOut; nValueIn += nTxValueIn; nValueOut += nTxValueOut; if (!tx.IsCoinStake) { nFees += nTxValueIn - nTxValueOut; } if (!ConnectInputs(ref tx, ref inputs, ref queuedOutputs, ref cursor, true, fScriptChecks, scriptFlags)) { return false; } } for (var i = 0u; i < tx.vout.Length; i++) { var outKey = new COutPoint(hashTx, i); var outData = new TxOutItem() { nMerkleNodeID = -1, nValue = tx.vout[i].nValue, scriptPubKey = tx.vout[i].scriptPubKey, IsSpent = false, nOut = i }; queuedOutputs.Add(outKey, outData); } } if (!block.IsProofOfStake) { long nBlockReward = CBlock.GetProofOfWorkReward(cursor.nBits, nFees); // Check coinbase reward if (block.vtx[0].nValueOut > nBlockReward) { return false; // coinbase reward exceeded } } cursor.nMint = nValueOut - nValueIn + nFees; cursor.nMoneySupply = (cursor.prev != null ? cursor.prev.nMoneySupply : 0) + nValueOut - nValueIn; if (!UpdateDBCursor(ref cursor)) { return false; // Unable to commit changes } if (fJustCheck) { return true; } // Flush merkle nodes. var savedMerkleNodes = new Dictionary<uint256, CMerkleNode>(); foreach (var merklePair in queuedMerkleNodes) { var merkleNode = merklePair.Value; if (!SaveMerkleNode(ref merkleNode)) { // Unable to save merkle tree cursor. return false; } savedMerkleNodes.Add(merklePair.Key, merkleNode); } // Write queued transaction changes var newOutpointItems = new List<TxOutItem>(); var updatedOutpointItems = new List<TxOutItem>(); foreach (var outPair in queuedOutputs) { var outItem = outPair.Value; if (outItem.nMerkleNodeID == -1) { // This outpoint doesn't exist yet, adding to insert list. outItem.nMerkleNodeID = savedMerkleNodes[outPair.Key.hash].nMerkleNodeID; newOutpointItems.Add(outItem); } else { // This outpount already exists, adding to update list. updatedOutpointItems.Add(outItem); } } if (updatedOutpointItems.Count != 0 && !UpdateOutpoints(ref updatedOutpointItems)) { return false; // Unable to update outpoints } if (newOutpointItems.Count != 0 && !InsertOutpoints(ref newOutpointItems)) { return false; // Unable to insert outpoints } return true; }
/// <summary> /// Get merkle node cursor by output metadata. /// </summary> /// <param name="item">Output metadata object</param> /// <returns>Merkle node cursor or null</returns> public CMerkleNode GetMerkleCursor(TxOutItem item, out CBlockStoreItem blockCursor) { blockCursor = null; // Trying to get cursor from the database. var QueryMerkleCursor = dbConn.Query<CMerkleNode>("select * from [MerkleNodes] where [nMerkleNodeID] = ?", item.nMerkleNodeID); if (QueryMerkleCursor.Count == 1) { var merkleNode = QueryMerkleCursor[0]; // Search for block var results = blockMap.Where(x => x.Value.ItemID == merkleNode.nParentBlockID).Select(x => x.Value).ToArray(); blockCursor = results[0]; return merkleNode; } // Nothing found. return null; }