public override void ValidationTransactionScript(ChainedHeader chainedHeader, Transaction tx, int txIndex, TxInput txInput, int txInputIndex, TxOutput prevTxOutput)
 {
     if (ValidationTransactionScriptAction == null)
         base.ValidationTransactionScript(chainedHeader, tx, txIndex, txInput, txInputIndex, prevTxOutput);
     else
         ValidationTransactionScriptAction(chainedHeader, tx, txIndex, txInput, txInputIndex, prevTxOutput);
 }
Beispiel #2
0
 public bool TryGetUnspentTxOutput(TxOutputKey txOutputKey, out TxOutput txOutput)
 {
     using (var handle = this.cursorCache.TakeItem())
     {
         var cursor = handle.Item.Item;
         return(cursor.TryGetUnspentTxOutput(txOutputKey, out txOutput));
     }
 }
        public void TestUnconfTxAdded()
        {
            // create tx spending a previous output that exists
            var decodedTx = Transaction.Create(
                0,
                ImmutableArray.Create(new TxInput(UInt256.One, 0, ImmutableArray<byte>.Empty, 0)),
                ImmutableArray.Create(new TxOutput(0, ImmutableArray<byte>.Empty)),
                0);
            var tx = decodedTx.Transaction;

            // create prev output tx
            var unspentTx = new UnspentTx(tx.Inputs[0].PrevTxHash, 0, 1, 0, false, new OutputStates(1, OutputState.Unspent));
            var txOutput = new TxOutput(0, ImmutableArray<byte>.Empty);

            // mock chain state with prev output
            var chainState = new Mock<IChainState>();
            chainState.Setup(x => x.TryGetUnspentTx(tx.Inputs[0].PrevTxHash, out unspentTx)).Returns(true);
            chainState.Setup(x => x.TryGetUnspentTxOutput(tx.Inputs[0].PrevTxOutputKey, out txOutput)).Returns(true);

            // mock core daemon for chain state retrieval
            var coreDaemon = new Mock<ICoreDaemon>();
            coreDaemon.Setup(x => x.GetChainState()).Returns(chainState.Object);

            using (var unconfirmedTxesBuilder = new UnconfirmedTxesBuilder(coreDaemon.Object, Mock.Of<ICoreStorage>(), storageManager))
            {
                // try to add the tx
                Assert.IsTrue(unconfirmedTxesBuilder.TryAddTransaction(decodedTx));

                // verify unconfirmed tx was added
                UnconfirmedTx unconfirmedTx;
                Assert.IsTrue(unconfirmedTxesBuilder.TryGetTransaction(tx.Hash, out unconfirmedTx));
                Assert.IsNotNull(unconfirmedTx);

                // verify tx was indexed against its input
                var txesSpending = unconfirmedTxesBuilder.GetTransactionsSpending(tx.Inputs[0].PrevTxOutputKey);
                Assert.AreEqual(1, txesSpending.Count);
                Assert.AreEqual(tx.Hash, txesSpending.Values.Single().Hash);
            }
        }
        public void TestAddBlockConfirmingTx()
        {
            // create tx spending a previous output that exists
            var decodedTx = Transaction.Create(
                0,
                ImmutableArray.Create(new TxInput(UInt256.One, 0, ImmutableArray<byte>.Empty, 0)),
                ImmutableArray.Create(new TxOutput(0, ImmutableArray<byte>.Empty)),
                0);
            var tx = decodedTx.Transaction;

            // create prev output tx
            var unspentTx = new UnspentTx(tx.Inputs[0].PrevTxHash, 0, 1, 0, false, new OutputStates(1, OutputState.Unspent));
            var txOutput = new TxOutput(0, ImmutableArray<byte>.Empty);

            // create a fake chain
            var fakeHeaders = new FakeHeaders();
            var genesisHeader = fakeHeaders.GenesisChained();

            // create a block confirming the tx
            var block = Block.Create(RandomData.RandomBlockHeader().With(PreviousBlock: genesisHeader.Hash), ImmutableArray.Create(tx));
            var chainedHeader = new ChainedHeader(block.Header, 1, 0, DateTimeOffset.Now);

            // mock core storage with chained header
            var coreStorage = new Mock<ICoreStorage>();
            var initialChain = new ChainBuilder().ToImmutable();
            coreStorage.Setup(x => x.TryReadChain(null, out initialChain)).Returns(true);
            coreStorage.Setup(x => x.TryGetChainedHeader(chainedHeader.Hash, out chainedHeader)).Returns(true);

            // mock chain state with prev output
            var chainState = new Mock<IChainState>();
            chainState.Setup(x => x.TryGetUnspentTx(tx.Inputs[0].PrevTxHash, out unspentTx)).Returns(true);
            chainState.Setup(x => x.TryGetUnspentTxOutput(tx.Inputs[0].PrevTxOutputKey, out txOutput)).Returns(true);

            // mock core daemon for chain state retrieval
            var coreDaemon = new Mock<ICoreDaemon>();
            coreDaemon.Setup(x => x.GetChainState()).Returns(chainState.Object);

            using (var unconfirmedTxesBuilder = new UnconfirmedTxesBuilder(coreDaemon.Object, coreStorage.Object, storageManager))
            {
                // add the tx
                Assert.IsTrue(unconfirmedTxesBuilder.TryAddTransaction(decodedTx));

                // add the block
                unconfirmedTxesBuilder.AddBlock(genesisHeader, Enumerable.Empty<BlockTx>());
                unconfirmedTxesBuilder.AddBlock(chainedHeader, block.BlockTxes);

                // verify the confirmed tx was removed
                UnconfirmedTx unconfirmedTx;
                Assert.IsFalse(unconfirmedTxesBuilder.TryGetTransaction(tx.Hash, out unconfirmedTx));
                Assert.IsNull(unconfirmedTx);

                // verify the confirmed tx was de-indexed against its input
                Assert.AreEqual(0, unconfirmedTxesBuilder.GetTransactionsSpending(tx.Inputs[0].PrevTxOutputKey).Count);
            }
        }
        private void TestTryAddGetRemoveUnspentTxOutput(ITestStorageProvider provider)
        {
            var random = new Random();

            var txOutput0Key = new TxOutputKey(UInt256.Zero, 0);
            var txOutput0 = new TxOutput(0, random.NextBytes(100).ToImmutableArray());
            var txOutput1Key = new TxOutputKey(UInt256.One, 1);
            var txOutput1 = new TxOutput(1, random.NextBytes(100).ToImmutableArray());

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial empty state
                TxOutput actualTxOutput0, actualTxOutput1;
                Assert.IsFalse(chainStateCursor.TryGetUnspentTxOutput(txOutput0Key, out actualTxOutput0));
                Assert.IsFalse(chainStateCursor.TryGetUnspentTxOutput(txOutput1Key, out actualTxOutput1));

                // add unspent tx 0
                Assert.IsTrue(chainStateCursor.TryAddUnspentTxOutput(txOutput0Key, txOutput0));

                // verify unspent txes
                Assert.IsTrue(chainStateCursor.TryGetUnspentTxOutput(txOutput0Key, out actualTxOutput0));
                Assert.AreEqual(txOutput0, actualTxOutput0);
                Assert.IsFalse(chainStateCursor.TryGetUnspentTxOutput(txOutput1Key, out actualTxOutput1));

                // add unspent tx 1
                Assert.IsTrue(chainStateCursor.TryAddUnspentTxOutput(txOutput1Key, txOutput1));

                // verify unspent txes
                Assert.IsTrue(chainStateCursor.TryGetUnspentTxOutput(txOutput0Key, out actualTxOutput0));
                Assert.AreEqual(txOutput0, actualTxOutput0);
                Assert.IsTrue(chainStateCursor.TryGetUnspentTxOutput(txOutput1Key, out actualTxOutput1));
                Assert.AreEqual(txOutput1, actualTxOutput1);

                // remove unspent tx 1
                Assert.IsTrue(chainStateCursor.TryRemoveUnspentTxOutput(txOutput1Key));

                // verify unspent txes
                Assert.IsTrue(chainStateCursor.TryGetUnspentTxOutput(txOutput0Key, out actualTxOutput0));
                Assert.AreEqual(txOutput0, actualTxOutput0);
                Assert.IsFalse(chainStateCursor.TryGetUnspentTxOutput(txOutput1Key, out actualTxOutput1));

                // remove unspent tx 0
                Assert.IsTrue(chainStateCursor.TryRemoveUnspentTxOutput(txOutput0Key));

                // verify unspent txes
                Assert.IsFalse(chainStateCursor.TryGetUnspentTxOutput(txOutput0Key, out actualTxOutput0));
                Assert.IsFalse(chainStateCursor.TryGetUnspentTxOutput(txOutput1Key, out actualTxOutput1));
            }
        }
