public async Task SimpleCaseTest()
        {
            FakeDatabaseGeneratorParameters parameters = new FakeDatabaseGeneratorParameters(true, FakeDatabaseGeneratorParameters.AutoThreads);
            DatabaseConnection databaseConnection      = DatabaseConnection.CreateLocalDbConnection(parameters.SqlDbName);

            DatabaseGenerator databaseGenerator = new DatabaseGenerator(
                parameters,
                databaseConnection,
                () => new FakeBlockchainParser(this.GetBlocksForSimpleScenario()));

            await databaseGenerator.GenerateAndPopulateDatabase();

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(databaseConnection.ConnectionString))
            {
                // ValidationBlockchainDataSet will give us the aggregate values per the entire blockchain.
                ValidationBlockchainDataSet validationBlockchainDataSet = bitcoinDataLayer.GetValidationBlockchainDataSet(100).DataSet;
                Assert.AreEqual(1, validationBlockchainDataSet.ValidationBlockchain.Count);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].BlockCount);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].TransactionCount);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].TransactionInputCount);
                Assert.AreEqual(50, validationBlockchainDataSet.ValidationBlockchain[0].TotalInputBtc);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].TransactionOutputCount);
                Assert.AreEqual(99, validationBlockchainDataSet.ValidationBlockchain[0].TotalOutputBtc);
                Assert.AreEqual(1, validationBlockchainDataSet.ValidationBlockchain[0].TransactionFeeBtc);
                Assert.AreEqual(49, validationBlockchainDataSet.ValidationBlockchain[0].TotalUnspentOutputBtc);

                // TODO: Implement the next part of the validation.
                // bitcoinDataLayer.GetValidationBlockchainFilesDataSet(100);
                // bitcoinDataLayer.GetValidationBlockSampleDataSet(100, 1);
                // bitcoinDataLayer.GetValidationTransactionSampleDataSet(100, 1);
                // bitcoinDataLayer.GetValidationTransactionInputSampleDataSet(100, 1);
                // bitcoinDataLayer.GetValidationTransactionOutputSampleDataSet(100, 1);
            }
        }
        private bool ValidateDataAgainstBaseline()
        {
            //// These are values we can use to produce validation baselines for a smaller sample.
            //// const int maxBlockchainFileId = 3;
            //// const int blockSampleRatio = 1000;
            //// const int transactionSampleRatio = 1000;
            //// const int transactionInputSampleRatio = 10000;
            //// const int transactionOutputSampleRatio = 10000;

            const int maxBlockchainFileId          = 340;
            const int blockSampleRatio             = 500;
            const int transactionSampleRatio       = 100000;
            const int transactionInputSampleRatio  = 200000;
            const int transactionOutputSampleRatio = 200000;

            bool validationResult;

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString, ValidationSqlCommandTimeout))
            {
                validationResult = ValidateDataSet("01_BlockchainData", () => bitcoinDataLayer.GetValidationBlockchainDataSet(maxBlockchainFileId));
                validationResult = ValidateDataSet("02_BlockchainFilesData", () => bitcoinDataLayer.GetValidationBlockchainFilesDataSet(maxBlockchainFileId)) && validationResult;
                validationResult = ValidateDataSet("03_BlockSampleData", () => bitcoinDataLayer.GetValidationBlockSampleDataSet(maxBlockchainFileId, blockSampleRatio)) && validationResult;
                validationResult = ValidateDataSet("04_TransactionSampleData", () => bitcoinDataLayer.GetValidationTransactionSampleDataSet(maxBlockchainFileId, transactionSampleRatio)) && validationResult;
                validationResult = ValidateDataSet("05_TransactionInputSampleData", () => bitcoinDataLayer.GetValidationTransactionInputSampleDataSet(maxBlockchainFileId, transactionInputSampleRatio)) && validationResult;
                validationResult = ValidateDataSet("06_TransactionOutputSampleData", () => bitcoinDataLayer.GetValidationTransactionOutputSampleDataSet(maxBlockchainFileId, transactionOutputSampleRatio)) && validationResult;
            }

            return(validationResult);
        }
        public async Task SimpleCaseTest()
        {
            FakeDatabaseGeneratorParameters parameters = new FakeDatabaseGeneratorParameters(true, FakeDatabaseGeneratorParameters.AutoThreads);
            DatabaseConnection databaseConnection = DatabaseConnection.CreateLocalDbConnection(parameters.SqlDbName);

            DatabaseGenerator databaseGenerator = new DatabaseGenerator(
                parameters,
                databaseConnection,
                () => new FakeBlockchainParser(this.GetBlocksForSimpleScenario()));

            await databaseGenerator.GenerateAndPopulateDatabase();

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(databaseConnection.ConnectionString))
            {
                // ValidationBlockchainDataSet will give us the aggregate values per the entire blockchain.
                ValidationBlockchainDataSet validationBlockchainDataSet = bitcoinDataLayer.GetValidationBlockchainDataSet(100).DataSet;
                Assert.AreEqual(1, validationBlockchainDataSet.ValidationBlockchain.Count);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].BlockCount);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].TransactionCount);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].TransactionInputCount);
                Assert.AreEqual(50, validationBlockchainDataSet.ValidationBlockchain[0].TotalInputBtc);
                Assert.AreEqual(2, validationBlockchainDataSet.ValidationBlockchain[0].TransactionOutputCount);
                Assert.AreEqual(99, validationBlockchainDataSet.ValidationBlockchain[0].TotalOutputBtc);
                Assert.AreEqual(1, validationBlockchainDataSet.ValidationBlockchain[0].TransactionFeeBtc);
                Assert.AreEqual(49, validationBlockchainDataSet.ValidationBlockchain[0].TotalUnspentOutputBtc);

                // TODO: Implement the next part of the validation.
                // bitcoinDataLayer.GetValidationBlockchainFilesDataSet(100);
                // bitcoinDataLayer.GetValidationBlockSampleDataSet(100, 1);
                // bitcoinDataLayer.GetValidationTransactionSampleDataSet(100, 1);
                // bitcoinDataLayer.GetValidationTransactionInputSampleDataSet(100, 1);
                // bitcoinDataLayer.GetValidationTransactionOutputSampleDataSet(100, 1);
            }
        }
