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); }
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)); } }
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); } }
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); }
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; } }
public static byte[] EncodeTxOutput(TxOutput txOutput) { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { EncodeTxOutput(writer, txOutput); return stream.ToArray(); } }
public PrevTxOutput(TxOutput txOutput, int blockHeight, int txIndex, uint txVersion, bool isCoinbase) : this(txOutput.Value, txOutput.ScriptPublicKey, blockHeight, txIndex, txVersion, isCoinbase) { }
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); }
public static void EncodeTxOutput(BinaryWriter writer, TxOutput txOutput) { writer.WriteUInt64(txOutput.Value); writer.WriteVarBytes(txOutput.ScriptPublicKey.ToArray()); }
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(); }
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; } } }
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(); }
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); } }