Beispiel #6
0
        public virtual void ValidationTransactionScript(ChainedHeader chainedHeader, Transaction tx, int txIndex, TxInput txInput, int txInputIndex, TxOutput prevTxOutput)
        {
            var scriptEngine = new ScriptEngine(this.IgnoreSignatures);

            // create the transaction script from the input and output
            var script = txInput.ScriptSignature.Concat(prevTxOutput.ScriptPublicKey);
            if (!scriptEngine.VerifyScript(chainedHeader.Hash, txIndex, prevTxOutput.ScriptPublicKey.ToArray(), tx, txInputIndex, script.ToArray()))
            {
                logger.Debug($"Script did not pass in block: {chainedHeader.Hash}, tx: {txIndex}, {tx.Hash}, input: {txInputIndex}");
                throw new ValidationException(chainedHeader.Hash);
            }
        }
Beispiel #7
0
        public void TestSimpleSpend()
        {
            // prepare block
            var fakeHeaders = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();
            var chainedHeader2 = fakeHeaders.NextChained();
            var chainedHeader3 = 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(1, Transaction.Create(1, ImmutableArray.Create<TxInput>(), ImmutableArray.Create<TxOutput>(), 0));
            var emptyCoinbaseTx2 = BlockTx.Create(2, Transaction.Create(2, 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, 3, OutputState.Unspent);
            var txOutput1Key = new TxOutputKey(txHash, 0);
            var txOutput1 = new TxOutput(0, ImmutableArray<byte>.Empty);
            var txOutput2Key = new TxOutputKey(txHash, 1);
            var txOutput2 = new TxOutput(1, ImmutableArray<byte>.Empty);
            var txOutput3Key = new TxOutputKey(txHash, 2);
            var txOutput3 = new TxOutput(2, ImmutableArray<byte>.Empty);

            // prepare unspent output
            var unspentTransactions = ImmutableDictionary.Create<UInt256, UnspentTx>().Add(txHash, unspentTx);

            // add the unspent transaction
            memoryChainStateCursor.TryAddUnspentTx(unspentTx);
            memoryChainStateCursor.TryAddUnspentTxOutput(txOutput1Key, txOutput1);
            memoryChainStateCursor.TryAddUnspentTxOutput(txOutput2Key, txOutput2);
            memoryChainStateCursor.TryAddUnspentTxOutput(txOutput3Key, txOutput3);

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

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

            // verify utxo storage
            UnspentTx actualUnspentTx; TxOutput actualTxOutput;
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTx(txHash, out actualUnspentTx));
            Assert.IsTrue(actualUnspentTx.OutputStates.Length == 3);
            Assert.IsTrue(actualUnspentTx.OutputStates[0] == OutputState.Spent);
            Assert.IsTrue(actualUnspentTx.OutputStates[1] == OutputState.Unspent);
            Assert.IsTrue(actualUnspentTx.OutputStates[2] == OutputState.Unspent);

            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTxOutput(txOutput1Key, out actualTxOutput));
            Assert.AreEqual(txOutput1, actualTxOutput);
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTxOutput(txOutput2Key, out actualTxOutput));
            Assert.AreEqual(txOutput2, actualTxOutput);
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTxOutput(txOutput3Key, out actualTxOutput));
            Assert.AreEqual(txOutput3, actualTxOutput);

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

            // spend the input
            chain.AddBlock(chainedHeader2);
            utxoBuilder.CalculateUtxo(memoryChainStateCursor, chain.ToImmutable(), new[] { emptyCoinbaseTx1, tx1 }.ToBufferBlock()).ToEnumerable().ToList();

            // verify utxo storage
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTx(txHash, out actualUnspentTx));
            Assert.IsTrue(actualUnspentTx.OutputStates.Length == 3);
            Assert.IsTrue(actualUnspentTx.OutputStates[0] == OutputState.Spent);
            Assert.IsTrue(actualUnspentTx.OutputStates[1] == OutputState.Spent);
            Assert.IsTrue(actualUnspentTx.OutputStates[2] == OutputState.Unspent);

            // create an input to spend the unspent transaction's third output
            var input2 = new TxInput(txHash, 2, ImmutableArray.Create<byte>(), 0);
            var tx2 = BlockTx.Create(2, Transaction.Create(0, ImmutableArray.Create(input2), ImmutableArray.Create<TxOutput>(), 0));

            // spend the input
            chain.AddBlock(chainedHeader3);
            utxoBuilder.CalculateUtxo(memoryChainStateCursor, chain.ToImmutable(), new[] { emptyCoinbaseTx2, tx2 }.ToBufferBlock()).ToEnumerable().ToList();

            // verify utxo storage
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTx(txHash, out actualUnspentTx));
            Assert.IsTrue(actualUnspentTx.IsFullySpent);
        }