示例#4
0
        public void UpdateSourceTransactionId()
        {
            const long maxBatchSize = 10000000;

            Stopwatch updateTransactionSourceOutputWatch = new Stopwatch();

            updateTransactionSourceOutputWatch.Start();

            Console.Write("Setting direct links: inputs to source outputs (this may take a long time)...");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString, BitcoinDataLayer.ExtendedDbCommandTimeout))
            {
                long rowsToUpdateCommand = bitcoinDataLayer.GetTransactionSourceRowsToUpdate();
                long batchSize           = rowsToUpdateCommand / 10;
                batchSize = batchSize >= 1 ? batchSize : 1;
                batchSize = batchSize <= maxBatchSize ? batchSize : maxBatchSize;

                long totalRowsUpdated = bitcoinDataLayer.UpdateNullTransactionSources();
                Console.Write("\rSetting direct links: inputs to source outputs (this may take a long time)... {0}%", 95 * totalRowsUpdated / rowsToUpdateCommand);

                int rowsUpdated;
                while ((rowsUpdated = bitcoinDataLayer.UpdateTransactionSourceBatch(batchSize)) > 0)
                {
                    totalRowsUpdated += rowsUpdated;
                    Console.Write("\rSetting direct links: inputs to source outputs (this may take a long time)... {0}%", 95 * totalRowsUpdated / rowsToUpdateCommand);
                }
                bitcoinDataLayer.FixupTransactionSourceIdForDuplicateTransactionHash();
            }
            updateTransactionSourceOutputWatch.Stop();

            Console.WriteLine("\rSetting direct links: inputs to source outputs completed in {0:0.000} seconds.          ", updateTransactionSourceOutputWatch.Elapsed.TotalSeconds);
        }
示例#5
0
 private bool IsDatabaseEmpty()
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         return(bitcoinDataLayer.IsDatabaseEmpty());
     }
 }
示例#6
0
 private string GetLastKnownBlockchainFileName()
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         return(bitcoinDataLayer.GetLastKnownBlockchainFileName());
     }
 }
示例#7
0
 /// <summary>
 /// Deletes asynchronously from the database all the information associated with the last blockchain file.
 /// </summary>
 /// <returns>
 /// A task representing the asynchronous operation.
 /// </returns>
 private async Task DeleteLastBlockchainFileAsync()
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         await bitcoinDataLayer.DeleteLastBlockchainFileAsync();
     }
 }
示例#8
0
 private void TransferTable(DataTable dataTable)
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         bitcoinDataLayer.BulkCopyTable(dataTable);
     }
 }
示例#9
0
 private void ProcessBlockchainFile(int blockFileId, string blockchainFileName)
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         bitcoinDataLayer.AddBlockchainFile(new DBData.BlockchainFile(blockFileId, blockchainFileName));
         this.processingStatistics.AddBlockchainFilesCount(1);
     }
 }
示例#10
0
        private void DisableAllHeavyIndexes()
        {
            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                bitcoinDataLayer.DisableAllHeavyIndexes();
            }

            Console.WriteLine("Database indexes were disabled.");
        }
示例#11
0
 public void UpdateTransactionOutputAddressId()
 {
     Console.WriteLine("Update addressID ing..., this will cost very long time!");
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString, 4 * BitcoinDataLayer.ExtendedDbCommandTimeout))
     {
         bitcoinDataLayer.UpdateTransactionOutputAddressId();
     }
     Console.WriteLine("AddressId Completed!");
 }
