Пример #1
0
        public void TestCanSpend_Spent()
        {
            // prepare utxo storage
            var chain = Chain.CreateForGenesisBlock(new FakeHeaders().GenesisChained());
            var unspentTransactions = ImmutableSortedDictionary.CreateBuilder <UInt256, UnspentTx>();

            // prepare spent output
            var txHash = new UInt256(0);

            unspentTransactions.Add(txHash, new UnspentTx(txHash, blockIndex: 0, txIndex: 0, txVersion: 0, isCoinbase: false, length: 1, state: OutputState.Spent));

            // prepare utxo
            var memoryStorage     = new MemoryStorageManager(unspentTransactions: unspentTransactions.ToImmutable());
            var chainStateStorage = memoryStorage.OpenChainStateCursor().Item;

            chainStateStorage.BeginTransaction();
            chainStateStorage.ChainTip = chain.GenesisBlock;
            chainStateStorage.CommitTransaction();
            var utxo = new ChainState(chain, memoryStorage);

            // prepare output reference
            var prevTxOutput = new TxOutputKey(txHash, txOutputIndex: 0);

            // check if output can be spent
            var canSpend = utxo.CanSpend(prevTxOutput);

            // verify output cannot be spent
            Assert.IsFalse(canSpend);
        }
Пример #2
0
        public void TestCanSpend_NegativeIndex()
        {
            // prepare utxo storage
            var chain = new Chain(ImmutableList.Create(new FakeHeaders().GenesisChained()));
            var unspentTransactions = ImmutableSortedDictionary.CreateBuilder <UInt256, UnspentTx>();

            // prepare unspent output
            var txHash = new UInt256(0);

            unspentTransactions.Add(txHash, new UnspentTx(txHash, blockIndex: 0, txIndex: 0, length: 1, state: OutputState.Unspent));

            // prepare utxo
            var memoryStorage     = new MemoryStorageManager(unspentTransactions: unspentTransactions.ToImmutable());
            var chainStateStorage = memoryStorage.OpenChainStateCursor().Item;

            chainStateStorage.AddChainedHeader(chain.GenesisBlock);
            var utxo = new ChainState(chain, memoryStorage);

            // prepare output reference
            var prevTxOutput = new TxOutputKey(txHash, txOutputIndex: UInt32.MaxValue);

            // check if output can be spent
            var canSpend = utxo.CanSpend(prevTxOutput);

            // verify output cannot be spent
            Assert.IsFalse(canSpend);
        }
Пример #3
0
        public void TestTxOutputKeyEquality()
        {
            var randomTxOutputKey = RandomData.RandomTxOutputKey();

            var sameTxOutputKey = new TxOutputKey
                                  (
                txHash: randomTxOutputKey.TxHash,
                txOutputIndex: randomTxOutputKey.TxOutputIndex
                                  );

            var differentTxOutputKeyTxHash = new TxOutputKey
                                             (
                txHash: ~randomTxOutputKey.TxHash,
                txOutputIndex: randomTxOutputKey.TxOutputIndex
                                             );

            var differentTxOutputKeyTxOutputIndex = new TxOutputKey
                                                    (
                txHash: randomTxOutputKey.TxHash,
                txOutputIndex: ~randomTxOutputKey.TxOutputIndex
                                                    );

            Assert.IsTrue(randomTxOutputKey.Equals(sameTxOutputKey));
            Assert.IsTrue(randomTxOutputKey == sameTxOutputKey);
            Assert.IsFalse(randomTxOutputKey != sameTxOutputKey);

            Assert.IsFalse(randomTxOutputKey.Equals(differentTxOutputKeyTxHash));
            Assert.IsFalse(randomTxOutputKey == differentTxOutputKeyTxHash);
            Assert.IsTrue(randomTxOutputKey != differentTxOutputKeyTxHash);

            Assert.IsFalse(randomTxOutputKey.Equals(differentTxOutputKeyTxOutputIndex));
            Assert.IsFalse(randomTxOutputKey == differentTxOutputKeyTxOutputIndex);
            Assert.IsTrue(randomTxOutputKey != differentTxOutputKeyTxOutputIndex);
        }