Beispiel #8
0
 public bool TryGetUnspentTxOutput(TxOutputKey txOutputKey, out TxOutput txOutput)
 {
     using (var handle = this.cursorCache.TakeItem())
     {
         var cursor = handle.Item.Item;
         return cursor.TryGetUnspentTxOutput(txOutputKey, out txOutput);
     }
 }
        public bool TryGetUnspentTxOutput(TxOutputKey txOutputKey, out TxOutput txOutput)
        {
            CheckTransaction();

            using (SetSessionContext())
            {
                Api.JetSetCurrentIndex(this.jetSession, this.unspentTxOutputTableId, "IX_TxOutputKey");
                Api.MakeKey(this.jetSession, this.unspentTxOutputTableId, DbEncoder.EncodeTxOutputKey(txOutputKey), MakeKeyGrbit.NewKey);
                if (Api.TrySeek(this.jetSession, this.unspentTxOutputTableId, SeekGrbit.SeekEQ))
                {
                    var txOutputBytesColumn = new BytesColumnValue { Columnid = this.txOutputBytesColumnId };
                    Api.RetrieveColumns(this.jetSession, this.unspentTxOutputTableId, txOutputBytesColumn);

                    txOutput = DataDecoder.DecodeTxOutput(txOutputBytesColumn.Value);
                    return true;
                }

                txOutput = default(TxOutput);
                return false;
            }
        }
