예제 #1
0
        public void TestExceptionInLoadTxInput()
        {
            var expectedException = new Exception();

            var coreStorage = new Mock <ICoreStorage>();

            var chainedHeader = RandomData.RandomChainedHeader();
            var tx            = RandomData.RandomTransaction(new RandomDataOptions {
                TxInputCount = 1
            });
            var txLookupKey = new TxLookupKey(UInt256.Zero, 0);
            var inputTx     = RandomData.RandomTransaction();
            var loadingTx   = new LoadingTx(1, tx, chainedHeader, ImmutableArray.Create(txLookupKey));

            var loadingTxes = new BufferBlock <LoadingTx>();

            loadingTxes.Post(loadingTx);
            loadingTxes.Complete();

            // throw expected exception when the input transaction is looked up
            BlockTx outputTx = null;

            coreStorage.Setup(x => x.TryGetTransaction(txLookupKey.BlockHash, txLookupKey.TxIndex, out outputTx)).Throws(expectedException);

            var loadedTxes = TxLoader.LoadTxes(coreStorage.Object, loadingTxes);

            Exception actualEx;

            AssertMethods.AssertAggregateThrows <Exception>(() =>
                                                            loadedTxes.ToEnumerable().ToList(), out actualEx);
            Assert.AreSame(expectedException, actualEx);
        }
예제 #2
0
        public void TestUtxoLookAheadWarmupException()
        {
            var deferredCursor = new Mock <IDeferredChainStateCursor>();

            deferredCursor.Setup(x => x.CursorCount).Returns(4);

            var blockTxes = new BufferBlock <DecodedBlockTx>();

            var lookAhead = UtxoLookAhead.LookAhead(blockTxes, deferredCursor.Object);

            var blockTx0 = BlockTx.Create(0, RandomData.RandomTransaction(new RandomDataOptions {
                TxInputCount = 2
            }));
            var blockTx1 = BlockTx.Create(1, RandomData.RandomTransaction(new RandomDataOptions {
                TxInputCount = 2
            }));

            var expectedException = new InvalidOperationException();

            deferredCursor.Setup(x => x.WarmUnspentTx(blockTx1.Transaction.Inputs[0].PrevTxOutputKey.TxHash)).Throws(expectedException);

            blockTxes.Post(blockTx0);
            blockTxes.Post(blockTx1);
            blockTxes.Complete();

            Exception actualEx;

            AssertMethods.AssertAggregateThrows <Exception>(() =>
                                                            lookAhead.Completion.Wait(2000), out actualEx);
            Assert.AreSame(expectedException, actualEx);
        }
예제 #3
0
        public void TestDoubleSpend()
        {
            // prepare block
            var fakeHeaders      = new FakeHeaders();
            var chainedHeader0   = fakeHeaders.GenesisChained();
            var chainedHeader1   = fakeHeaders.NextChained();
            var chainedHeader2   = fakeHeaders.NextChained();
            var chain            = Chain.CreateForGenesisBlock(chainedHeader0).ToBuilder();
            var emptyCoinbaseTx0 = BlockTx.Create(0, Transaction.Create(0, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0));
            var emptyCoinbaseTx1 = BlockTx.Create(0, Transaction.Create(1, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0));

            // initialize memory utxo builder storage
            var memoryStorage          = new MemoryStorageManager();
            var memoryChainStateCursor = memoryStorage.OpenChainStateCursor().Item;

            memoryChainStateCursor.BeginTransaction();

            // initialize utxo builder
            var utxoBuilder = new UtxoBuilder();

            // prepare an unspent transaction
            var txHash      = new UInt256(100);
            var unspentTx   = new UnspentTx(txHash, chainedHeader1.Height, 0, 0, false, 1, OutputState.Unspent);
            var txOutputKey = new TxOutputKey(txHash, 0);
            var txOutput    = new TxOutput(0, ImmutableArray <byte> .Empty);

            // add the unspent transaction
            memoryChainStateCursor.TryAddUnspentTx(unspentTx);
            memoryChainStateCursor.TryAddUnspentTxOutput(txOutputKey, txOutput);

            // create an input to spend the unspent transaction
            var input = new TxInput(txHash, 0, ImmutableArray.Create <byte>(), 0);
            var tx    = BlockTx.Create(1, Transaction.Create(0, ImmutableArray.Create(input), ImmutableArray.Create <TxOutput>(), 0));

            // spend the input
            chain.AddBlock(chainedHeader1);
            utxoBuilder.CalculateUtxo(memoryChainStateCursor, chain.ToImmutable(), new[] { emptyCoinbaseTx0, tx }.ToBufferBlock()).ToEnumerable().ToList();

            // verify utxo storage
            UnspentTx actualUnspentTx; TxOutput actualTxOutput;

            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTx(txHash, out actualUnspentTx));
            Assert.IsTrue(actualUnspentTx.IsFullySpent);
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTxOutput(txOutputKey, out actualTxOutput));
            Assert.AreEqual(txOutput, actualTxOutput);

            // attempt to spend the input again, validation exception should be thrown
            chain.AddBlock(chainedHeader2);
            AssertMethods.AssertAggregateThrows <ValidationException>(() =>
                                                                      utxoBuilder.CalculateUtxo(memoryChainStateCursor, chain.ToImmutable(), new[] { emptyCoinbaseTx1, tx }.ToBufferBlock()).ToEnumerable().ToList());
        }