Пример #4
0
        public void TestCanSpend_NegativeIndex()
        {
            // prepare utxo storage
            var unspentTransactions = ImmutableDictionary.CreateBuilder <UInt256, UnspentTx>();
            var unspentOutputs      = ImmutableDictionary.CreateBuilder <TxOutputKey, TxOutput>();

            // prepare unspent output
            var txHash = new UInt256(0);

            unspentTransactions.Add(txHash, new UnspentTx(confirmedBlockHash: 0, length: 1, state: OutputState.Unspent));
            unspentOutputs.Add(new TxOutputKey(txHash, UInt32.MaxValue), new TxOutput(0, ImmutableArray.Create <byte>()));

            // prepare utxo
            var chainStateStorage = new MemoryChainStateStorage(0, unspentTransactions.ToImmutable(), unspentOutputs.ToImmutable());
            var utxo = new Utxo(chainStateStorage);

            // prepare output reference
            var prevTxOutput = new TxOutputKey(txHash, txOutputIndex: UInt32.MaxValue);

            // check if output can be spent
            var canSpend = utxo.CanSpend(prevTxOutput);

            // verify output cannot be spent
            Assert.IsFalse(canSpend);
        }
Пример #5
0
        public bool CanSpend(TxOutputKey txOutputKey)
        {
            if (txOutputKey == null)
            {
                throw new ArgumentNullException("prevTxOutput");
            }

            UnspentTx unspentTx;

            if (this.chainStateStorage.TryGetTransaction(txOutputKey.TxHash, out unspentTx))
            {
                var outputIndex = unchecked ((int)txOutputKey.TxOutputIndex);

                if (outputIndex < 0 || outputIndex >= unspentTx.OutputStates.Length)
                {
                    return(false);
                }

                return(unspentTx.OutputStates[outputIndex] == OutputState.Unspent);
            }
            else
            {
                return(false);
            }
        }
Пример #6
0
        private TxOutput LookupPreviousOutput(TxOutputKey txOutputKey, ChainedBlock chainedBlock, Dictionary <UInt256, int> blockTxIndices, ChainStateBuilder chainStateBuilder)
        {
            TxOutput prevOutput;

            if (chainStateBuilder.TryGetOutput(txOutputKey, out prevOutput))
            {
                return(prevOutput);
            }
            else
            {
                Transaction prevTx;
                int         prevTxIndex;
                if (blockTxIndices.TryGetValue(txOutputKey.TxHash, out prevTxIndex))
                {
                    Debug.Assert(prevTxIndex >= 0 && prevTxIndex < chainedBlock.Transactions.Count);
                    prevTx = chainedBlock.Transactions[prevTxIndex];
                    Debug.Assert(prevTx.Hash == txOutputKey.TxHash);
                }
                else
                {
                    throw new ValidationException(chainedBlock.Hash);
                }

                var outputIndex = unchecked ((int)txOutputKey.TxOutputIndex);
                if (outputIndex < 0 || outputIndex >= prevTx.Outputs.Count)
                {
                    throw new ValidationException(chainedBlock.Hash);
                }

                return(prevTx.Outputs[outputIndex]);
            }
        }