Beispiel #10
0
 public static byte[] EncodeTxOutput(TxOutput txOutput)
 {
     using (var stream = new MemoryStream())
     using (var writer = new BinaryWriter(stream))
     {
         EncodeTxOutput(writer, txOutput);
         return stream.ToArray();
     }
 }
Beispiel #11
0
 public PrevTxOutput(TxOutput txOutput, int blockHeight, int txIndex, uint txVersion, bool isCoinbase)
     : this(txOutput.Value, txOutput.ScriptPublicKey, blockHeight, txIndex, txVersion, isCoinbase)
 {
 }
Beispiel #12
0
        public void TestReplayForward()
        {
            var coreStorage = new Mock<ICoreStorage>();
            var chainState = new Mock<IChainState>();
            chainState.Setup(x => x.CursorCount).Returns(4);

            var testBlocks = new TestBlocks();

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

            chainState.Setup(x => x.Chain).Returns(() => testBlocks.Chain);

            // mock block txes read
            var blockTxes = block.Transactions.Select((tx, txIndex) => (BlockTx)BlockTx.Create(txIndex, tx)).GetEnumerator();
            coreStorage.Setup(x => x.TryReadBlockTransactions(chainedHeader.Hash, out blockTxes)).Returns(true);

            // mock unspent tx lookup
            var expectedValue = 50UL * (ulong)100.MILLION();
            for (var txIndex = 0; txIndex < block.Transactions.Length; txIndex++)
            {
                var tx = block.Transactions[txIndex];
                for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                {
                    var input = tx.Inputs[inputIndex];

                    // create a fake unspent tx, with enough outputs for this input
                    var unspentTx = new UnspentTx(input.PrevTxOutputKey.TxHash, blockIndex: 1, txIndex: txIndex * inputIndex, txVersion: 0, isCoinbase: false,
                        outputStates: tx.IsCoinbase ? OutputStates.Empty : new OutputStates(input.PrevTxOutputKey.TxOutputIndex.ToIntChecked() + 1, OutputState.Unspent));
                    var txOutput = new TxOutput(tx.Outputs[0].Value, tx.Outputs[0].ScriptPublicKey);

                    chainState.Setup(x => x.TryGetUnspentTx(unspentTx.TxHash, out unspentTx)).Returns(true);
                    chainState.Setup(x => x.TryGetUnspentTxOutput(input.PrevTxOutputKey, out txOutput)).Returns(true);
                }
            }

            var validatableTxes = UtxoReplayer.ReplayCalculateUtxo(coreStorage.Object, chainState.Object, chainedHeader).ToEnumerable().ToList();

            // verify correct number of transactions were replayed
            Assert.AreEqual(validatableTxes.Count, block.Transactions.Length);

            expectedValue = 50UL * (ulong)100.MILLION();
            foreach (var validatableTx in validatableTxes)
            {
                // verify validatable tx matches original block tx
                Assert.AreEqual(block.Transactions[validatableTx.Index].Hash, validatableTx.Transaction.Hash);

                // if coinbase, verify no tx outputs for coinbase inputs
                if (validatableTx.IsCoinbase)
                {
                    Assert.AreEqual(0, validatableTx.PrevTxOutputs.Length);
                }
                else
                {
                    // verify there is a tx output for each input
                    Assert.AreEqual(block.Transactions[validatableTx.Index].Inputs.Length, validatableTx.PrevTxOutputs.Length);

                    // verify each tx output matches the mocked data
                    for (var inputIndex = 0; inputIndex < validatableTx.Transaction.Inputs.Length; inputIndex++)
                    {
                        var prevTxOutput = validatableTx.PrevTxOutputs[inputIndex];

                        expectedValue -= 1;
                        Assert.AreEqual(expectedValue, prevTxOutput.Value);
                        CollectionAssert.AreEqual(block.Transactions[0].Outputs[0].ScriptPublicKey, prevTxOutput.ScriptPublicKey);
                    }
                }
            }
        }
        public bool TryAddUnspentTxOutput(TxOutputKey txOutputKey, TxOutput txOutput)
        {
            CheckWriteTransaction();

            try
            {
                unspentTxOutputs.Modify(x => x.Add(txOutputKey, txOutput));
                return true;
            }
            catch (ArgumentException)
            {
                return false;
            }
        }
 public bool TryGetUnspentTxOutput(TxOutputKey txOutputKey, out TxOutput txOutput)
 {
     CheckTransaction();
     return unspentTxOutputs.Value.TryGetValue(txOutputKey, out txOutput);
 }
 public bool TryAddUnspentTxOutput(TxOutputKey txOutputKey, TxOutput txOutput)
 {
     CheckWriteTransaction();
     return unspentTxOutputs.TryAdd(txOutputKey, txOutput);
 }