예제 #4
0
        public void TestChainTipOutOfSync()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();
            var header2     = fakeHeaders.NextChained();

            var rules            = Mock.Of <ICoreRules>();
            var coreStorage      = new Mock <ICoreStorage>();
            var storageManager   = new Mock <IStorageManager>();
            var chainStateCursor = new Mock <IDeferredChainStateCursor>();

            storageManager.Setup(x => x.OpenChainStateCursor()).Returns(
                new DisposeHandle <IChainStateCursor>(_ => { }, chainStateCursor.Object));

            storageManager.Setup(x => x.OpenDeferredChainStateCursor(It.IsAny <IChainState>())).Returns(
                new DisposeHandle <IDeferredChainStateCursor>(_ => { }, chainStateCursor.Object));

            chainStateCursor.Setup(x => x.TryGetHeader(header0.Hash, out header0)).Returns(true);
            chainStateCursor.Setup(x => x.TryGetHeader(header1.Hash, out header1)).Returns(true);
            chainStateCursor.Setup(x => x.TryGetHeader(header2.Hash, out header2)).Returns(true);

            // return header 1 as the chain tip
            chainStateCursor.Setup(x => x.ChainTip).Returns(header1);

            // init chain state builder seeing header 1
            var chainStateBuilder = new ChainStateBuilder(rules, coreStorage.Object, storageManager.Object);

            Assert.AreEqual(header1.Hash, chainStateBuilder.Chain.LastBlock.Hash);

            // alter the chain tip outside of the chain state builder
            chainStateCursor.Setup(x => x.ChainTip).Returns(header2);

            // attempt to add block when out of sync
            ChainStateOutOfSyncException actualEx;

            AssertMethods.AssertAggregateThrows <ChainStateOutOfSyncException>(() =>
                                                                               chainStateBuilder.AddBlockAsync(header2, Enumerable.Empty <BlockTx>()).Wait(),
                                                                               out actualEx);

            Assert.AreEqual(header1.Hash, actualEx.ExpectedChainTip.Hash);
            Assert.AreEqual(header2.Hash, actualEx.ActualChainTip.Hash);

            // attempt to rollback block when out of sync
            AssertMethods.AssertThrows <ChainStateOutOfSyncException>(() =>
                                                                      chainStateBuilder.RollbackBlock(header2, Enumerable.Empty <BlockTx>()),
                                                                      out actualEx);

            Assert.AreEqual(header1.Hash, actualEx.ExpectedChainTip.Hash);
            Assert.AreEqual(header2.Hash, actualEx.ActualChainTip.Hash);
        }
예제 #5
0
        public void TestInvalidMerkleRoot()
        {
            // prepare mocks
            var coreStorage      = new Mock <ICoreStorage>();
            var storageManager   = new Mock <IStorageManager>();
            var chainStateCursor = new Mock <IDeferredChainStateCursor>();

            storageManager.Setup(x => x.OpenChainStateCursor()).Returns(
                new DisposeHandle <IChainStateCursor>(_ => { }, chainStateCursor.Object));

            storageManager.Setup(x => x.OpenDeferredChainStateCursor(It.IsAny <IChainState>())).Returns(
                new DisposeHandle <IDeferredChainStateCursor>(_ => { }, chainStateCursor.Object));

            chainStateCursor.Setup(x => x.CursorCount).Returns(1);
            chainStateCursor.Setup(x => x.DataFlowBlocks).Returns(new IDataflowBlock[0]);

            // prepare a test block
            var testBlocks = new TestBlocks();
            var rules      = testBlocks.Rules;

            var block         = testBlocks.MineAndAddBlock(txCount: 10);
            var chainedHeader = testBlocks.Chain.LastBlock;

            // create an invalid version of the header where the merkle root is incorrect
            var invalidChainedHeader = ChainedHeader.CreateFromPrev(rules.ChainParams.GenesisChainedHeader, block.Header.With(MerkleRoot: UInt256.Zero), DateTimeOffset.Now);

            // mock genesis block & chain tip
            var genesisHeader = rules.ChainParams.GenesisChainedHeader;

            chainStateCursor.Setup(x => x.ChainTip).Returns(genesisHeader);
            chainStateCursor.Setup(x => x.TryGetHeader(genesisHeader.Hash, out genesisHeader)).Returns(true);

            // mock invalid block
            chainStateCursor.Setup(x => x.TryGetHeader(chainedHeader.Hash, out invalidChainedHeader)).Returns(true);

            // init chain state builder
            var chainStateBuilder = new ChainStateBuilder(rules, coreStorage.Object, storageManager.Object);

            Assert.AreEqual(rules.ChainParams.GenesisBlock.Hash, chainStateBuilder.Chain.LastBlock.Hash);

            // attempt to add block with invalid merkle root
            ValidationException actualEx;

            AssertMethods.AssertAggregateThrows <ValidationException>(() =>
                                                                      chainStateBuilder.AddBlockAsync(invalidChainedHeader, Enumerable.Empty <BlockTx>()).Wait(),
                                                                      out actualEx);

            // verify error
            Assert.AreEqual($"Failing block {invalidChainedHeader.Hash} at height 1: Merkle root is invalid", actualEx.Message);
        }
예제 #6
0
        public void TestExceptionInLoadingTxes()
        {
            var expectedException = new Exception();

            var coreStorage = Mock.Of <ICoreStorage>();

            var loadingTxes = new BufferBlock <LoadingTx>();

            ((IDataflowBlock)loadingTxes).Fault(expectedException);

            var loadedTxes = TxLoader.LoadTxes(coreStorage, loadingTxes);

            Exception actualEx;

            AssertMethods.AssertAggregateThrows <Exception>(() =>
                                                            loadedTxes.ToEnumerable().ToList(), out actualEx);
            Assert.AreSame(expectedException, actualEx);
        }