Пример #7
0
        public void TestTxOutputKeyEquality()
        {
            var randomTxOutputKey = RandomData.RandomTxOutputKey();

            var sameTxOutputKey = new TxOutputKey
            (
                txHash: randomTxOutputKey.TxHash,
                txOutputIndex: randomTxOutputKey.TxOutputIndex
            );

            var differentTxOutputKeyTxHash = new TxOutputKey
            (
                txHash: ~randomTxOutputKey.TxHash,
                txOutputIndex: randomTxOutputKey.TxOutputIndex
            );

            var differentTxOutputKeyTxOutputIndex = new TxOutputKey
            (
                txHash: randomTxOutputKey.TxHash,
                txOutputIndex: ~randomTxOutputKey.TxOutputIndex
            );

            Assert.IsTrue(randomTxOutputKey.Equals(sameTxOutputKey));
            Assert.IsTrue(randomTxOutputKey == sameTxOutputKey);
            Assert.IsFalse(randomTxOutputKey != sameTxOutputKey);

            Assert.IsFalse(randomTxOutputKey.Equals(differentTxOutputKeyTxHash));
            Assert.IsFalse(randomTxOutputKey == differentTxOutputKeyTxHash);
            Assert.IsTrue(randomTxOutputKey != differentTxOutputKeyTxHash);

            Assert.IsFalse(randomTxOutputKey.Equals(differentTxOutputKeyTxOutputIndex));
            Assert.IsFalse(randomTxOutputKey == differentTxOutputKeyTxOutputIndex);
            Assert.IsTrue(randomTxOutputKey != differentTxOutputKeyTxOutputIndex);
        }
Пример #8
0
        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);
                }
            }
        }
Пример #9
0
        public bool TryGetOutput(TxOutputKey txOutputKey, out TxOutput txOutput)
        {
            Api.JetBeginTransaction2(this.jetSession, BeginTransactionGrbit.ReadOnly);
            try
            {
                //Api.JetSetCurrentIndex(this.jetSession, this.unspentTxOutputsTableId, "IX_TxOutputKey");
                Api.MakeKey(this.jetSession, this.unspentTxOutputsTableId, DataEncoder.EncodeTxOutputKey(txOutputKey), MakeKeyGrbit.NewKey);
                if (Api.TrySeek(this.jetSession, this.unspentTxOutputsTableId, SeekGrbit.SeekEQ))
                {
                    var txOutputBytes = Api.RetrieveColumn(this.jetSession, this.unspentTxOutputsTableId, this.txOutputSmallColumnId);
                    if (txOutputBytes == null)
                    {
                        txOutputBytes = Api.RetrieveColumn(this.jetSession, this.unspentTxOutputsTableId, this.txOutputLargeColumnId);
                    }

                    txOutput = DataEncoder.DecodeTxOutput(txOutputBytes);
                    return(true);
                }
                else
                {
                    txOutput = default(TxOutput);
                    return(false);
                }
            }
            finally
            {
                Api.JetCommitTransaction(this.jetSession, CommitTransactionGrbit.LazyFlush);
            }
        }
Пример #10
0
 public static void EncodeTxOutputKey(Stream stream, TxOutputKey txOutputKey)
 {
     using (var writer = new BinaryWriter(stream, Encoding.ASCII, leaveOpen: true))
     {
         writer.WriteUInt256(txOutputKey.TxHash);
         writer.WriteUInt32(txOutputKey.TxOutputIndex);
     }
 }
Пример #11
0
 public static byte[] EncodeTxOutputKey(TxOutputKey txOutputKey)
 {
     using (var stream = new MemoryStream())
     {
         EncodeTxOutputKey(stream, txOutputKey);
         return(stream.ToArray());
     }
 }
Пример #12
0
        //public static void DecodeBlockHashTxIndex(byte[] bytes, out UInt256 blockHash, out int txIndex)
        //{
        //    var blockHashBytes = new byte[32];
        //    var txIndexBytes = new byte[4];

        //    Buffer.BlockCopy(bytes, 0, blockHashBytes, 0, 32);
        //    Buffer.BlockCopy(bytes, 32, txIndexBytes, 0, 4);

        //    blockHash = DbEncoder.DecodeUInt256(blockHashBytes);
        //    txIndex = DbEncoder.DecodeInt32(txIndexBytes);
        //}

        //public static byte[] EncodeBlockHashTxIndex(UInt256 blockHash, int txIndex)
        //{
        //    var blockHashTxIndexBytes = new byte[36];
        //    Buffer.BlockCopy(DbEncoder.EncodeUInt256(blockHash), 0, blockHashTxIndexBytes, 0, 32);
        //    Buffer.BlockCopy(DbEncoder.EncodeInt32(txIndex), 0, blockHashTxIndexBytes, 32, 4);

        //    return blockHashTxIndexBytes;
        //}

        public static byte[] EncodeTxOutputKey(TxOutputKey txOutputKey)
        {
            var buffer = new byte[36];

            txOutputKey.TxHash.ToByteArrayBE(buffer, 0);
            Buffer.BlockCopy(EncodeInt32((int)txOutputKey.TxOutputIndex), 0, buffer, 32, 4);

            return(buffer);
        }
