public async Task <uint256> InsertMerkleProof()
        {
            var blockStream = await RpcClient.GetBlockAsStreamAsync(await RpcClient.GetBestBlockHashAsync());

            var firstBlock     = HelperTools.ParseByteStreamToBlock(blockStream);
            var block          = firstBlock.CreateNextBlockWithCoinbase(firstBlock.Transactions.First().Outputs.First().ScriptPubKey.GetDestinationPublicKeys().First(), new Money(50, MoneyUnit.MilliBTC), new ConsensusFactory());
            var firstBlockHash = firstBlock.GetHash();

            var tx = Transaction.Parse(Tx1Hex, Network.Main);

            block.AddTransaction(tx);
            tx = Transaction.Parse(Tx2Hex, Network.Main);
            block.AddTransaction(tx);
            tx = Transaction.Parse(Tx3Hex, Network.Main);
            block.AddTransaction(tx);
            tx = Transaction.Parse(Tx4Hex, Network.Main);
            block.AddTransaction(tx);
            tx = Transaction.Parse(Tx5Hex, Network.Main);
            block.AddTransaction(tx);

            rpcClientFactoryMock.AddKnownBlock((await RpcClient.GetBlockCountAsync()) + 1, block.ToBytes());
            var node      = NodeRepository.GetNodes().First();
            var rpcClient = rpcClientFactoryMock.Create(node.Host, node.Port, node.Username, node.Password);

            PublishBlockHashToEventBus(await rpcClient.GetBestBlockHashAsync());


            return(firstBlockHash);
        }
        private async Task <uint256> AddBlocks(bool dsCheckMempool)
        {
            long blockCount = await RpcClient.GetBlockCountAsync();

            var blockStream = await RpcClient.GetBlockAsStreamAsync(await RpcClient.GetBestBlockHashAsync());

            var firstBlock = HelperTools.ParseByteStreamToBlock(blockStream);

            rpcClientFactoryMock.AddKnownBlock(blockCount++, firstBlock.ToBytes());
            PublishBlockHashToEventBus(await RpcClient.GetBestBlockHashAsync());
            var firstBlockHash = firstBlock.GetHash();

            var pubKey = firstBlock.Transactions.First().Outputs.First().ScriptPubKey.GetDestinationPublicKeys().First();
            var block1 = firstBlock.CreateNextBlockWithCoinbase(pubKey, new Money(50, MoneyUnit.MilliBTC), new ConsensusFactory());

            var tx = Transaction.Parse(Tx1Hex, Network.Main);

            block1.AddTransaction(tx);
            block1.Check();
            long forkHeight = blockCount++;

            rpcClientFactoryMock.AddKnownBlock(forkHeight, block1.ToBytes());
            PublishBlockHashToEventBus(await RpcClient.GetBestBlockHashAsync());

            var block2 = block1.CreateNextBlockWithCoinbase(pubKey, new Money(50, MoneyUnit.MilliBTC), new ConsensusFactory());
            var tx2    = Transaction.Parse(Tx2Hex, Network.Main);

            block2.AddTransaction(tx2);
            block2.Check();
            rpcClientFactoryMock.AddKnownBlock(blockCount++, block2.ToBytes());
            PublishBlockHashToEventBus(await RpcClient.GetBestBlockHashAsync());

            if (dsCheckMempool)
            {
                // Use already inserted tx2, but change Version so we get new hash
                var nextBlock     = block1.CreateNextBlockWithCoinbase(pubKey, new Money(50, MoneyUnit.MilliBTC), new ConsensusFactory());
                var doubleSpendTx = Transaction.Parse(Tx2Hex, Network.Main);
                doubleSpendTx.Version = 2;
                doubleSpendTx.GetHash();
                nextBlock.AddTransaction(doubleSpendTx);
                nextBlock.Check();
                rpcClientFactoryMock.AddKnownBlock(forkHeight, nextBlock.ToBytes());
            }

            // check if created successfully
            await CheckBlockPresentInDbAsync(firstBlockHash);

            return(firstBlockHash);
        }
        public async Task TestBigBlocks(double txsCount)
        {
            var node      = NodeRepository.GetNodes().First();
            var rpcClient = rpcClientFactoryMock.Create(node.Host, node.Port, node.Username, node.Password);

            var stream  = new MemoryStream(Encoders.Hex.DecodeData(File.ReadAllText(@"Data/16mb_tx.txt")));
            var bStream = new BitcoinStream(stream, false)
            {
                MaxArraySize = unchecked ((int)uint.MaxValue)
            };
            var tx = Transaction.Create(Network.Main);

            tx.ReadWrite(bStream);

            var txId = tx.GetHash(int.MaxValue).ToString();

            _ = await CreateAndInsertTxAsync(false, true, 2, new string[] { txId.ToString() });

            List <Transaction> txs = new();

            for (int i = 0; i < txsCount; i++)
            {
                txs.Add(tx);
            }

            (_, string blockHash) = await CreateAndPublishNewBlockWithTxs(rpcClient, null, txs.ToArray(), true, true);

            var block = await TxRepositoryPostgres.GetBestBlockAsync();

            Assert.IsFalse(HelperTools.AreByteArraysEqual(block.BlockHash, new uint256(blockHash).ToBytes()));

            PublishBlockHashToEventBus(blockHash);

            WaitUntilEventBusIsIdle();

            block = await TxRepositoryPostgres.GetBestBlockAsync();

            Assert.IsTrue(HelperTools.AreByteArraysEqual(block.BlockHash, new uint256(blockHash).ToBytes()));
            Assert.AreEqual(0, (await TxRepositoryPostgres.GetUnparsedBlocksAsync()).Length);

            // check if block was correctly parsed
            var blockStream = await RpcClient.GetBlockAsStreamAsync(await RpcClient.GetBestBlockHashAsync());

            var parsedBlock = HelperTools.ParseByteStreamToBlock(blockStream);

            Assert.AreEqual(txsCount + 1, parsedBlock.Transactions.Count);
        }
        public async Task <(Transaction doubleSpendTx, Transaction originalTx, uint256 firstBlockHash)> InsertDoubleSpend()
        {
            var node      = NodeRepository.GetNodes().First();
            var rpcClient = (Mock.RpcClientMock)rpcClientFactoryMock.Create(node.Host, node.Port, node.Username, node.Password);

            long blockCount = await RpcClient.GetBlockCountAsync();

            var blockStream = await RpcClient.GetBlockAsStreamAsync(await RpcClient.GetBestBlockHashAsync());

            var firstBlock = HelperTools.ParseByteStreamToBlock(blockStream);

            rpcClientFactoryMock.AddKnownBlock(blockCount++, firstBlock.ToBytes());
            var firstBlockHash = firstBlock.GetHash();

            var tx = Transaction.Parse(Tx1Hex, Network.Main);

            var(forkHeight, _) = await CreateAndPublishNewBlock(rpcClient, null, tx, true);

            var tx2 = Transaction.Parse(Tx2Hex, Network.Main);

            await CreateAndPublishNewBlock(rpcClient, null, tx2, true);

            tx = Transaction.Parse(Tx3Hex, Network.Main);
            await CreateAndPublishNewBlock(rpcClient, null, tx, true);

            tx = Transaction.Parse(Tx4Hex, Network.Main);
            await CreateAndPublishNewBlock(rpcClient, null, tx, true);

            tx = Transaction.Parse(Tx5Hex, Network.Main);
            var(_, blockHash) = await CreateAndPublishNewBlock(rpcClient, null, tx, true);

            PublishBlockHashToEventBus(blockHash);

            // Use already inserted tx2 with changing only Version so we get new TxId
            var doubleSpendTx = Transaction.Parse(Tx2Hex, Network.Main);

            doubleSpendTx.Version = 2;
            doubleSpendTx.GetHash();
            await CreateAndPublishNewBlock(rpcClient, forkHeight, doubleSpendTx);

            return(doubleSpendTx, tx2, firstBlockHash);
        }
        public virtual async Task TestSkipParsing()
        {
            var node      = NodeRepository.GetNodes().First();
            var rpcClient = (Mock.RpcClientMock)rpcClientFactoryMock.Create(node.Host, node.Port, node.Username, node.Password);

            long blockCount = await RpcClient.GetBlockCountAsync();

            var blockStream = await RpcClient.GetBlockAsStreamAsync(await RpcClient.GetBestBlockHashAsync());

            var firstBlock = HelperTools.ParseByteStreamToBlock(blockStream);

            rpcClientFactoryMock.AddKnownBlock(blockCount++, firstBlock.ToBytes());

            var tx = Transaction.Parse(Tx1Hex, Network.Main);

            await CreateAndPublishNewBlock(rpcClient, null, tx, true);

            Assert.AreEqual(0, (await TxRepositoryPostgres.GetUnparsedBlocksAsync()).Length);

            var block = await TxRepositoryPostgres.GetBestBlockAsync();

            // we publish same NewBlockAvailableInDB as before
            var block2Parse = block;

            EventBus.Publish(new NewBlockAvailableInDB
            {
                BlockDBInternalId = block2Parse.BlockInternalId,
                BlockHash         = new uint256(block2Parse.BlockHash).ToString()
            });

            WaitUntilEventBusIsIdle();

            // best block must stay the same, since parsing was skipped
            var blockAfterRepublish = await TxRepositoryPostgres.GetBestBlockAsync();

            Assert.AreEqual(block.BlockInternalId, blockAfterRepublish.BlockInternalId);
            Assert.AreEqual(block.ParsedForMerkleAt, blockAfterRepublish.ParsedForMerkleAt);
            Assert.AreEqual(block.ParsedForDSAt, blockAfterRepublish.ParsedForDSAt);
        }
