private PrevTxOutput Unspend(IChainStateCursor chainStateCursor, TxInput input, ChainedHeader chainedHeader) { UnspentTx unspentTx; if (!chainStateCursor.TryGetUnspentTx(input.PrevTxOutputKey.TxHash, out unspentTx)) { // unable to rollback, the unspent tx has been pruned //TODO better exception throw new InvalidOperationException(); } // retrieve previous output index var outputIndex = unchecked ((int)input.PrevTxOutputKey.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); } var wasFullySpent = unspentTx.IsFullySpent; // mark output as unspent unspentTx = unspentTx.SetOutputState(outputIndex, OutputState.Unspent); // increment unspent output count chainStateCursor.UnspentOutputCount++; // update storage var wasUpdated = chainStateCursor.TryUpdateUnspentTx(unspentTx); if (!wasUpdated) { throw new ValidationException(chainedHeader.Hash); } // increment unspent tx count if (wasFullySpent) { chainStateCursor.UnspentTxCount++; } TxOutput txOutput; if (!chainStateCursor.TryGetUnspentTxOutput(input.PrevTxOutputKey, out txOutput)) { // output missing throw new ValidationException(chainedHeader.Hash); } return(new PrevTxOutput(txOutput, unspentTx)); }
private PrevTxOutput Spend(IChainStateCursor chainStateCursor, int txIndex, Transaction tx, int inputIndex, TxInput input, ChainedHeader chainedHeader, BlockSpentTxesBuilder blockSpentTxes) { UnspentTx unspentTx; if (!chainStateCursor.TryGetUnspentTx(input.PrevTxOutputKey.TxHash, out unspentTx)) { // output wasn't present in utxo, invalid block throw new ValidationException(chainedHeader.Hash); } var outputIndex = unchecked ((int)input.PrevTxOutputKey.TxOutputIndex); if (outputIndex < 0 || outputIndex >= unspentTx.OutputStates.Length) { // output was out of bounds throw new ValidationException(chainedHeader.Hash); } if (unspentTx.OutputStates[outputIndex] == OutputState.Spent) { // output was already spent throw new ValidationException(chainedHeader.Hash); } // update output states unspentTx = unspentTx.SetOutputState(outputIndex, OutputState.Spent); // decrement unspent output count chainStateCursor.UnspentOutputCount--; // update transaction output states in the utxo var wasUpdated = chainStateCursor.TryUpdateUnspentTx(unspentTx); if (!wasUpdated) { throw new ValidationException(chainedHeader.Hash); } // store pruning information for a fully spent transaction if (unspentTx.IsFullySpent) { blockSpentTxes.AddSpentTx(unspentTx.ToSpentTx()); // decrement unspent tx count chainStateCursor.UnspentTxCount--; } TxOutput txOutput; if (!chainStateCursor.TryGetUnspentTxOutput(input.PrevTxOutputKey, out txOutput)) { // output missing throw new ValidationException(chainedHeader.Hash); } return(new PrevTxOutput(txOutput, unspentTx)); }
private PrevTxOutput Unspend(IChainStateCursor chainStateCursor, TxInput input, ChainedHeader chainedHeader) { UnspentTx unspentTx; if (!chainStateCursor.TryGetUnspentTx(input.PrevTxOutputKey.TxHash, out unspentTx)) { // unable to rollback, the unspent tx has been pruned //TODO better exception throw new InvalidOperationException(); } // retrieve previous output index var outputIndex = unchecked((int)input.PrevTxOutputKey.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); var wasFullySpent = unspentTx.IsFullySpent; // mark output as unspent unspentTx = unspentTx.SetOutputState(outputIndex, OutputState.Unspent); // increment unspent output count chainStateCursor.UnspentOutputCount++; // update storage var wasUpdated = chainStateCursor.TryUpdateUnspentTx(unspentTx); if (!wasUpdated) throw new ValidationException(chainedHeader.Hash); // increment unspent tx count if (wasFullySpent) chainStateCursor.UnspentTxCount++; TxOutput txOutput; if (!chainStateCursor.TryGetUnspentTxOutput(input.PrevTxOutputKey, out txOutput)) // output missing throw new ValidationException(chainedHeader.Hash); return new PrevTxOutput(txOutput, unspentTx); }
private PrevTxOutput Spend(IChainStateCursor chainStateCursor, int txIndex, Transaction tx, int inputIndex, TxInput input, ChainedHeader chainedHeader, BlockSpentTxesBuilder blockSpentTxes) { UnspentTx unspentTx; if (!chainStateCursor.TryGetUnspentTx(input.PrevTxOutputKey.TxHash, out unspentTx)) { // output wasn't present in utxo, invalid block throw new ValidationException(chainedHeader.Hash); } var outputIndex = unchecked((int)input.PrevTxOutputKey.TxOutputIndex); if (outputIndex < 0 || outputIndex >= unspentTx.OutputStates.Length) { // output was out of bounds throw new ValidationException(chainedHeader.Hash); } if (unspentTx.OutputStates[outputIndex] == OutputState.Spent) { // output was already spent throw new ValidationException(chainedHeader.Hash); } // update output states unspentTx = unspentTx.SetOutputState(outputIndex, OutputState.Spent); // decrement unspent output count chainStateCursor.UnspentOutputCount--; // update transaction output states in the utxo var wasUpdated = chainStateCursor.TryUpdateUnspentTx(unspentTx); if (!wasUpdated) throw new ValidationException(chainedHeader.Hash); // store pruning information for a fully spent transaction if (unspentTx.IsFullySpent) { blockSpentTxes.AddSpentTx(unspentTx.ToSpentTx()); // decrement unspent tx count chainStateCursor.UnspentTxCount--; } TxOutput txOutput; if (!chainStateCursor.TryGetUnspentTxOutput(input.PrevTxOutputKey, out txOutput)) // output missing throw new ValidationException(chainedHeader.Hash); return new PrevTxOutput(txOutput, unspentTx); }