Пример #13
0
 public static byte[] EncodeTxOutputKey(TxOutputKey txOutputKey)
 {
     using (var stream = new MemoryStream())
         using (var writer = new BinaryWriter(stream))
         {
             EncodeTxOutputKey(writer, txOutputKey);
             return(stream.ToArray());
         }
 }
Пример #14
0
        public ImmutableDictionary <UInt256, UnconfirmedTx> GetTransactionsSpending(TxOutputKey txOutputKey)
        {
            using (var handle = storageManager.OpenUnconfirmedTxesCursor())
            {
                var unconfirmedTxesCursor = handle.Item;
                unconfirmedTxesCursor.BeginTransaction(readOnly: true);

                return(unconfirmedTxesCursor.GetTransactionsSpending(txOutputKey));
            }
        }
Пример #15
0
        private byte[] MakeUnspentTxOutputKey(TxOutputKey txOutputKey)
        {
            var key = new byte[37];

            key[0] = UNSPENT_TX_OUTPUT_PREFIX;
            txOutputKey.TxHash.ToByteArrayBE(key, 1);
            Buffer.BlockCopy(Bits.GetBytes(txOutputKey.TxOutputIndex), 0, key, 33, 4);

            return(key);
        }
Пример #16
0
 public void MintTxOutput(ChainPosition chainPosition, TxOutputKey txOutputKey, TxOutput txOutput, UInt256 outputScriptHash, bool isCoinbase)
 {
     //this.Add(() =>
     //{
     foreach (var visitor in this.visitors)
     {
         visitor.MintTxOutput(chainPosition, txOutputKey, txOutput, outputScriptHash, isCoinbase);
     }
     //});
 }
Пример #17
0
 public void UnspendTxOutput(ChainPosition chainPosition, TxInput txInput, TxOutputKey txOutputKey, TxOutput txOutput, UInt256 outputScriptHash)
 {
     //this.Add(() =>
     //{
     foreach (var visitor in this.visitors)
     {
         visitor.UnspendTxOutput(chainPosition, txInput, txOutputKey, txOutput, outputScriptHash);
     }
     //});
 }
Пример #18
0
        public bool ContainsUnspentTxOutput(TxOutputKey txOutputKey)
        {
            CheckTransaction();

            using (SetSessionContext())
            {
                Api.JetSetCurrentIndex(this.jetSession, this.unspentTxOutputTableId, "IX_TxOutputKey");
                Api.MakeKey(this.jetSession, this.unspentTxOutputTableId, DbEncoder.EncodeTxOutputKey(txOutputKey), MakeKeyGrbit.NewKey);
                return(Api.TrySeek(this.jetSession, this.unspentTxOutputTableId, SeekGrbit.SeekEQ));
            }
        }
Пример #19
0
 public ImmutableDictionary <UInt256, UnconfirmedTx> GetTransactionsSpending(TxOutputKey prevTxOutputKey)
 {
     ImmutableDictionary <UInt256, UnconfirmedTx> .Builder unconfirmedTxes;
     if (unconfirmedTxesByPrevTxOutputKey.Value.TryGetValue(prevTxOutputKey, out unconfirmedTxes))
     {
         return(unconfirmedTxes.ToImmutable());
     }
     else
     {
         return(ImmutableDictionary <UInt256, UnconfirmedTx> .Empty);
     }
 }
