private void Unmint(IChainStateCursor chainStateCursor, Transaction tx, ChainedHeader chainedHeader) { // check that transaction exists UnspentTx unspentTx; if (!chainStateCursor.TryGetUnspentTx(tx.Hash, out unspentTx)) { // missing transaction output logger.Warn($"Missing transaction at block {chainedHeader.Height:N0}, {chainedHeader.Hash}, tx {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 if (!chainStateCursor.TryRemoveUnspentTx(tx.Hash)) { throw new ValidationException(chainedHeader.Hash); } // remove the tx outputs for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++) { if (!chainStateCursor.TryRemoveUnspentTxOutput(new TxOutputKey(tx.Hash, (uint)outputIndex))) { throw new ValidationException(chainedHeader.Hash); } } }
public DeferredChainStateCursor(IChainState chainState, IStorageManager storageManager) { this.chainState = chainState; this.storageManager = storageManager; headers = new DeferredDictionary <UInt256, ChainedHeader>( blockHash => { ChainedHeader header; return(Tuple.Create(chainState.TryGetHeader(blockHash, out header), header)); }); unspentTxes = new WorkQueueDictionary <UInt256, UnspentTx>( txHash => { UnspentTx unspentTx; return(Tuple.Create(chainState.TryGetUnspentTx(txHash, out unspentTx), unspentTx)); }); unspentTxOutputs = new WorkQueueDictionary <TxOutputKey, TxOutput>( txOutputKey => { TxOutput txOutput; return(Tuple.Create(chainState.TryGetUnspentTxOutput(txOutputKey, out txOutput), txOutput)); }); blockSpentTxes = new DeferredDictionary <int, BlockSpentTxes>( blockHeight => { BlockSpentTxes spentTxes; return(Tuple.Create(chainState.TryGetBlockSpentTxes(blockHeight, out spentTxes), spentTxes)); }); blockUnmintedTxes = new DeferredDictionary <UInt256, IImmutableList <UnmintedTx> >( blockHash => { IImmutableList <UnmintedTx> unmintedTxes; return(Tuple.Create(chainState.TryGetBlockUnmintedTxes(blockHash, out unmintedTxes), unmintedTxes)); }); utxoApplier = new ActionBlock <WorkQueueDictionary <UInt256, UnspentTx> .WorkItem>( workItem => { workItem.Consume( (operation, unspentTxHash, unspentTx) => { lock (parentCursor) switch (operation) { case WorkQueueOperation.Nothing: break; case WorkQueueOperation.Add: if (!parentCursor.TryAddUnspentTx(unspentTx)) { throw new InvalidOperationException(); } break; case WorkQueueOperation.Update: if (!parentCursor.TryUpdateUnspentTx(unspentTx)) { throw new InvalidOperationException(); } break; case WorkQueueOperation.Remove: if (!parentCursor.TryRemoveUnspentTx(unspentTxHash)) { throw new InvalidOperationException(); } break; default: throw new InvalidOperationException(); } }); }); unspentTxes.WorkQueue.LinkTo(utxoApplier, new DataflowLinkOptions { PropagateCompletion = true }); utxoApplier2 = new ActionBlock <WorkQueueDictionary <TxOutputKey, TxOutput> .WorkItem>( workItem => { workItem.Consume( (operation, txOutputKey, txOutput) => { lock (parentCursor) switch (operation) { case WorkQueueOperation.Nothing: break; case WorkQueueOperation.Add: if (!parentCursor.TryAddUnspentTxOutput(txOutputKey, txOutput)) { throw new InvalidOperationException(); } break; case WorkQueueOperation.Update: throw new InvalidOperationException(); case WorkQueueOperation.Remove: if (!parentCursor.TryRemoveUnspentTxOutput(txOutputKey)) { throw new InvalidOperationException(); } break; default: throw new InvalidOperationException(); } }); }); unspentTxOutputs.WorkQueue.LinkTo(utxoApplier2, new DataflowLinkOptions { PropagateCompletion = true }); }
private void Unmint(IChainStateCursor chainStateCursor, Transaction tx, ChainedHeader chainedHeader) { // check that transaction exists UnspentTx unspentTx; if (!chainStateCursor.TryGetUnspentTx(tx.Hash, out unspentTx)) { // missing transaction output logger.Warn($"Missing transaction at block {chainedHeader.Height:N0}, {chainedHeader.Hash}, tx {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 if (!chainStateCursor.TryRemoveUnspentTx(tx.Hash)) { throw new ValidationException(chainedHeader.Hash); } // remove the tx outputs for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++) { if (!chainStateCursor.TryRemoveUnspentTxOutput(new TxOutputKey(tx.Hash, (uint)outputIndex))) throw new ValidationException(chainedHeader.Hash); } }