示例#12
0
        private DatabaseIdManager GetDatabaseIdManager()
        {
            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                int  blockFileId;
                long blockId;
                long bitcoinTransactionId;
                long transactionInputId;
                long transactionOutputId;

                bitcoinDataLayer.GetMaximumIdValues(out blockFileId, out blockId, out bitcoinTransactionId, out transactionInputId, out transactionOutputId);

                return(new DatabaseIdManager(blockFileId + 1, blockId + 1, bitcoinTransactionId + 1, transactionInputId + 1, transactionOutputId + 1));
            }
        }
示例#13
0
        private void RebuildAllHeavyIndexes()
        {
            Stopwatch rebuildDatabaseIndexesWatch = new Stopwatch();

            rebuildDatabaseIndexesWatch.Start();

            Console.Write("Rebuilding database indexes ");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString, BitcoinDataLayer.ExtendedDbCommandTimeout))
            {
                bitcoinDataLayer.RebuildAllHeavyIndexes(() => Console.Write("."));
            }

            rebuildDatabaseIndexesWatch.Stop();
            Console.WriteLine("\rDatabase indexes were rebuilt successfully in {0:0.000} seconds.", rebuildDatabaseIndexesWatch.Elapsed.TotalSeconds);
        }
示例#14
0
        private void ShrinkDatabase()
        {
            Stopwatch shrinkDatabaseWatch = new Stopwatch();

            shrinkDatabaseWatch.Start();

            Console.Write("Shrinking database files...");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                bitcoinDataLayer.ShrinkDatabase(this.parameters.SqlDbName);
            }

            shrinkDatabaseWatch.Stop();
            Console.WriteLine("\rShrinking database files completed in {0:0.000} seconds.", shrinkDatabaseWatch.Elapsed.TotalSeconds);
        }
示例#15
0
        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.
                    activeBlockIds.Add(summaryBlockRow.BlockId);
                    previousBlockHash = currentBlockHash;
                    currentBlockHash  = new ParserData.ByteArray(summaryBlockRow.PreviousBlockHash);
                }
                else
                {
                    // 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());
        }
示例#16
0
        private void DisplayDatabaseStatistics()
        {
            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                int blockchainFileCount;
                int blockCount;
                int transactionCount;
                int transactionInputCount;
                int transactionOutputCount;

                bitcoinDataLayer.GetDatabaseEntitiesCount(out blockchainFileCount, out blockCount, out transactionCount, out transactionInputCount, out transactionOutputCount);

                Console.WriteLine();
                Console.WriteLine("Database information:");
                Console.WriteLine();
                Console.WriteLine("                 Block Files: {0,14:n0}", blockchainFileCount);
                Console.WriteLine("                      Blocks: {0,14:n0}", blockCount);
                Console.WriteLine("                Transactions: {0,14:n0}", transactionCount);
                Console.WriteLine("          Transaction Inputs: {0,14:n0}", transactionInputCount);
                Console.WriteLine("         Transaction Outputs: {0,14:n0}", transactionOutputCount);
            }
        }
