public bool TryAddUnspentTx(UnspentTx unspentTx) { if (!this.inTransaction) { throw new InvalidOperationException(); } try { using (var jetUpdate = this.jetSession.BeginUpdate(this.unspentTxTableId, JET_prep.Insert)) { Api.SetColumn(this.jetSession, this.unspentTxTableId, this.txHashColumnId, DbEncoder.EncodeUInt256(unspentTx.TxHash)); Api.SetColumn(this.jetSession, this.unspentTxTableId, this.blockIndexColumnId, unspentTx.BlockIndex); Api.SetColumn(this.jetSession, this.unspentTxTableId, this.txIndexColumnId, unspentTx.TxIndex); Api.SetColumn(this.jetSession, this.unspentTxTableId, this.outputStatesColumnId, DataEncoder.EncodeOutputStates(unspentTx.OutputStates)); jetUpdate.Save(); // increase unspent tx count Api.EscrowUpdate(this.jetSession, this.globalsTableId, this.unspentTxCountColumnId, +1); return(true); } } catch (EsentKeyDuplicateException) { return(false); } }
public bool TryGetTransaction(UInt256 txHash, out UnspentTx unspentTx) { Api.JetBeginTransaction2(this.jetSession, BeginTransactionGrbit.ReadOnly); try { //Api.JetSetCurrentIndex(this.jetSession, this.unspentTxTableId, "IX_TxHash"); Api.MakeKey(this.jetSession, this.unspentTxTableId, txHash.ToByteArray(), MakeKeyGrbit.NewKey); if (Api.TrySeek(this.jetSession, this.unspentTxTableId, SeekGrbit.SeekEQ)) { var confirmedBlockHash = new UInt256(Api.RetrieveColumn(this.jetSession, this.unspentTxTableId, this.confirmedBlockHashColumnId)); var outputStates = DataEncoder.DecodeOutputStates(Api.RetrieveColumn(this.jetSession, this.unspentTxTableId, this.outputStatesColumnId)); unspentTx = new UnspentTx(confirmedBlockHash, outputStates); return(true); } else { unspentTx = default(UnspentTx); return(false); } } finally { Api.JetCommitTransaction(this.jetSession, CommitTransactionGrbit.LazyFlush); } }
public void UpdateTransaction(UInt256 txHash, UnspentTx unspentTx) { Api.JetBeginTransaction(this.jetSession); try { //Api.JetSetCurrentIndex(this.jetSession, this.unspentTxTableId, "IX_TxHash"); Api.MakeKey(this.jetSession, this.unspentTxTableId, txHash.ToByteArray(), MakeKeyGrbit.NewKey); if (!Api.TrySeek(this.jetSession, this.unspentTxTableId, SeekGrbit.SeekEQ)) { throw new KeyNotFoundException(); } Api.JetPrepareUpdate(this.jetSession, this.unspentTxTableId, JET_prep.Replace); try { Api.SetColumn(this.jetSession, this.unspentTxTableId, this.outputStatesColumnId, DataEncoder.EncodeOutputStates(unspentTx.OutputStates)); Api.JetUpdate(this.jetSession, this.unspentTxTableId); Api.JetCommitTransaction(this.jetSession, CommitTransactionGrbit.LazyFlush); } catch (Exception) { Api.JetPrepareUpdate(this.jetSession, this.unspentTxTableId, JET_prep.Cancel); throw; } } catch (Exception) { Api.JetRollback(this.jetSession, RollbackTransactionGrbit.None); throw; } }
public void AddTransaction(UInt256 txHash, UnspentTx unspentTx) { Api.JetBeginTransaction(this.jetSession); try { Api.JetPrepareUpdate(this.jetSession, this.unspentTxTableId, JET_prep.Insert); try { Api.SetColumn(this.jetSession, this.unspentTxTableId, this.txHashColumnId, txHash.ToByteArray()); Api.SetColumn(this.jetSession, this.unspentTxTableId, this.confirmedBlockHashColumnId, unspentTx.ConfirmedBlockHash.ToByteArray()); Api.SetColumn(this.jetSession, this.unspentTxTableId, this.outputStatesColumnId, DataEncoder.EncodeOutputStates(unspentTx.OutputStates)); Api.JetUpdate(this.jetSession, this.unspentTxTableId); Api.JetCommitTransaction(this.jetSession, CommitTransactionGrbit.LazyFlush); this.unspentTxCount++; } catch (Exception) { Api.JetPrepareUpdate(this.jetSession, this.unspentTxTableId, JET_prep.Cancel); throw; } } catch (Exception) { Api.JetRollback(this.jetSession, RollbackTransactionGrbit.None); throw; } }
public bool TryUpdateUnspentTx(UnspentTx unspentTx) { CheckWriteTransaction(); using (SetSessionContext()) { Api.JetSetCurrentIndex(this.jetSession, this.unspentTxTableId, "IX_TxHash"); Api.MakeKey(this.jetSession, this.unspentTxTableId, DbEncoder.EncodeUInt256(unspentTx.TxHash), MakeKeyGrbit.NewKey); if (Api.TrySeek(this.jetSession, this.unspentTxTableId, SeekGrbit.SeekEQ)) { using (var jetUpdate = this.jetSession.BeginUpdate(this.unspentTxTableId, JET_prep.Replace)) { Api.SetColumn(this.jetSession, this.unspentTxTableId, this.outputStatesColumnId, DataEncoder.EncodeOutputStates(unspentTx.OutputStates)); jetUpdate.Save(); } return(true); } else { return(false); } } }
private void Unspend(TxInput input, ChainedHeader chainedHeader, ImmutableDictionary <UInt256, SpentTx> spentTxes) { bool wasRestored; UnspentTx unspentTx; if (this.chainStateCursor.TryGetUnspentTx(input.PreviousTxOutputKey.TxHash, out unspentTx)) { wasRestored = false; } else { // lookup fully spent transaction SpentTx spentTx; if (!spentTxes.TryGetValue(input.PreviousTxOutputKey.TxHash, out spentTx)) { throw new ValidationException(chainedHeader.Hash); } // restore fully spent transaction unspentTx = new UnspentTx(spentTx.TxHash, spentTx.ConfirmedBlockIndex, spentTx.TxIndex, new OutputStates(spentTx.OutputCount, OutputState.Spent)); wasRestored = true; } // retrieve previous output index var outputIndex = unchecked ((int)input.PreviousTxOutputKey.TxOutputIndex); if (outputIndex < 0 || outputIndex >= unspentTx.OutputStates.Length) { throw new Exception("TODO - corruption"); } // check that output isn't already considered unspent if (unspentTx.OutputStates[outputIndex] == OutputState.Unspent) { throw new ValidationException(chainedHeader.Hash); } // mark output as unspent unspentTx = unspentTx.SetOutputState(outputIndex, OutputState.Unspent); // update storage if (!wasRestored) { var wasUpdated = this.chainStateCursor.TryUpdateUnspentTx(unspentTx); if (!wasUpdated) { throw new ValidationException(chainedHeader.Hash); } } else { // a restored fully spent transaction must be added back var wasAdded = this.chainStateCursor.TryAddUnspentTx(unspentTx); if (!wasAdded) { throw new ValidationException(chainedHeader.Hash); } } }
public static byte[] EncodeUnspentTx(UnspentTx unspentTx) { using (var stream = new MemoryStream()) { EncodeUnspentTx(stream, unspentTx); return(stream.ToArray()); } }
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); } }
public static byte[] EncodeUnspentTx(UnspentTx unspentTx) { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { EncodeUnspentTx(writer, unspentTx); return(stream.ToArray()); } }
public static void EncodeUnspentTx(Stream stream, UnspentTx unspentTx) { using (var writer = new BinaryWriter(stream, Encoding.ASCII, leaveOpen: true)) { writer.WriteUInt256(unspentTx.ConfirmedBlockHash); writer.WriteVarBytes(unspentTx.OutputStates.ToByteArray()); writer.WriteInt32(unspentTx.OutputStates.Length); } }
public static void EncodeUnspentTx(BinaryWriter writer, UnspentTx unspentTx) { writer.WriteUInt256(unspentTx.TxHash); writer.WriteInt32(unspentTx.BlockIndex); writer.WriteInt32(unspentTx.TxIndex); writer.WriteUInt32(unspentTx.TxVersion); writer.WriteBool(unspentTx.IsCoinbase); writer.WriteVarBytes(unspentTx.OutputStates.ToByteArray()); writer.WriteInt32(unspentTx.OutputStates.Length); }
public void TestReadUnspentTransactions(ITestStorageProvider provider) { var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var unspentTx2 = new UnspentTx(txHash: 2, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); using (var storageManager = provider.OpenStorageManager()) using (var handle = storageManager.OpenChainStateCursor()) { var chainStateCursor = handle.Item; // begin transaction chainStateCursor.BeginTransaction(); // verify initial empty state Assert.AreEqual(0, chainStateCursor.ReadUnspentTransactions().Count()); // add unspent tx 0 Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx0)); // verify unspent txes CollectionAssert.AreEquivalent(new[] { unspentTx0 }, chainStateCursor.ReadUnspentTransactions().ToList()); // add unspent tx 1 Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx1)); // verify unspent txes CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1 }, chainStateCursor.ReadUnspentTransactions().ToList()); // add unspent tx 2 Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx2)); // verify unspent txes CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1, unspentTx2 }, chainStateCursor.ReadUnspentTransactions().ToList()); // remove unspent tx 2 Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx2.TxHash)); // verify unspent txes CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1 }, chainStateCursor.ReadUnspentTransactions().ToList()); // remove unspent tx 1 Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash)); // verify unspent txes CollectionAssert.AreEquivalent(new[] { unspentTx0 }, chainStateCursor.ReadUnspentTransactions().ToList()); // remove unspent tx 0 Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash)); // verify unspent txes Assert.AreEqual(0, chainStateCursor.ReadUnspentTransactions().Count()); } }
private void TestUnspentTxCount(ITestStorageProvider provider) { var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var unspentTx2 = new UnspentTx(txHash: 2, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); using (var storageManager = provider.OpenStorageManager()) using (var handle = storageManager.OpenChainStateCursor()) { var chainStateCursor = handle.Item; // begin transaction chainStateCursor.BeginTransaction(); // verify initial count Assert.AreEqual(0, chainStateCursor.UnspentTxCount); // add unspent tx 0 chainStateCursor.TryAddUnspentTx(unspentTx0); // verify count Assert.AreEqual(1, chainStateCursor.UnspentTxCount); // add unspent tx 1 chainStateCursor.TryAddUnspentTx(unspentTx1); // verify count Assert.AreEqual(2, chainStateCursor.UnspentTxCount); // add unspent tx 2 chainStateCursor.TryAddUnspentTx(unspentTx2); // verify count Assert.AreEqual(3, chainStateCursor.UnspentTxCount); // remove unspent tx 2 chainStateCursor.TryRemoveUnspentTx(unspentTx2.TxHash); // verify count Assert.AreEqual(2, chainStateCursor.UnspentTxCount); // remove unspent tx 1 chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash); // verify count Assert.AreEqual(1, chainStateCursor.UnspentTxCount); // remove unspent tx 0 chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash); // verify count Assert.AreEqual(0, chainStateCursor.UnspentTxCount); } }
private void TestRollbackTransaction(ITestStorageProvider provider) { var fakeHeaders = new FakeHeaders(); var chainedHeader0 = fakeHeaders.GenesisChained(); var chainedHeader1 = fakeHeaders.NextChained(); var chainedHeader2 = fakeHeaders.NextChained(); var unspentTx = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var spentTxes = ImmutableList.Create(new SpentTx(txHash: 1, confirmedBlockIndex: 0, txIndex: 0, outputCount: 1, spentBlockIndex: 0)); using (var storageManager = provider.OpenStorageManager()) using (var handle = storageManager.OpenChainStateCursor()) { var chainStateCursor = handle.Item; // begin transaction chainStateCursor.BeginTransaction(); // add header 0 chainStateCursor.AddChainedHeader(chainedHeader0); // verify chain CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor.ReadChain().ToList()); // add unspent tx chainStateCursor.TryAddUnspentTx(unspentTx); // verify unspent tx Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx.TxHash)); Assert.AreEqual(1, chainStateCursor.UnspentTxCount); // add spent txes chainStateCursor.TryAddBlockSpentTxes(0, spentTxes); // verify spent txes IImmutableList <SpentTx> actualSpentTxes; Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes)); CollectionAssert.AreEqual(spentTxes, (ICollection)actualSpentTxes); // rollback transaction chainStateCursor.RollbackTransaction(); // verify chain Assert.AreEqual(0, chainStateCursor.ReadChain().Count()); // verify unspent tx Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx.TxHash)); Assert.AreEqual(0, chainStateCursor.UnspentTxCount); // verify spent txes Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes)); } }
public bool TryGetUnspentTx(UInt256 txHash, out UnspentTx unspentTx) { if (this.inTransaction) { return(this.unspentTransactions.TryGetValue(txHash, out unspentTx)); } else { return(this.chainStateStorage.TryGetUnspentTx(txHash, out unspentTx)); } }
private void Mint(Transaction tx, int txIndex, ChainedHeader chainedHeader) { // add transaction to the utxo var unspentTx = new UnspentTx(tx.Hash, chainedHeader.Height, txIndex, tx.Outputs.Length, OutputState.Unspent); if (!this.chainStateCursor.TryAddUnspentTx(unspentTx)) { // duplicate transaction this.logger.Warn("Duplicate transaction at block {0:#,##0}, {1}, coinbase".Format2(chainedHeader.Height, chainedHeader.Hash.ToHexNumberString())); throw new ValidationException(chainedHeader.Hash); } }
public bool TryGetUnspentTx(UInt256 txHash, out UnspentTx unspentTx) { this.semaphore.Wait(); try { return(this.unspentTransactions.TryGetValue(txHash, out unspentTx)); } finally { this.semaphore.Release(); } }
public bool TryAddUnspentTx(UnspentTx unspentTx) { return(this.semaphore.Do(() => { var wasAdded = this.unspentTransactions.TryAdd(unspentTx.TxHash, unspentTx); if (wasAdded) { this.unspentTxesVersion++; } return wasAdded; })); }
private void TestTryAddGetRemoveUnspentTx(ITestStorageProvider provider) { var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); using (var storageManager = provider.OpenStorageManager()) using (var handle = storageManager.OpenChainStateCursor()) { var chainStateCursor = handle.Item; // begin transaction chainStateCursor.BeginTransaction(); // verify initial empty state UnspentTx actualUnspentTx0, actualUnspentTx1; Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0)); Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1)); // add unspent tx 0 Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx0)); // verify unspent txes Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0)); Assert.AreEqual(unspentTx0, actualUnspentTx0); Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1)); // add unspent tx 1 Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx1)); // verify unspent txes Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0)); Assert.AreEqual(unspentTx0, actualUnspentTx0); Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1)); Assert.AreEqual(unspentTx1, actualUnspentTx1); // remove unspent tx 1 Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash)); // verify unspent txes Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0)); Assert.AreEqual(unspentTx0, actualUnspentTx0); Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1)); // remove unspent tx 0 Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash)); // verify unspent txes Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0)); Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1)); } }
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 bool TryUpdateUnspentTx(UnspentTx unspentTx) { CheckWriteTransaction(); if (unspentTransactions.Value.ContainsKey(unspentTx.TxHash)) { unspentTransactions.Modify(x => x[unspentTx.TxHash] = unspentTx); return(true); } else { return(false); } }
public bool TryAddUnspentTx(UnspentTx unspentTx) { CheckWriteTransaction(); try { unspentTransactions.Modify(x => x.Add(unspentTx.TxHash, unspentTx)); return(true); } catch (ArgumentException) { return(false); } }
public bool TryUpdateUnspentTx(UnspentTx unspentTx) { return(this.semaphore.Do(() => { if (this.unspentTransactions.ContainsKey(unspentTx.TxHash)) { this.unspentTransactions[unspentTx.TxHash] = unspentTx; this.unspentTxesVersion++; return true; } else { return false; } })); }
public bool TryGetUnspentTx(UInt256 txHash, out UnspentTx unspentTx) { Api.JetSetCurrentIndex(this.jetSession, this.unspentTxTableId, "IX_TxHash"); Api.MakeKey(this.jetSession, this.unspentTxTableId, DbEncoder.EncodeUInt256(txHash), MakeKeyGrbit.NewKey); if (Api.TrySeek(this.jetSession, this.unspentTxTableId, SeekGrbit.SeekEQ)) { var blockIndex = Api.RetrieveColumnAsInt32(this.jetSession, this.unspentTxTableId, this.blockIndexColumnId).Value; var txIndex = Api.RetrieveColumnAsInt32(this.jetSession, this.unspentTxTableId, this.txIndexColumnId).Value; var outputStates = DataEncoder.DecodeOutputStates(Api.RetrieveColumn(this.jetSession, this.unspentTxTableId, this.outputStatesColumnId)); unspentTx = new UnspentTx(txHash, blockIndex, txIndex, outputStates); return(true); } unspentTx = default(UnspentTx); return(false); }
private void TestCommitTransaction(ITestStorageProvider provider) { var fakeHeaders = new FakeHeaders(); var chainedHeader0 = fakeHeaders.GenesisChained(); var unspentTx = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var spentTxes = ImmutableList.Create(new SpentTx(txHash: 1, confirmedBlockIndex: 0, txIndex: 0, outputCount: 1, spentBlockIndex: 0)); using (var storageManager = provider.OpenStorageManager()) using (var handle = storageManager.OpenChainStateCursor()) { var chainStateCursor = handle.Item; // begin transaction chainStateCursor.BeginTransaction(); // add data chainStateCursor.AddChainedHeader(chainedHeader0); chainStateCursor.TryAddUnspentTx(unspentTx); chainStateCursor.TryAddBlockSpentTxes(0, spentTxes); // verify data Assert.AreEqual(chainedHeader0, chainStateCursor.GetChainTip()); Assert.AreEqual(1, chainStateCursor.UnspentTxCount); UnspentTx actualUnspentTx; Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx)); Assert.AreEqual(unspentTx, actualUnspentTx); IImmutableList <SpentTx> actualSpentTxes; Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes)); CollectionAssert.AreEqual((ICollection)spentTxes, (ICollection)actualSpentTxes); // commit transaction chainStateCursor.CommitTransaction(); // verify data Assert.AreEqual(chainedHeader0, chainStateCursor.GetChainTip()); Assert.AreEqual(1, chainStateCursor.UnspentTxCount); Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx)); Assert.AreEqual(unspentTx, actualUnspentTx); Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes)); CollectionAssert.AreEqual((ICollection)spentTxes, (ICollection)actualSpentTxes); } }
private void TestContainsUnspentTx(ITestStorageProvider provider) { var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent)); using (var storageManager = provider.OpenStorageManager()) using (var handle = storageManager.OpenChainStateCursor()) { var chainStateCursor = handle.Item; // begin transaction chainStateCursor.BeginTransaction(); // verify presence Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash)); Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash)); // add unspent tx 0 chainStateCursor.TryAddUnspentTx(unspentTx0); // verify presence Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash)); Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash)); // add unspent tx 1 chainStateCursor.TryAddUnspentTx(unspentTx1); // verify presence Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash)); Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash)); // remove unspent tx 1 chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash); // verify presence Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash)); Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash)); // remove unspent tx 0 chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash); // verify presence Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash)); Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash)); } }
public bool TryGetUnspentTx(UInt256 txHash, out UnspentTx unspentTx) { CheckTransaction(); using (SetSessionContext()) { Api.JetSetCurrentIndex(this.jetSession, this.unspentTxTableId, "IX_TxHash"); Api.MakeKey(this.jetSession, this.unspentTxTableId, DbEncoder.EncodeUInt256(txHash), MakeKeyGrbit.NewKey); if (Api.TrySeek(this.jetSession, this.unspentTxTableId, SeekGrbit.SeekEQ)) { var blockIndexColumn = new Int32ColumnValue { Columnid = this.blockIndexColumnId }; var txIndexColumn = new Int32ColumnValue { Columnid = this.txIndexColumnId }; var txVersionColumn = new UInt32ColumnValue { Columnid = this.txVersionColumnId }; var isCoinbaseColumn = new BoolColumnValue { Columnid = this.isCoinbaseColumnId }; var outputStatesColumn = new BytesColumnValue { Columnid = this.outputStatesColumnId }; var txOutputBytesColumn = new BytesColumnValue { Columnid = this.txOutputBytesColumnId }; Api.RetrieveColumns(this.jetSession, this.unspentTxTableId, blockIndexColumn, txIndexColumn, txVersionColumn, isCoinbaseColumn, outputStatesColumn, txOutputBytesColumn); var blockIndex = blockIndexColumn.Value.Value; var txIndex = txIndexColumn.Value.Value; var txVersion = txVersionColumn.Value.Value; var isCoinbase = isCoinbaseColumn.Value.Value; var outputStates = DataDecoder.DecodeOutputStates(outputStatesColumn.Value); unspentTx = new UnspentTx(txHash, blockIndex, txIndex, txVersion, isCoinbase, outputStates); return(true); } unspentTx = default(UnspentTx); return(false); } }
public void TestDoubleSpend() { // prepare test kernel var kernel = new StandardKernel(new MemoryStorageModule()); // prepare block var fakeHeaders = new FakeHeaders(); var chainedHeader = new ChainedHeader(fakeHeaders.Genesis(), height: 0, totalWork: 0); // prepare an unspent transaction var txHash = new UInt256(100); var unspentTx = new UnspentTx(chainedHeader.Hash, 1, OutputState.Unspent); // mock a parent utxo containing the unspent transaction var unspentTransactions = ImmutableDictionary.Create <UInt256, UnspentTx>().Add(txHash, unspentTx); var mockParentChainStateStorage = new Mock <IChainStateStorage>(); mockParentChainStateStorage.Setup(utxo => utxo.UnspentTransactions()).Returns(unspentTransactions); var parentUtxo = new Utxo(mockParentChainStateStorage.Object); // initialize memory utxo builder storage var memoryChainStateBuilderStorage = new MemoryChainStateBuilderStorage(mockParentChainStateStorage.Object); kernel.Rebind <IChainStateBuilderStorage>().ToConstant(memoryChainStateBuilderStorage); // initialize utxo builder var chainStateBuilder = new ChainStateBuilder(null, parentUtxo, LogManager.CreateNullLogger(), kernel, null, null, null, null, null); // create an input to spend the unspent transaction var input = new TxInput(new TxOutputKey(txHash, txOutputIndex: 0), ImmutableArray.Create <byte>(), 0); var tx = new Transaction(0, ImmutableArray.Create(input), ImmutableArray.Create <TxOutput>(), 0); // spend the input chainStateBuilder.Spend(0, tx, 0, input, chainedHeader); // verify utxo storage Assert.IsFalse(memoryChainStateBuilderStorage.UnspentTransactionsDictionary.ContainsKey(txHash)); // attempt to spend the input again chainStateBuilder.Spend(0, tx, 0, input, chainedHeader); // validation exception should be thrown }
public bool TryAddUnspentTx(UnspentTx unspentTx) { if (this.inTransaction) { try { this.unspentTransactions.Add(unspentTx.TxHash, unspentTx); this.unspentTxesModified = true; return(true); } catch (ArgumentException) { return(false); } } else { return(this.chainStateStorage.TryAddUnspentTx(unspentTx)); } }
public bool TryUpdateUnspentTx(UnspentTx unspentTx) { if (this.inTransaction) { if (this.unspentTransactions.ContainsKey(unspentTx.TxHash)) { this.unspentTransactions[unspentTx.TxHash] = unspentTx; this.unspentTxesModified = true; return(true); } else { return(false); } } else { return(this.chainStateStorage.TryUpdateUnspentTx(unspentTx)); } }
public void TestUnspentTxEquality() { var randomUnspentTx = RandomData.RandomUnspentTx(); var sameUnspentTx = new UnspentTx ( txHash: randomUnspentTx.TxHash, blockHash: randomUnspentTx.BlockHash, txIndex: randomUnspentTx.TxIndex, unspentOutputs: randomUnspentTx.UnspentOutputs ); var differentUnspentTxBlockHash = new UnspentTx ( txHash: randomUnspentTx.TxHash, blockHash: ~randomUnspentTx.BlockHash, txIndex: randomUnspentTx.TxIndex, unspentOutputs: randomUnspentTx.UnspentOutputs ); var differentUnspentTxTxIndex = new UnspentTx ( txHash: randomUnspentTx.TxHash, blockHash: randomUnspentTx.BlockHash, txIndex: ~randomUnspentTx.TxIndex, unspentOutputs: randomUnspentTx.UnspentOutputs ); var differentUnspentTxTxHash = new UnspentTx ( txHash: ~randomUnspentTx.TxHash, blockHash: randomUnspentTx.BlockHash, txIndex: randomUnspentTx.TxIndex, unspentOutputs: randomUnspentTx.UnspentOutputs ); var differentUnspentTxUnpsentOutputs = new UnspentTx ( txHash: ~randomUnspentTx.TxHash, blockHash: randomUnspentTx.BlockHash, txIndex: randomUnspentTx.TxIndex, unspentOutputs: randomUnspentTx.UnspentOutputs ); Assert.IsTrue(randomUnspentTx.Equals(sameUnspentTx)); Assert.IsTrue(randomUnspentTx == sameUnspentTx); Assert.IsFalse(randomUnspentTx != sameUnspentTx); Assert.IsFalse(randomUnspentTx.Equals(differentUnspentTxBlockHash)); Assert.IsFalse(randomUnspentTx == differentUnspentTxBlockHash); Assert.IsTrue(randomUnspentTx != differentUnspentTxBlockHash); Assert.IsFalse(randomUnspentTx.Equals(differentUnspentTxTxIndex)); Assert.IsFalse(randomUnspentTx == differentUnspentTxTxIndex); Assert.IsTrue(randomUnspentTx != differentUnspentTxTxIndex); Assert.IsFalse(randomUnspentTx.Equals(differentUnspentTxTxHash)); Assert.IsFalse(randomUnspentTx == differentUnspentTxTxHash); Assert.IsTrue(randomUnspentTx != differentUnspentTxTxHash); Assert.IsFalse(randomUnspentTx.Equals(differentUnspentTxUnpsentOutputs)); Assert.IsFalse(randomUnspentTx == differentUnspentTxUnpsentOutputs); Assert.IsTrue(randomUnspentTx != differentUnspentTxUnpsentOutputs); }