Пример #20
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());
        }
Пример #21
0
        public bool TryAddUnspentTxOutput(TxOutputKey txOutputKey, TxOutput txOutput)
        {
            CheckWriteTransaction();

            try
            {
                unspentTxOutputs.Modify(x => x.Add(txOutputKey, txOutput));
                return(true);
            }
            catch (ArgumentException)
            {
                return(false);
            }
        }
Пример #22
0
        private static TransformManyBlock <DecodedBlockTx, Tuple <TxOutputKey, CompletionCount, DecodedBlockTx> > InitQueueUnspentTxLookup(CancellationToken cancelToken)
        {
            return(new TransformManyBlock <DecodedBlockTx, Tuple <TxOutputKey, CompletionCount, DecodedBlockTx> >(
                       blockTx =>
            {
                var tx = blockTx.Transaction;

                var outputCount = tx.Outputs.Length;
                var inputCount = !blockTx.IsCoinbase ? tx.Inputs.Length * 2 : 0;

                var txOutputKeys = new Tuple <TxOutputKey, CompletionCount, DecodedBlockTx> [1 + outputCount + inputCount];
                var completionCount = new CompletionCount(txOutputKeys.Length);
                var keyIndex = 0;

                // warm-up the UnspentTx entry that will be added for the new tx
                txOutputKeys[keyIndex++] = Tuple.Create(new TxOutputKey(blockTx.Hash, uint.MaxValue), completionCount, blockTx);

                // warm-up the TxOutput entries that will be added for each of the tx's outputs
                for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
                {
                    var txOutputKey = new TxOutputKey(blockTx.Hash, (uint)outputIndex);
                    txOutputKeys[keyIndex++] = Tuple.Create(txOutputKey, completionCount, blockTx);
                }

                // warm-up the previous UnspentTx and TxOutput entries that will be needed for each of the tx's inputs
                if (!blockTx.IsCoinbase)
                {
                    for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                    {
                        var input = tx.Inputs[inputIndex];

                        // input's previous tx's UnspentTx entry
                        var txOutputKey = new TxOutputKey(input.PrevTxHash, uint.MaxValue);
                        txOutputKeys[keyIndex++] = Tuple.Create(txOutputKey, completionCount, blockTx);

                        // input's previous tx outputs's TxOutput entry
                        txOutputKey = input.PrevTxOutputKey;
                        txOutputKeys[keyIndex++] = Tuple.Create(txOutputKey, completionCount, blockTx);
                    }
                }

                Debug.Assert(txOutputKeys.All(x => x != null));

                return txOutputKeys;
            },
                       new ExecutionDataflowBlockOptions {
                CancellationToken = cancelToken
            }));
        }
Пример #23
0
        public void Unmint(Transaction tx, ChainedHeader chainedHeader, bool isCoinbase)
        {
            // ignore duplicate coinbases
            if ((chainedHeader.Height == DUPE_COINBASE_1_HEIGHT && tx.Hash == DUPE_COINBASE_1_HASH) ||
                (chainedHeader.Height == DUPE_COINBASE_2_HEIGHT && tx.Hash == DUPE_COINBASE_2_HASH))
            {
                return;
            }

            // check that transaction exists
            UnspentTx unspentTx;

            if (!this.chainStateBuilderStorage.TryGetTransaction(tx.Hash, out unspentTx))
            {
                // missing transaction output
                this.logger.Warn("Missing transaction at block {0:#,##0}, {1}, tx {2}".Format2(chainedHeader.Height, chainedHeader.Hash.ToHexNumberString(), tx.Hash));
                throw new ValidationException(chainedHeader.Hash);
            }

            //TODO verify blockheight

            // verify all outputs are unspent before unminting
            if (!unspentTx.OutputStates.All(x => x == OutputState.Unspent))
            {
                throw new ValidationException(chainedHeader.Hash);
            }

            // remove the transaction
            this.chainStateBuilderStorage.RemoveTransaction(tx.Hash);

            // remove the transaction outputs
            for (var outputIndex = 0; outputIndex < tx.Outputs.Count; outputIndex++)
            {
                var txOutput    = tx.Outputs[outputIndex];
                var txOutputKey = new TxOutputKey(tx.Hash, (UInt32)outputIndex);

                this.chainStateBuilderStorage.RemoveOutput(txOutputKey);

                // MONITOR: UnspendTxOutput
                if (this.chainStateMonitor != null)
                {
                    this.chainStateMonitor.UnmintTxOutput(ChainPosition.Fake(), txOutputKey, txOutput, GetOutputScripHash(txOutput), isCoinbase);
                }
            }
        }