示例#17
0
        private void DeleteStaleBlocks()
        {
            Stopwatch deleteStaleBlocksWatch = new Stopwatch();

            deleteStaleBlocksWatch.Start();

            Console.Write("Searching for stale blocks in the database...");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                List <long> staleBlocksIds = GetStaleBlockIds(bitcoinDataLayer);

                if (staleBlocksIds.Count > 0)
                {
                    // Now delete all stale blocks
                    bitcoinDataLayer.DeleteBlocks(staleBlocksIds);

                    // Update the block IDs after deleting the stale blocks so that the block IDs are forming a consecutive sequence.
                    bitcoinDataLayer.CompactBlockIds(staleBlocksIds);
                }

                deleteStaleBlocksWatch.Stop();

                if (staleBlocksIds.Count == 0)
                {
                    Console.WriteLine("\rNo stale blocks were found. The search took {0:0.000} seconds.", deleteStaleBlocksWatch.Elapsed.TotalSeconds);
                }
                else
                {
                    string format = staleBlocksIds.Count == 1 ?
                                    "\rOne stale block was found and deleted in {1:0.000} seconds" :
                                    "\r{0} stale blocks were found and deleted in {1:0.000} seconds.";

                    Console.WriteLine(format, staleBlocksIds.Count, deleteStaleBlocksWatch.Elapsed.TotalSeconds);
                }
            }
        }
        private void ShrinkDatabase()
        {
            Stopwatch shrinkDatabaseWatch = new Stopwatch();
            shrinkDatabaseWatch.Start();

            Console.Write("Shrinking database files...");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                bitcoinDataLayer.ShrinkDatabase(this.parameters.SqlDbName);
            }

            shrinkDatabaseWatch.Stop();
            Console.WriteLine("\rShrinking database files completed in {0:0.000} seconds.", shrinkDatabaseWatch.Elapsed.TotalSeconds);
        }
        private void DisableAllHeavyIndexes()
        {
            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                bitcoinDataLayer.DisableAllHeavyIndexes();
            }

            Console.WriteLine("Database indexes were disabled.");
        }
 private bool IsDatabaseEmpty()
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         return bitcoinDataLayer.IsDatabaseEmpty();
     }
 }
        private void DisplayDatabaseStatistics()
        {
            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                int blockchainFileCount;
                int blockCount;
                int transactionCount;
                int transactionInputCount;
                int transactionOutputCount;

                bitcoinDataLayer.GetDatabaseEntitiesCount(out blockchainFileCount, out blockCount, out transactionCount, out transactionInputCount, out transactionOutputCount);

                Console.WriteLine();
                Console.WriteLine("Database information:");
                Console.WriteLine();
                Console.WriteLine("                 Block Files: {0,14:n0}", blockchainFileCount);
                Console.WriteLine("                      Blocks: {0,14:n0}", blockCount);
                Console.WriteLine("                Transactions: {0,14:n0}", transactionCount);
                Console.WriteLine("          Transaction Inputs: {0,14:n0}", transactionInputCount);
                Console.WriteLine("         Transaction Outputs: {0,14:n0}", transactionOutputCount);
            }
        }
        private void DeleteStaleBlocks()
        {
            Stopwatch deleteStaleBlocksWatch = new Stopwatch();
            deleteStaleBlocksWatch.Start();

            Console.Write("Searching for stale blocks in the database...");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                List<long> staleBlocksIds = GetStaleBlockIds(bitcoinDataLayer);

                if (staleBlocksIds.Count > 0)
                {
                    // Now delete all stale blocks
                    bitcoinDataLayer.DeleteBlocks(staleBlocksIds);

                    // Update the block IDs after deleting the stale blocks so that the block IDs are forming a consecutive sequence.
                    bitcoinDataLayer.CompactBlockIds(staleBlocksIds);
                }

                deleteStaleBlocksWatch.Stop();

                if (staleBlocksIds.Count == 0)
                {
                    Console.WriteLine("\rNo stale blocks were found. The search took {0:0.000} seconds.", deleteStaleBlocksWatch.Elapsed.TotalSeconds);
                }
                else
                {
                    string format = staleBlocksIds.Count == 1 ?
                        "\rOne stale block was found and deleted in {1:0.000} seconds" :
                        "\r{0} stale blocks were found and deleted in {1:0.000} seconds.";

                    Console.WriteLine(format, staleBlocksIds.Count, deleteStaleBlocksWatch.Elapsed.TotalSeconds);
                }
            }
        }
        private void UpdateTransactionSourceOutputId()
        {
            const long maxBatchSize = 10000000;

            Stopwatch updateTransactionSourceOutputWatch = new Stopwatch();
            updateTransactionSourceOutputWatch.Start();

            Console.Write("Setting direct links: inputs to source outputs...");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString, BitcoinDataLayer.ExtendedDbCommandTimeout))
            {
                long rowsToUpdateCommand = bitcoinDataLayer.GetTransactionSourceOutputRowsToUpdate();

                long batchSize = rowsToUpdateCommand / 10;
                batchSize = batchSize >= 1 ? batchSize : 1;
                batchSize = batchSize <= maxBatchSize ? batchSize : maxBatchSize;

                long totalRowsUpdated = bitcoinDataLayer.UpdateNullTransactionSources();
                Console.Write("\rSetting direct links: inputs to source outputs... {0}%", 95 * totalRowsUpdated / rowsToUpdateCommand);

                int rowsUpdated;
                while ((rowsUpdated = bitcoinDataLayer.UpdateTransactionSourceBatch(batchSize)) > 0)
                {
                    totalRowsUpdated += rowsUpdated;
                    Console.Write("\rSetting direct links: inputs to source outputs... {0}%", 95 * totalRowsUpdated / rowsToUpdateCommand);
                }

                bitcoinDataLayer.FixupTransactionSourceOutputIdForDuplicateTransactionHash();
            }

            updateTransactionSourceOutputWatch.Stop();

            Console.WriteLine("\rSetting direct links: inputs to source outputs completed in {0:0.000} seconds.", updateTransactionSourceOutputWatch.Elapsed.TotalSeconds);
        }
 /// <summary>
 /// Deletes asynchronously from the database all the information associated with the last blockchain file.
 /// </summary>
 /// <returns>
 /// A task representing the asynchronous operation.
 /// </returns>
 private async Task DeleteLastBlockchainFileAsync()
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         await bitcoinDataLayer.DeleteLastBlockchainFileAsync();
     }
 }
 private string GetLastKnownBlockchainFileName()
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         return bitcoinDataLayer.GetLastKnownBlockchainFileName();
     }
 }
        private DatabaseIdManager GetDatabaseIdManager()
        {
            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
            {
                int blockFileId;
                long blockId;
                long bitcoinTransactionId;
                long transactionInputId;
                long transactionOutputId;

                bitcoinDataLayer.GetMaximumIdValues(out blockFileId, out blockId, out bitcoinTransactionId, out transactionInputId, out transactionOutputId);

                return new DatabaseIdManager(blockFileId + 1, blockId + 1, bitcoinTransactionId + 1, transactionInputId + 1, transactionOutputId + 1);
            }
        }
 private void TransferTable(DataTable dataTable)
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         bitcoinDataLayer.BulkCopyTable(dataTable);
     }
 }
 private void ProcessBlockchainFile(int blockFileId, string blockchainFileName)
 {
     using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString))
     {
         bitcoinDataLayer.AddBlockchainFile(new DBData.BlockchainFile(blockFileId, blockchainFileName));
         this.processingStatistics.AddBlockchainFilesCount(1);
     }
 }
        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. 
                    activeBlockIds.Add(summaryBlockRow.BlockId);
                    previousBlockHash = currentBlockHash;
                    currentBlockHash = new ParserData.ByteArray(summaryBlockRow.PreviousBlockHash);
                }
                else
                {
                    // 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();
        }
        public async Task DuplicateTransactionHashTest()
        {
            ByteArray duplicateTransactionHash = SampleByteArray.GetSampleByteArray(100);

            FakeDatabaseGeneratorParameters parameters = new FakeDatabaseGeneratorParameters(true, 1);
            DatabaseConnection databaseConnection      = DatabaseConnection.CreateLocalDbConnection(parameters.SqlDbName);

            DatabaseGenerator databaseGenerator = new DatabaseGenerator(
                parameters,
                databaseConnection,
                () => new FakeBlockchainParser(this.GetBlocksForDuplicateTransactionHashScenario(duplicateTransactionHash)));

            await databaseGenerator.GenerateAndPopulateDatabase();

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(databaseConnection.ConnectionString))
            {
                // ValidationBlockchainDataSet will give us the aggregate values per the entire blockchain.
                ValidationBlockchainDataSet validationBlockchainDataSet = bitcoinDataLayer.GetValidationBlockchainDataSet(100).DataSet;
                Assert.AreEqual(1, validationBlockchainDataSet.ValidationBlockchain.Count);

                Assert.AreEqual(8, validationBlockchainDataSet.ValidationBlockchain[0].BlockCount);
                Assert.AreEqual(8, validationBlockchainDataSet.ValidationBlockchain[0].TransactionCount);
                Assert.AreEqual(8, validationBlockchainDataSet.ValidationBlockchain[0].TransactionInputCount);
                Assert.AreEqual(39, validationBlockchainDataSet.ValidationBlockchain[0].TotalInputBtc);
                Assert.AreEqual(11, validationBlockchainDataSet.ValidationBlockchain[0].TransactionOutputCount);
                Assert.AreEqual(69, validationBlockchainDataSet.ValidationBlockchain[0].TotalOutputBtc);
                Assert.AreEqual(0, validationBlockchainDataSet.ValidationBlockchain[0].TransactionFeeBtc);
                Assert.AreEqual(30, validationBlockchainDataSet.ValidationBlockchain[0].TotalUnspentOutputBtc);

                // ValidationBlockchainFilesDataSet will give us the aggregate values per block files.
                // In this setup we have one block per block file.
                ValidationBlockchainFilesDataSet validationBlockchainFilesDataSet = bitcoinDataLayer.GetValidationBlockchainFilesDataSet(100).DataSet;
                Assert.AreEqual(8, validationBlockchainFilesDataSet.ValidationBlockchainFiles.Count);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile0 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[0];
                Assert.AreEqual(0, blockchainFile0.BlockchainFileId);
                Assert.AreEqual("blk00000.dat", blockchainFile0.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile0.BlockCount);
                Assert.AreEqual(1, blockchainFile0.TransactionCount);
                Assert.AreEqual(1, blockchainFile0.TransactionInputCount);
                Assert.AreEqual(0, blockchainFile0.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile0.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile0.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile0.TransactionFeeBtc);
                Assert.AreEqual(0, blockchainFile0.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile1 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[1];
                Assert.AreEqual(1, blockchainFile1.BlockchainFileId);
                Assert.AreEqual("blk00001.dat", blockchainFile1.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile1.BlockCount);
                Assert.AreEqual(1, blockchainFile1.TransactionCount);
                Assert.AreEqual(1, blockchainFile1.TransactionInputCount);
                Assert.AreEqual(0, blockchainFile1.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile1.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile1.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile1.TransactionFeeBtc);
                Assert.AreEqual(0, blockchainFile1.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile2 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[2];
                Assert.AreEqual(2, blockchainFile2.BlockchainFileId);
                Assert.AreEqual("blk00002.dat", blockchainFile2.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile2.BlockCount);
                Assert.AreEqual(1, blockchainFile2.TransactionCount);
                Assert.AreEqual(1, blockchainFile2.TransactionInputCount);
                Assert.AreEqual(10, blockchainFile2.TotalInputBtc);
                Assert.AreEqual(2, blockchainFile2.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile2.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile2.TransactionFeeBtc);
                Assert.AreEqual(7, blockchainFile2.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile3 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[3];
                Assert.AreEqual(3, blockchainFile3.BlockchainFileId);
                Assert.AreEqual("blk00003.dat", blockchainFile3.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile3.BlockCount);
                Assert.AreEqual(1, blockchainFile3.TransactionCount);
                Assert.AreEqual(1, blockchainFile3.TransactionInputCount);
                Assert.AreEqual(3, blockchainFile3.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile3.TransactionOutputCount);
                Assert.AreEqual(3, blockchainFile3.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile3.TransactionFeeBtc);
                Assert.AreEqual(3, blockchainFile3.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile4 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[4];
                Assert.AreEqual(4, blockchainFile4.BlockchainFileId);
                Assert.AreEqual("blk00004.dat", blockchainFile4.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile4.BlockCount);
                Assert.AreEqual(1, blockchainFile4.TransactionCount);
                Assert.AreEqual(1, blockchainFile4.TransactionInputCount);
                Assert.AreEqual(10, blockchainFile4.TotalInputBtc);
                Assert.AreEqual(2, blockchainFile4.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile4.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile4.TransactionFeeBtc);
                Assert.AreEqual(4, blockchainFile4.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile5 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[5];
                Assert.AreEqual(5, blockchainFile5.BlockchainFileId);
                Assert.AreEqual("blk00005.dat", blockchainFile5.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile5.BlockCount);
                Assert.AreEqual(1, blockchainFile5.TransactionCount);
                Assert.AreEqual(1, blockchainFile5.TransactionInputCount);
                Assert.AreEqual(6, blockchainFile5.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile5.TransactionOutputCount);
                Assert.AreEqual(6, blockchainFile5.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile5.TransactionFeeBtc);
                Assert.AreEqual(6, blockchainFile5.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile6 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[6];
                Assert.AreEqual(6, blockchainFile6.BlockchainFileId);
                Assert.AreEqual("blk00006.dat", blockchainFile6.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile6.BlockCount);
                Assert.AreEqual(1, blockchainFile6.TransactionCount);
                Assert.AreEqual(1, blockchainFile6.TransactionInputCount);
                Assert.AreEqual(0, blockchainFile6.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile6.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile6.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile6.TransactionFeeBtc);
                Assert.AreEqual(0, blockchainFile6.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile7 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[7];
                Assert.AreEqual(7, blockchainFile7.BlockchainFileId);
                Assert.AreEqual("blk00007.dat", blockchainFile7.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile7.BlockCount);
                Assert.AreEqual(1, blockchainFile7.TransactionCount);
                Assert.AreEqual(1, blockchainFile7.TransactionInputCount);
                Assert.AreEqual(10, blockchainFile7.TotalInputBtc);
                Assert.AreEqual(2, blockchainFile7.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile7.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile7.TransactionFeeBtc);
                Assert.AreEqual(10, blockchainFile7.TotalUnspentOutputBtc);

                ValidationTransactionInputDataSet validationTransactionInputDataSet = bitcoinDataLayer.GetValidationTransactionInputSampleDataSet(100, 1).DataSet;
                Assert.AreEqual(8, validationTransactionInputDataSet.ValidationTransactionInput.Count);

                ValidationTransactionInputDataSet.ValidationTransactionInputRow transactionInput3 = validationTransactionInputDataSet.ValidationTransactionInput[3];
                Assert.AreEqual(3, transactionInput3.TransactionInputId);
                Assert.AreEqual(3, transactionInput3.BitcoinTransactionId);
                Assert.AreEqual(2, transactionInput3.SourceTransactionOutputId);
                Assert.AreEqual(3, transactionInput3.TransactionInputValueBtc);
                Assert.AreEqual(duplicateTransactionHash, new ByteArray(transactionInput3.SourceTransactionHash));
                Assert.AreEqual(0, transactionInput3.SourceTransactionOutputIndex);

                ValidationTransactionInputDataSet.ValidationTransactionInputRow transactionInput5 = validationTransactionInputDataSet.ValidationTransactionInput[5];
                Assert.AreEqual(5, transactionInput5.TransactionInputId);
                Assert.AreEqual(5, transactionInput5.BitcoinTransactionId);
                Assert.AreEqual(6, transactionInput5.SourceTransactionOutputId);
                Assert.AreEqual(6, transactionInput5.TransactionInputValueBtc);
                Assert.AreEqual(duplicateTransactionHash, new ByteArray(transactionInput5.SourceTransactionHash));
                Assert.AreEqual(1, transactionInput5.SourceTransactionOutputIndex);
            }
        }
        public async Task DuplicateTransactionHashTest()
        {
            ByteArray duplicateTransactionHash = SampleByteArray.GetSampleByteArray(100);

            FakeDatabaseGeneratorParameters parameters = new FakeDatabaseGeneratorParameters(true, 1);
            DatabaseConnection databaseConnection = DatabaseConnection.CreateLocalDbConnection(parameters.SqlDbName);

            DatabaseGenerator databaseGenerator = new DatabaseGenerator(
                parameters,
                databaseConnection,
                () => new FakeBlockchainParser(this.GetBlocksForDuplicateTransactionHashScenario(duplicateTransactionHash)));

            await databaseGenerator.GenerateAndPopulateDatabase();

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(databaseConnection.ConnectionString))
            {
                // ValidationBlockchainDataSet will give us the aggregate values per the entire blockchain.
                ValidationBlockchainDataSet validationBlockchainDataSet = bitcoinDataLayer.GetValidationBlockchainDataSet(100).DataSet;
                Assert.AreEqual(1, validationBlockchainDataSet.ValidationBlockchain.Count);

                Assert.AreEqual(8, validationBlockchainDataSet.ValidationBlockchain[0].BlockCount);
                Assert.AreEqual(8, validationBlockchainDataSet.ValidationBlockchain[0].TransactionCount);
                Assert.AreEqual(8, validationBlockchainDataSet.ValidationBlockchain[0].TransactionInputCount);
                Assert.AreEqual(39, validationBlockchainDataSet.ValidationBlockchain[0].TotalInputBtc);
                Assert.AreEqual(11, validationBlockchainDataSet.ValidationBlockchain[0].TransactionOutputCount);
                Assert.AreEqual(69, validationBlockchainDataSet.ValidationBlockchain[0].TotalOutputBtc);
                Assert.AreEqual(0, validationBlockchainDataSet.ValidationBlockchain[0].TransactionFeeBtc);
                Assert.AreEqual(30, validationBlockchainDataSet.ValidationBlockchain[0].TotalUnspentOutputBtc);

                // ValidationBlockchainFilesDataSet will give us the aggregate values per block files. 
                // In this setup we have one block per block file. 
                ValidationBlockchainFilesDataSet validationBlockchainFilesDataSet = bitcoinDataLayer.GetValidationBlockchainFilesDataSet(100).DataSet;
                Assert.AreEqual(8, validationBlockchainFilesDataSet.ValidationBlockchainFiles.Count);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile0 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[0];
                Assert.AreEqual(0, blockchainFile0.BlockchainFileId);
                Assert.AreEqual("blk00000.dat", blockchainFile0.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile0.BlockCount);
                Assert.AreEqual(1, blockchainFile0.TransactionCount);
                Assert.AreEqual(1, blockchainFile0.TransactionInputCount);
                Assert.AreEqual(0, blockchainFile0.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile0.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile0.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile0.TransactionFeeBtc);
                Assert.AreEqual(0, blockchainFile0.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile1 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[1];
                Assert.AreEqual(1, blockchainFile1.BlockchainFileId);
                Assert.AreEqual("blk00001.dat", blockchainFile1.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile1.BlockCount);
                Assert.AreEqual(1, blockchainFile1.TransactionCount);
                Assert.AreEqual(1, blockchainFile1.TransactionInputCount);
                Assert.AreEqual(0, blockchainFile1.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile1.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile1.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile1.TransactionFeeBtc);
                Assert.AreEqual(0, blockchainFile1.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile2 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[2];
                Assert.AreEqual(2, blockchainFile2.BlockchainFileId);
                Assert.AreEqual("blk00002.dat", blockchainFile2.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile2.BlockCount);
                Assert.AreEqual(1, blockchainFile2.TransactionCount);
                Assert.AreEqual(1, blockchainFile2.TransactionInputCount);
                Assert.AreEqual(10, blockchainFile2.TotalInputBtc);
                Assert.AreEqual(2, blockchainFile2.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile2.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile2.TransactionFeeBtc);
                Assert.AreEqual(7, blockchainFile2.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile3 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[3];
                Assert.AreEqual(3, blockchainFile3.BlockchainFileId);
                Assert.AreEqual("blk00003.dat", blockchainFile3.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile3.BlockCount);
                Assert.AreEqual(1, blockchainFile3.TransactionCount);
                Assert.AreEqual(1, blockchainFile3.TransactionInputCount);
                Assert.AreEqual(3, blockchainFile3.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile3.TransactionOutputCount);
                Assert.AreEqual(3, blockchainFile3.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile3.TransactionFeeBtc);
                Assert.AreEqual(3, blockchainFile3.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile4 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[4];
                Assert.AreEqual(4, blockchainFile4.BlockchainFileId);
                Assert.AreEqual("blk00004.dat", blockchainFile4.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile4.BlockCount);
                Assert.AreEqual(1, blockchainFile4.TransactionCount);
                Assert.AreEqual(1, blockchainFile4.TransactionInputCount);
                Assert.AreEqual(10, blockchainFile4.TotalInputBtc);
                Assert.AreEqual(2, blockchainFile4.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile4.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile4.TransactionFeeBtc);
                Assert.AreEqual(4, blockchainFile4.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile5 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[5];
                Assert.AreEqual(5, blockchainFile5.BlockchainFileId);
                Assert.AreEqual("blk00005.dat", blockchainFile5.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile5.BlockCount);
                Assert.AreEqual(1, blockchainFile5.TransactionCount);
                Assert.AreEqual(1, blockchainFile5.TransactionInputCount);
                Assert.AreEqual(6, blockchainFile5.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile5.TransactionOutputCount);
                Assert.AreEqual(6, blockchainFile5.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile5.TransactionFeeBtc);
                Assert.AreEqual(6, blockchainFile5.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile6 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[6];
                Assert.AreEqual(6, blockchainFile6.BlockchainFileId);
                Assert.AreEqual("blk00006.dat", blockchainFile6.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile6.BlockCount);
                Assert.AreEqual(1, blockchainFile6.TransactionCount);
                Assert.AreEqual(1, blockchainFile6.TransactionInputCount);
                Assert.AreEqual(0, blockchainFile6.TotalInputBtc);
                Assert.AreEqual(1, blockchainFile6.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile6.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile6.TransactionFeeBtc);
                Assert.AreEqual(0, blockchainFile6.TotalUnspentOutputBtc);

                ValidationBlockchainFilesDataSet.ValidationBlockchainFilesRow blockchainFile7 = validationBlockchainFilesDataSet.ValidationBlockchainFiles[7];
                Assert.AreEqual(7, blockchainFile7.BlockchainFileId);
                Assert.AreEqual("blk00007.dat", blockchainFile7.BlockchainFileName);
                Assert.AreEqual(1, blockchainFile7.BlockCount);
                Assert.AreEqual(1, blockchainFile7.TransactionCount);
                Assert.AreEqual(1, blockchainFile7.TransactionInputCount);
                Assert.AreEqual(10, blockchainFile7.TotalInputBtc);
                Assert.AreEqual(2, blockchainFile7.TransactionOutputCount);
                Assert.AreEqual(10, blockchainFile7.TotalOutputBtc);
                Assert.AreEqual(0, blockchainFile7.TransactionFeeBtc);
                Assert.AreEqual(10, blockchainFile7.TotalUnspentOutputBtc);

                ValidationTransactionInputDataSet validationTransactionInputDataSet = bitcoinDataLayer.GetValidationTransactionInputSampleDataSet(100, 1).DataSet;
                Assert.AreEqual(8, validationTransactionInputDataSet.ValidationTransactionInput.Count);

                ValidationTransactionInputDataSet.ValidationTransactionInputRow transactionInput3 = validationTransactionInputDataSet.ValidationTransactionInput[3];
                Assert.AreEqual(3, transactionInput3.TransactionInputId);
                Assert.AreEqual(3, transactionInput3.BitcoinTransactionId);
                Assert.AreEqual(2, transactionInput3.SourceTransactionOutputId);
                Assert.AreEqual(3, transactionInput3.TransactionInputValueBtc);
                Assert.AreEqual(duplicateTransactionHash, new ByteArray(transactionInput3.SourceTransactionHash));
                Assert.AreEqual(0, transactionInput3.SourceTransactionOutputIndex);

                ValidationTransactionInputDataSet.ValidationTransactionInputRow transactionInput5 = validationTransactionInputDataSet.ValidationTransactionInput[5];
                Assert.AreEqual(5, transactionInput5.TransactionInputId);
                Assert.AreEqual(5, transactionInput5.BitcoinTransactionId);
                Assert.AreEqual(6, transactionInput5.SourceTransactionOutputId);
                Assert.AreEqual(6, transactionInput5.TransactionInputValueBtc);
                Assert.AreEqual(duplicateTransactionHash, new ByteArray(transactionInput5.SourceTransactionHash));
                Assert.AreEqual(1, transactionInput5.SourceTransactionOutputIndex);
            }
        }
        private void RebuildAllHeavyIndexes()
        {
            Stopwatch rebuildDatabaseIndexesWatch = new Stopwatch();
            rebuildDatabaseIndexesWatch.Start();

            Console.Write("Rebuilding database indexes ");

            using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString, BitcoinDataLayer.ExtendedDbCommandTimeout))
            {
                bitcoinDataLayer.RebuildAllHeavyIndexes(() => Console.Write("."));
            }

            rebuildDatabaseIndexesWatch.Stop();
            Console.WriteLine("\rDatabase indexes were rebuilt successfully in {0:0.000} seconds.", rebuildDatabaseIndexesWatch.Elapsed.TotalSeconds);
        }