Beispiel #16
0
 public static void EncodeTxOutput(BinaryWriter writer, TxOutput txOutput)
 {
     writer.WriteUInt64(txOutput.Value);
     writer.WriteVarBytes(txOutput.ScriptPublicKey.ToArray());
 }
Beispiel #17
0
 public PrevTxOutput(TxOutput txOutput, UnspentTx unspentTx)
     : this(txOutput, unspentTx.BlockIndex, unspentTx.TxIndex, unspentTx.TxVersion, unspentTx.IsCoinbase)
 {
 }
 private static byte[] GetScriptFromInputPrevOutput(TxInput input, TxOutput prevOutput)
 {
     return input.ScriptSignature.Concat(prevOutput.ScriptPublicKey).ToArray();
 }
Beispiel #19
0
 public PrevTxOutput(TxOutput txOutput, UnspentTx unspentTx)
     : this(txOutput, unspentTx.BlockIndex, unspentTx.TxIndex, unspentTx.TxVersion, unspentTx.IsCoinbase)
 { }
        public bool TryAddUnspentTxOutput(TxOutputKey txOutputKey, TxOutput txOutput)
        {
            CheckWriteTransaction();

            using (SetSessionContext())
            {
                try
                {
                    using (var jetUpdate = this.jetSession.BeginUpdate(this.unspentTxOutputTableId, JET_prep.Insert))
                    {
                        Api.SetColumns(this.jetSession, this.unspentTxOutputTableId,
                            new BytesColumnValue { Columnid = this.txOutputKeyColumnId, Value = DbEncoder.EncodeTxOutputKey(txOutputKey) },
                            new BytesColumnValue { Columnid = this.txOutputBytesColumnId, Value = DataEncoder.EncodeTxOutput(txOutput) });

                        jetUpdate.Save();
                    }

                    return true;
                }
                catch (EsentKeyDuplicateException)
                {
                    return false;
                }
            }
        }