Пример #24
0
        public void TestCanSpend_Missing()
        {
            // prepare utxo storage
            var unspentTransactions = ImmutableDictionary.CreateBuilder <UInt256, UnspentTx>();
            var unspentOutputs      = ImmutableDictionary.CreateBuilder <TxOutputKey, TxOutput>();

            // prepare utxo
            var chainStateStorage = new MemoryChainStateStorage(0, unspentTransactions.ToImmutable(), unspentOutputs.ToImmutable());
            var utxo = new Utxo(chainStateStorage);

            // prepare output reference
            var prevTxOutput = new TxOutputKey(txHash: 0, txOutputIndex: 0);

            // check if output can be spent
            var canSpend = utxo.CanSpend(prevTxOutput);

            // verify output cannot be spent
            Assert.IsFalse(canSpend);
        }
Пример #25
0
        public void TestCanSpend_Missing()
        {
            // prepare utxo
            var chain             = new Chain(ImmutableList.Create(new FakeHeaders().GenesisChained()));
            var memoryStorage     = new MemoryStorageManager();
            var chainStateStorage = memoryStorage.OpenChainStateCursor().Item;

            chainStateStorage.AddChainedHeader(chain.GenesisBlock);
            var utxo = new ChainState(chain, memoryStorage);

            // prepare output reference
            var prevTxOutput = new TxOutputKey(txHash: 0, txOutputIndex: 0);

            // check if output can be spent
            var canSpend = utxo.CanSpend(prevTxOutput);

            // verify output cannot be spent
            Assert.IsFalse(canSpend);
        }
Пример #26
0
        public void AddOutput(TxOutputKey txOutputKey, TxOutput txOutput)
        {
            Api.JetBeginTransaction(this.jetSession);
            try
            {
                Api.JetPrepareUpdate(this.jetSession, this.unspentTxOutputsTableId, JET_prep.Insert);
                try
                {
                    var txOutputBytes = DataEncoder.EncodeTxOutput(txOutput);

                    Api.SetColumn(this.jetSession, this.unspentTxOutputsTableId, this.txOutputKeyColumnId, DataEncoder.EncodeTxOutputKey(txOutputKey));
                    if (txOutputBytes.Length <= 255)
                    {
                        Api.SetColumn(this.jetSession, this.unspentTxOutputsTableId, this.txOutputSmallColumnId, txOutputBytes);
                    }
                    else
                    {
                        Api.SetColumn(this.jetSession, this.unspentTxOutputsTableId, this.txOutputLargeColumnId, txOutputBytes);
                    }

                    if (IndexOutputs)
                    {
                        var sha256 = new SHA256Managed();
                        Api.SetColumn(this.jetSession, this.unspentTxOutputsTableId, this.outputScriptHashColumnId, sha256.ComputeHash(txOutput.ScriptPublicKey.ToArray()));
                    }

                    Api.JetUpdate(this.jetSession, this.unspentTxOutputsTableId);
                    Api.JetCommitTransaction(this.jetSession, CommitTransactionGrbit.LazyFlush);
                    this.unspentTxOutputsCount++;
                }
                catch (Exception)
                {
                    Api.JetPrepareUpdate(this.jetSession, this.unspentTxOutputsTableId, JET_prep.Cancel);
                    throw;
                }
            }
            catch (Exception)
            {
                Api.JetRollback(this.jetSession, RollbackTransactionGrbit.None);
                throw;
            }
        }
