private void QueryBlockTest_ShouldSetReward()
        {
            // test case: set block reward based on pool output value.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _poolConfig.Wallet.Adress.Returns("POOL_ADDRESS");

            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Tx = new List<string> { "TX_HASH" } });
            _daemonClient.GetTransaction("TX_HASH").Returns(info => new Transaction
            {
                Details = new List<TransactionDetail> { new TransactionDetail { Address = "POOL_ADDRESS", Amount = 999 } }
            });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block reward should be set to 999
            block.Reward.Should().Equal((decimal)999);
        }
        private void QueryBlockTest_WithGeneratePoolOutputCategory_ShouldGetConfirmed()
        {
            // test case: we supply a pending block which should stay as pending as pool output category is still 'immature'.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _poolConfig.Wallet.Adress.Returns("POOL_ADDRESS");

            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Tx = new List<string> { "TX_HASH" } });
            _daemonClient.GetTransaction("TX_HASH").Returns(info => new Transaction
            {
                Details = new List<TransactionDetail> { new TransactionDetail { Address = "POOL_ADDRESS", Category = "generate" } }
            });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should still stay as pending
            block.Status.Should().Equal(BlockStatus.Confirmed);
        }
        private void QueryBlockTest_WithNonExistingPoolOutput_ShouldBeOrphaned()
        {
            // test case: generation transaction doesn't contain an output for the pool.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Tx = new List<string> { "TX_HASH" } });
            _daemonClient.GetTransaction("TX_HASH").Returns(info => new Transaction());

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should be marked as orphaned.
            block.Status.Should().Equal(BlockStatus.Orphaned);
        }
        private void QueryBlockTest_WithNonExistingGenerationTransaction_ShouldBeOrphaned()
        {
            // test case: coin reports generation transaction hash as invalid.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Tx = new List<string> { "TX_HASH" } });

            _daemonClient.GetTransaction("TX_HASH").Returns(x =>
            {
                throw new RpcErrorException(new RpcErrorResponse
                {
                    Error = new RpcError
                    {
                        Code = -5 // 'Invalid or non-wallet transaction id'
                    }
                });
            });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should be marked as orphaned.
            block.Status.Should().Equal(BlockStatus.Orphaned);
        }
        private void QueryBlockTest_WithNegativeConfirmations_ShouldBeOrphaned()
        {
            // test case: coin daemon returns block-info with negative confirmations.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Confirmations = -1 });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should be marked as orphaned.
            block.Status.Should().Equal(BlockStatus.Orphaned);
        }
        private void QueryBlockTest_WithInvalidTransactionHash_ShouldBeOrphaned()
        {
            // test case: coin daemon reports a different tx-hash then the one in block.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Tx = new List<string> { "DIFFERENT" } });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should be marked as orphaned.
            block.Status.Should().Equal(BlockStatus.Orphaned);
        }
        private void QueryBlockTest_WithInvalidBlockHash_ShouldBeOrphaned()
        {
            // test case: coin daemon reports block hash as invalid.
            var block = new PersistedBlock(1, false, false, false, "INVALID_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _daemonClient.GetBlock("INVALID_HASH").Returns(x =>
            {
                throw new RpcErrorException(new RpcErrorResponse
                {
                    Error = new RpcError
                    {
                        Code = -5 // 'block not found'.
                    }
                });
            });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should be marked as orphaned.
            block.Status.Should().Equal(BlockStatus.Orphaned);
        }
        private void QueryBlockTest_WithIncorrectPoolOutputAddress_ShouldBeOrphaned()
        {
            // test case: generation transaction output doesn't match pool output address.
            var block = new PersistedBlock(1, false, false, false, "BLOCK_HASH", "TX_HASH", 0, 0, DateTime.Now);
            _poolConfig.Wallet.Adress.Returns("POOL_ADDRESS");

            _daemonClient.GetBlock("BLOCK_HASH").Returns(info => new Block { Tx = new List<string> { "TX_HASH" } });
            _daemonClient.GetTransaction("TX_HASH").Returns(info => new Transaction
            {
                Details = new List<TransactionDetail> { new TransactionDetail { Address = "DIFFERENT_ADDRESS" } }
            });

            // query the block.
            var exposed = Exposed.From(new BlockProcessor(_poolConfig, _daemonClient, _storageLayer));
            exposed.QueryBlock(block);

            // block should be marked as orphaned.
            block.Status.Should().Equal(BlockStatus.Orphaned);
        }