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 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 Transaction 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 TestReadOneLoadingTx() { var coreStorageMock = new Mock<ICoreStorage>(); // create a fake transaction with 4 inputs var prevTxCount = 4; var txIndex = 1; var chainedHeader = RandomData.RandomChainedHeader(); // create previous transactions for 4 inputs var prevTxes = new Transaction[prevTxCount]; var inputs = new TxInput[prevTxCount]; for (var i = 0; i < prevTxCount; i++) { var prevTx = RandomData.RandomTransaction(); var prevBlockTx = (BlockTx)BlockTx.Create(i, prevTx); prevTxes[i] = prevTx; inputs[i] = new TxInput(prevTx.Hash, 0, ImmutableArray.Create<byte>(), 0); // mock retrieval of the previous transaction coreStorageMock.Setup(coreStorage => coreStorage.TryGetTransaction(UInt256.Zero, i, out prevBlockTx)).Returns(true); } // create a loading tx with the 4 inputs referencing block hash 0 var tx = RandomData.RandomTransaction(new RandomDataOptions { TxOutputCount = 1 }) .CreateWith(Inputs: inputs.ToImmutableArray()).Transaction; var prevOutputTxKeys = ImmutableArray.CreateRange( Enumerable.Range(0, prevTxCount).Select(x => new TxLookupKey(UInt256.Zero, x))); var loadingTx = new LoadingTx(txIndex, tx, chainedHeader, prevOutputTxKeys); // begin queuing transactions to load var loadingTxes = new BufferBlock<LoadingTx>(); loadingTxes.Post(loadingTx); loadingTxes.Complete(); // begin transaction loading var txLoader = TxLoader.LoadTxes(coreStorageMock.Object, loadingTxes); // verify the loaded transaction var loadedTxesBuffer = new BufferBlock<LoadedTx>(); txLoader.LinkTo(loadedTxesBuffer, new DataflowLinkOptions { PropagateCompletion = true }); txLoader.Completion.Wait(); IList<LoadedTx> actualLoadedTxes; Assert.IsTrue(loadedTxesBuffer.TryReceiveAll(out actualLoadedTxes)); var actualLoadedTx = actualLoadedTxes.Single(); Assert.AreEqual(loadingTx.TxIndex, actualLoadedTx.TxIndex); Assert.AreEqual(loadingTx.Transaction, actualLoadedTx.Transaction); CollectionAssert.AreEqual(prevTxes.Select(x => x.Hash).ToArray(), actualLoadedTx.InputTxes.Select(x => x.Hash).ToArray()); }
private static LoadedTx LoadTxInput(ICoreStorage coreStorage, ConcurrentDictionary<TxLookupKey, Lazy<BlockTx>> txCache, LoadingTx loadingTx, int inputIndex) { var txIndex = loadingTx.TxIndex; var transaction = loadingTx.Transaction; var chainedHeader = loadingTx.ChainedHeader; // load previous transaction for this input, unless this is a coinbase transaction if (!loadingTx.IsCoinbase) { var prevOutputTxKey = loadingTx.PrevOutputTxKeys[inputIndex]; var input = transaction.Inputs[inputIndex]; var inputPrevTxHash = input.PrevTxOutputKey.TxHash; var inputPrevTx = txCache.GetOrAdd(prevOutputTxKey, new Lazy<BlockTx>(() => { BlockTx tx; if (coreStorage.TryGetTransaction(prevOutputTxKey.BlockHash, prevOutputTxKey.TxIndex, out tx)) return tx; else throw new MissingDataException(prevOutputTxKey.BlockHash); })).Value; if (input.PrevTxOutputKey.TxHash != inputPrevTx.Hash) throw new Exception("TODO"); if (loadingTx.InputTxes.TryComplete(inputIndex, inputPrevTx.Decode().DecodedTx)) return loadingTx.ToLoadedTx(); else return null; } else { Debug.Assert(inputIndex == -1); return new LoadedTx(transaction, txIndex, ImmutableArray.Create<DecodedTx>()); } }
private static LoadedTx LoadTxInput(ICoreStorage coreStorage, ConcurrentDictionary <TxLookupKey, Lazy <BlockTx> > txCache, LoadingTx loadingTx, int inputIndex) { var txIndex = loadingTx.TxIndex; var transaction = loadingTx.Transaction; var chainedHeader = loadingTx.ChainedHeader; // load previous transaction for this input, unless this is a coinbase transaction if (!loadingTx.IsCoinbase) { var prevOutputTxKey = loadingTx.PrevOutputTxKeys[inputIndex]; var input = transaction.Inputs[inputIndex]; var inputPrevTxHash = input.PrevTxOutputKey.TxHash; var inputPrevTx = txCache.GetOrAdd(prevOutputTxKey, new Lazy <BlockTx>(() => { BlockTx tx; if (coreStorage.TryGetTransaction(prevOutputTxKey.BlockHash, prevOutputTxKey.TxIndex, out tx)) { return(tx); } else { throw new MissingDataException(prevOutputTxKey.BlockHash); } })).Value; if (input.PrevTxOutputKey.TxHash != inputPrevTx.Hash) { throw new Exception("TODO"); } if (loadingTx.InputTxes.TryComplete(inputIndex, inputPrevTx.Decode().DecodedTx)) { return(loadingTx.ToLoadedTx()); } else { return(null); } } else { Debug.Assert(inputIndex == -1); return(new LoadedTx(transaction, txIndex, ImmutableArray.Create <DecodedTx>())); } }