Пример #27
0
        public bool TryRemoveUnspentTxOutput(TxOutputKey txOutputKey)
        {
            CheckWriteTransaction();

            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))
                {
                    Api.JetDelete(this.jetSession, this.unspentTxOutputTableId);

                    return(true);
                }
                else
                {
                    return(false);
                }
            }
        }
Пример #28
0
        private Transaction GetPreviousTransaction(Block block, int txIndex, TxOutputKey prevTxOutputKey, ImmutableDictionary <UInt256, UnspentTx> utxo, ImmutableDictionary <UInt256, ImmutableHashSet <int> > newTransactions)
        {
            if (newTransactions.ContainsKey(prevTxOutputKey.TxHash))
            {
                var eligible = newTransactions[prevTxOutputKey.TxHash].Where(x => x < txIndex).ToList();
                if (eligible.Count > 0)
                {
                    var max = eligible.Max();

                    if (max >= block.Transactions.Length)
                    {
                        throw new Exception();
                    }

                    var prevTx1 = block.Transactions[max];
                    if (prevTx1.Hash != prevTxOutputKey.TxHash)
                    {
                        throw new Exception();
                    }

                    return(prevTx1);
                }
            }

            // find previous transaction
            if (!utxo.ContainsKey(prevTxOutputKey.TxHash))
            {
                throw new MissingDataException(DataType.Transaction, prevTxOutputKey.TxHash);
            }

            var prevTxKey = utxo[prevTxOutputKey.TxHash].ToTxKey();

            var prevTx2 = this.CacheContext.GetTransaction(prevTxKey);

            if (prevTx2.Hash != prevTxOutputKey.TxHash)
            {
                throw new Exception();
            }

            return(prevTx2);
        }
Пример #29
0
        public void TestCanSpend_Missing()
        {
            // prepare utxo
            var chain             = Chain.CreateForGenesisBlock(new FakeHeaders().GenesisChained());
            var memoryStorage     = new MemoryStorageManager();
            var chainStateStorage = memoryStorage.OpenChainStateCursor().Item;

            chainStateStorage.BeginTransaction();
            chainStateStorage.ChainTip = chain.GenesisBlock;
            chainStateStorage.CommitTransaction();
            var utxo = new ChainState(chain, memoryStorage);

            // prepare output reference
            var prevTxOutput = new TxOutputKey(txHash: UInt256.Zero, txOutputIndex: 0);

            // check if output can be spent
            var canSpend = utxo.CanSpend(prevTxOutput);

            // verify output cannot be spent
            Assert.IsFalse(canSpend);
        }
Пример #30
0
        public bool RemoveOutput(TxOutputKey txOutputKey)
        {
            Api.JetBeginTransaction(this.jetSession);
            try
            {
                //Api.JetSetCurrentIndex(this.jetSession, this.unspentTxOutputsTableId, "IX_TxOutputKey");
                Api.MakeKey(this.jetSession, this.unspentTxOutputsTableId, DataEncoder.EncodeTxOutputKey(txOutputKey), MakeKeyGrbit.NewKey);
                if (!Api.TrySeek(this.jetSession, this.unspentTxOutputsTableId, SeekGrbit.SeekEQ))
                {
                    throw new KeyNotFoundException();
                }

                Api.JetDelete(this.jetSession, this.unspentTxOutputsTableId);
                Api.JetCommitTransaction(this.jetSession, CommitTransactionGrbit.LazyFlush);
                this.unspentTxOutputsCount--;
                return(true);
            }
            catch (Exception)
            {
                Api.JetRollback(this.jetSession, RollbackTransactionGrbit.None);
                throw;
            }
        }
Пример #31
0
        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);
            }
        }