private IEnumerable <Block> GetBlocksForSimpleScenario()
        {
            DataHelper dataHelper = new DataHelper();

            Block block1 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(1),
                transactionHash: SampleByteArray.GetSampleByteArray(1),
                input: new InputInfo(ByteArray.Empty, TransactionInput.OutputIndexNotUsed),
                output: new OutputInfo(50));

            Block block2 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(2),
                transactionHash: SampleByteArray.GetSampleByteArray(2),
                input: new InputInfo(block1.Transactions[0].TransactionHash, 0),
                output: new OutputInfo(49));

            return(new List <Block>()
            {
                block1,
                block2,
            });
        }
        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 IEnumerable <Block> GetBlocksForDuplicateTransactionHashScenario(ByteArray duplicateTransactionHash)
        {
            DataHelper dataHelper = new DataHelper();

            Block block1 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(1),
                transactionHash: SampleByteArray.GetSampleByteArray(1),
                input: new InputInfo(ByteArray.Empty, TransactionInput.OutputIndexNotUsed),
                output: new OutputInfo(10));

            Block block2 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(2),
                transactionHash: SampleByteArray.GetSampleByteArray(2),
                input: new InputInfo(ByteArray.Empty, TransactionInput.OutputIndexNotUsed),
                output: new OutputInfo(10));

            // The block that contains the first instance of a duplicate transaction hash.
            Block block3 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(3),
                transactionHash: duplicateTransactionHash,
                inputs: new InputInfo[] { new InputInfo(block1.Transactions[0].TransactionHash, 0) },
                outputs: new OutputInfo[] { new OutputInfo(3), new OutputInfo(7) });

            // This block spends the first output of the first transaction that has the duplicate hash.
            Block block4 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(4),
                transactionHash: SampleByteArray.GetSampleByteArray(4),
                input: new InputInfo(duplicateTransactionHash, 0),
                output: new OutputInfo(3));

            // The block that contains the second instance of a duplicate transaction hash.
            // Technically this makes the unspent outputs of the first transaction that has the same hash unspendable.
            Block block5 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(5),
                transactionHash: duplicateTransactionHash,
                inputs: new InputInfo[] { new InputInfo(block2.Transactions[0].TransactionHash, 0) },
                outputs: new OutputInfo[] { new OutputInfo(4), new OutputInfo(6) });

            // This block spends the second output of the second transaction that has the duplicate hash.
            Block block6 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(6),
                transactionHash: SampleByteArray.GetSampleByteArray(6),
                input: new InputInfo(duplicateTransactionHash, 1),
                output: new OutputInfo(6));

            Block block7 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(7),
                transactionHash: SampleByteArray.GetSampleByteArray(7),
                input: new InputInfo(ByteArray.Empty, TransactionInput.OutputIndexNotUsed),
                output: new OutputInfo(10));

            // The block that contains the third instance of a duplicate transaction hash.
            // Technically this makes the unspent outputs of the first two transaction that have the same hash unspendable.
            Block block8 = dataHelper.GenerateBlock(
                blockHash: SampleByteArray.GetSampleByteArray(8),
                transactionHash: duplicateTransactionHash,
                inputs: new InputInfo[] { new InputInfo(block7.Transactions[0].TransactionHash, 0) },
                outputs: new OutputInfo[] { new OutputInfo(2), new OutputInfo(8) });

            return(new List <Block>()
            {
                block1,
                block2,
                block3,
                block4,
                block5,
                block6,
                block7,
                block8,
            });
        }
Esempio n. 4
0
 private static byte[] MutateSample(int index, byte value) =>
 SampleByteArray.Select((b, i) => i == index ? value : b).ToArray();