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);
        }
Exemple #2
0
        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());
        }
Exemple #3
0
        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>());
            }
        }
Exemple #4
0
        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>()));
            }
        }