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 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); }
private bool IsDatabaseEmpty() { using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString)) { return(bitcoinDataLayer.IsDatabaseEmpty()); } }
private string GetLastKnownBlockchainFileName() { using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString)) { return(bitcoinDataLayer.GetLastKnownBlockchainFileName()); } }
/// <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 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 void DisableAllHeavyIndexes() { using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString)) { bitcoinDataLayer.DisableAllHeavyIndexes(); } Console.WriteLine("Database indexes were disabled."); }
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!"); }
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 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); }
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 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()); }
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 bool IsDatabaseEmpty() { using (BitcoinDataLayer bitcoinDataLayer = new BitcoinDataLayer(this.databaseConnection.ConnectionString)) { return bitcoinDataLayer.IsDatabaseEmpty(); } }
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); }
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 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); } }