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);
            }
        }
        /// <summary>
        /// Represents the main entry point in the command line tool.
        /// </summary>
        /// <param name="args">
        /// Contains the command line arguments.
        /// For a complete description of the command line arguments see method TypeHelpPage.
        /// </param>
        /// <returns>
        /// 0 - Success.
        /// 1 - Error.
        /// </returns>
        private static int Main(string[] args)
        {
            int result = 1; // Assume error.

            try
            {
                ParameterParser <DatabaseGeneratorParameters> parameterParser = new ParameterParser <DatabaseGeneratorParameters>(DatabaseGeneratorParameters.ParameterListRules);
                DatabaseGeneratorParameters parameters = parameterParser.ParseParameters(args);

                if (parameters.IsHelpSpecified)
                {
                    TypeHelpPage();
                    result = 0; // Success.
                }
                else
                {
                    Console.WriteLine(GetApplicationNameAndVersion());

                    if (parameters.IsShowDbSchemaSpecified)
                    {
                        TypeDbSchema();
                        result = 0; // Success.
                    }
                    else if (parameters.IsRunValidationSpecified)
                    {
                        AutoValidator autoValidator = new AutoValidator(
                            parameters.SqlServerName,
                            parameters.SqlDbName,
                            parameters.SqlUserName,
                            parameters.SqlPassword);

                        result = autoValidator.Validate() ? 0 : 1;
                    }
                    else
                    {
                        Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Active threads: {0}", parameters.Threads));
                        Console.WriteLine();

                        DatabaseConnection databaseConnection = DatabaseConnection.CreateSqlServerConnection(parameters.SqlServerName, parameters.SqlDbName, parameters.SqlUserName, parameters.SqlPassword);
                        DatabaseGenerator  databaseGenerator  = new DatabaseGenerator(parameters, databaseConnection);
                        databaseGenerator.GenerateAndPopulateDatabase().Wait();

                        result = 0; // Success.
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }

            Console.WriteLine();
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
            //// TypePeakMemoryUsage();

            return(result);
        }
        static int Main(string[] args)
        {
            int result = 1; // Assume error.

            try
            {
                ParameterParser <DatabaseGeneratorParameters> parameterParser = new ParameterParser <DatabaseGeneratorParameters>(DatabaseGeneratorParameters.ParameterListRules);
                DatabaseGeneratorParameters parameters = parameterParser.ParseParameters(args);

                if (parameters.IsHelpSpecified)
                {
                    TypeHelpPage();
                    result = 0; // Success.
                }
                else
                {
                    Console.WriteLine(GetApplicationNameAndVersion());

                    if (parameters.IsShowDbSchemaSpecified)
                    {
                        TypeDbSchema();
                        result = 0; // Success.
                    }
                    else
                    {
                        Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Active threads: {0}", parameters.Threads));
                        Console.WriteLine();

                        DatabaseConnection databaseConnection = DatabaseConnection.CreateSqlServerConnection(parameters.SqlServerName, parameters.SqlDbName, parameters.SqlUserName, parameters.SqlPassword);
                        DatabaseGenerator  databaseGenerator  = new DatabaseGenerator(parameters, databaseConnection);
                        databaseGenerator.GenerateAndPopulateDatabase().Wait();

                        //一般情况下,只是调用GenerateAndPopulateDatabase(),将数据存入数据库,
                        //但有时为了做图方便及其他,为每个TX_IN直接添加对应的SourceTranceactionId,则
                        //把UpdateSourceTransactionId()的注释删除。为建立索引,如果数据库已经建好的,一定要
                        //把GenerateAndPopulateDatabase()注释掉,否则会浪费很多时间。
                        //同理UpdateTransactionOutputAddressId()函数是为每个TXOUT的比特币地址设置一个ID值,相同的ADDR具有相同的ID
                        //选择性调用

                        //databaseGenerator.UpdateSourceTransactionId();
                        //databaseGenerator.UpdateTransactionOutputAddressId();

                        result = 0; // Success.
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }

            Console.WriteLine();

            //// TypePeakMemoryUsage();

            return(result);
        }
        /// <summary>
        /// Represents the main entry point in the command line tool.
        /// </summary>
        /// <param name="args">
        /// Contains the command line arguments.
        /// For a complete description of the command line arguments see method TypeHelpPage.
        /// </param>
        /// <returns>
        /// 0 - Success.
        /// 1 - Error.
        /// </returns>
        private static int Main(string[] args)
        {
            int result = 1; // Assume error.

            try
            {
                ParameterParser<DatabaseGeneratorParameters> parameterParser = new ParameterParser<DatabaseGeneratorParameters>(DatabaseGeneratorParameters.ParameterListRules);
                DatabaseGeneratorParameters parameters = parameterParser.ParseParameters(args);

                if (parameters.IsHelpSpecified)
                {
                    TypeHelpPage();
                    result = 0; // Success.
                }
                else
                {
                    Console.WriteLine(GetApplicationNameAndVersion());

                    if (parameters.IsShowDbSchemaSpecified)
                    {
                        TypeDbSchema();
                        result = 0; // Success.
                    }
                    else if (parameters.IsRunValidationSpecified)
                    {
                        AutoValidator autoValidator = new AutoValidator(
                            parameters.SqlServerName,
                            parameters.SqlDbName,
                            parameters.SqlUserName,
                            parameters.SqlPassword);

                        result = autoValidator.Validate() ? 0 : 1;
                    }
                    else
                    {
                        Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Active threads: {0}", parameters.Threads));
                        Console.WriteLine();

                        DatabaseConnection databaseConnection = DatabaseConnection.CreateSqlServerConnection(parameters.SqlServerName, parameters.SqlDbName, parameters.SqlUserName, parameters.SqlPassword);
                        DatabaseGenerator databaseGenerator = new DatabaseGenerator(parameters, databaseConnection);
                        databaseGenerator.GenerateAndPopulateDatabase().Wait();

                        result = 0; // Success.
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }

            Console.WriteLine();

            //// TypePeakMemoryUsage();

            return result;
        }
        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);
            }
        }