Beispiel #21
0
 public PrevTxOutput(TxOutput txOutput, int blockHeight, int txIndex, uint txVersion, bool isCoinbase)
     : this(txOutput.Value, txOutput.ScriptPublicKey, blockHeight, txIndex, txVersion, isCoinbase)
 { }
Beispiel #22
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());
        }
        private void TestContainsUnspentTxOutput(ITestStorageProvider provider)
        {
            var random = new Random();

            var txOutput0Key = new TxOutputKey(UInt256.Zero, 0);
            var txOutput0 = new TxOutput(0, random.NextBytes(100).ToImmutableArray());
            var txOutput1Key = new TxOutputKey(UInt256.One, 1);
            var txOutput1 = new TxOutput(1, random.NextBytes(100).ToImmutableArray());

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsUnspentTxOutput(txOutput0Key));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTxOutput(txOutput1Key));

                // add unspent tx 0
                chainStateCursor.TryAddUnspentTxOutput(txOutput0Key, txOutput0);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsUnspentTxOutput(txOutput0Key));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTxOutput(txOutput1Key));

                // add unspent tx 1
                chainStateCursor.TryAddUnspentTxOutput(txOutput1Key, txOutput1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsUnspentTxOutput(txOutput0Key));
                Assert.IsTrue(chainStateCursor.ContainsUnspentTxOutput(txOutput1Key));

                // remove unspent tx 1
                chainStateCursor.TryRemoveUnspentTxOutput(txOutput1Key);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsUnspentTxOutput(txOutput0Key));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTxOutput(txOutput1Key));

                // remove unspent tx 0
                chainStateCursor.TryRemoveUnspentTxOutput(txOutput0Key);

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsUnspentTxOutput(txOutput0Key));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTxOutput(txOutput1Key));
            }
        }
 public bool MatchesTxOutput(TxOutput txOutput, UInt256 txOutputScriptHash)
 {
     throw new NotSupportedException();
 }
Beispiel #25
0
        private void ScanForEntry(ChainPosition chainPosition, EnumWalletEntryType walletEntryType, TxOutput txOutput, UInt256 outputScriptHash)
        {
            var matchingAddresses = ImmutableList.CreateBuilder<MonitoredWalletAddress>();

            // test hash addresses
            List<MonitoredWalletAddress> addresses;
            if (this.addressesByOutputScriptHash.TryGetValue(outputScriptHash, out addresses))
            {
                matchingAddresses.AddRange(addresses);
            }

            // test matcher addresses
            foreach (var address in this.matcherAddresses)
            {
                if (address.Address.MatchesTxOutput(txOutput, outputScriptHash))
                    matchingAddresses.Add(address);
            }

            if (matchingAddresses.Count > 0)
            {
                var entry = new WalletEntry
                (
                    addresses: matchingAddresses.ToImmutable(),
                    type: walletEntryType,
                    chainPosition: chainPosition,
                    value: txOutput.Value
                );

                lock (this.entries)
                {
                    if (keepEntries)
                        this.entries.Add(entry);

                    this.entriesCount++;
                }
                this.bitBalance += entry.BitValue * walletEntryType.Direction();

                logger.Debug($"{walletEntryType + ":",-10}   {txOutput.Value / (decimal)(100.MILLION()),20:#,##0.000_000_00} BTC, Entries: {this.entriesCount:#,##0}");

                this.OnEntryAdded?.Invoke(entry);
            }
        }