Example #6
0
        public async Task <(long, string)> CreateAndPublishNewBlockWithTxs(IRpcClient rpcClient, long?blockHeightToStartFork, Transaction[] transactions, bool noPublish = false, bool bigBlock = false)
        {
            string blockHash   = null;
            long   blockHeight = await rpcClient.GetBlockCountAsync();

            if (blockHeight == 0)
            {
                var blockStream = await rpcClient.GetBlockAsStreamAsync(await rpcClient.GetBestBlockHashAsync());

                var firstBlock = HelperTools.ParseByteStreamToBlock(blockStream);
                rpcClientFactoryMock.AddKnownBlock(blockHeight, firstBlock.ToBytes());
                PublishBlockHashToEventBus(await rpcClient.GetBestBlockHashAsync());
            }
            PubKey pubKey = new Key().PubKey;

            if (transactions != null)
            {
                NBitcoin.Block lastBlock;
                if (blockHeightToStartFork.HasValue)
                {
                    lastBlock = NBitcoin.Block.Load(await rpcClient.GetBlockByHeightAsBytesAsync(blockHeightToStartFork.Value), Network.Main);
                }
                else
                {
                    lastBlock = HelperTools.ParseByteStreamToBlock(await rpcClient.GetBlockAsStreamAsync(await rpcClient.GetBestBlockHashAsync()));
                }
                var block = lastBlock.CreateNextBlockWithCoinbase(pubKey, new Money(50, MoneyUnit.MilliBTC), new ConsensusFactory());
                foreach (var transaction in transactions)
                {
                    block.AddTransaction(transaction);
                }

                if (!bigBlock)
                {
                    block.Check();
                }

                if (blockHeightToStartFork.HasValue)
                {
                    blockHeight = blockHeightToStartFork.Value;
                }

                if (bigBlock)
                {
                    rpcClientFactoryMock.AddBigKnownBlock(++blockHeight, block);
                }
                else
                {
                    rpcClientFactoryMock.AddKnownBlock(++blockHeight, block.ToBytes());
                }


                blockHash = block.GetHash().ToString();
                if (!noPublish)
                {
                    PublishBlockHashToEventBus(block.GetHash().ToString());
                }
            }

            return(blockHeight, blockHash);
        }