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); }
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); }
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()); }
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); }
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); }
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); }