public TransactionOutput(
     long transactionOutputId,
     long bitcoinTransactionId,
     int outputIndex,
     decimal outputValueBtc,
     ByteArray outputScript)
     this.TransactionOutputId = transactionOutputId;
     this.BitcoinTransactionId = bitcoinTransactionId;
     this.OutputIndex = outputIndex;
     this.OutputValueBtc = outputValueBtc;
     this.OutputScript = outputScript;
 public TransactionInputSource(long transactionInputId, ByteArray sourceTransactionHash, int sourceTransactionOutputIndex)
     this.TransactionInputId = transactionInputId;
     this.SourceTransactionHash = sourceTransactionHash;
     this.SourceTransactionOutputIndex = sourceTransactionOutputIndex;
 public InputInfo(ByteArray sourceTransactionHash, uint sourceTransactionOutputIndex)
     this.SourceTransactionHash = sourceTransactionHash;
     this.SourceTransactionOutputIndex = sourceTransactionOutputIndex;
        private static List<long> GetStaleBlockIds(BitcoinDataLayer bitcoinDataLayer)
            SummaryBlockDataSet summaryBlockDataSet = bitcoinDataLayer.GetSummaryBlockDataSet();

            // KEY:     The 256-bit hash of the block
            // VALUE:   The summary block data as represented by an instance of DBData.SummaryBlockDataSet.BlockRow.
            Dictionary<ParserData.ByteArray, SummaryBlockDataSet.SummaryBlockRow> blockDictionary = summaryBlockDataSet.SummaryBlock.ToDictionary(
                b => new ParserData.ByteArray(b.BlockHash),
                b => b);

            SummaryBlockDataSet.SummaryBlockRow lastBlock = summaryBlockDataSet.SummaryBlock.OrderByDescending(b => b.BlockId).First();
            ParserData.ByteArray previousBlockHash = ParserData.ByteArray.Empty;
            ParserData.ByteArray currentBlockHash = new ParserData.ByteArray(lastBlock.BlockHash);

            // A hashset containing the IDs of all active blocks. Active as in not stale.
            HashSet<long> activeBlockIds = new HashSet<long>();

            // Loop through blocks starting from the last one and going from one block to the next as indicated by PreviousBlockHash.
            // Collect all the block IDs for the blocks that we go through in activeBlockIds.
            // After this loop, blocks that we did not loop through are stale blocks.
            while (currentBlockHash.IsZeroArray() == false)
                SummaryBlockDataSet.SummaryBlockRow summaryBlockRow;
                if (blockDictionary.TryGetValue(currentBlockHash, out summaryBlockRow))
                    // The current block was found in the list of blocks. 
                    previousBlockHash = currentBlockHash;
                    currentBlockHash = new ParserData.ByteArray(summaryBlockRow.PreviousBlockHash);
                    // The current block was not found in the list of blocks. 
                    // This should never happen for a valid blockchain content.
                    throw new InvalidBlockchainContentException(string.Format(CultureInfo.InvariantCulture, "Block with hash [{0}] makes a reference to an unknown block with hash: [{1}]", previousBlockHash, currentBlockHash));

            // At this point activeBlockIds  contains the IDs of all active blocks.
            // Parse the list of all blocks and collect those whose IDs are not in activeBlockIds.
            return (from sumaryBlockRow in summaryBlockDataSet.SummaryBlock
                    where activeBlockIds.Contains(sumaryBlockRow.BlockId) == false
                    select sumaryBlockRow.BlockId).ToList();