// GetCurrentTransactionAndScope // // Returns both the current transaction and scope. This is implemented for optimizations // in TransactionScope because it is required to get both of them in several cases. internal static void GetCurrentTransactionAndScope( TxLookup defaultLookup, out Transaction?current, out TransactionScope?currentScope, out Transaction?contextTransaction) { current = null; currentScope = null; contextTransaction = null; ContextData contextData = ContextData.LookupContextData(defaultLookup); if (contextData != null) { currentScope = contextData.CurrentScope; current = FastGetTransaction(currentScope, contextData, out contextTransaction); } }
public ITxTracer StartNewTxTrace(Transaction?tx) { IList <IBlockTracer> childBlockTracers = _childTracers; List <ITxTracer> tracers = new(childBlockTracers.Count); for (int i = 0; i < childBlockTracers.Count; i++) { IBlockTracer childBlockTracer = childBlockTracers[i]; ITxTracer txTracer = childBlockTracer.StartNewTxTrace(tx); if (txTracer != NullTxTracer.Instance) { tracers.Add(txTracer); } } return(tracers.Count > 0 ? new CompositeTxTracer(tracers) : NullTxTracer.Instance); }
public ReplaceOrderResponse( OrderCancelTransaction orderCancelTransaction, Transaction orderCreateTransaction, OrderFillTransaction?orderFillTransaction, Transaction?orderReissueTransaction, Transaction?orderReissueRejectTransaction, OrderCancelTransaction?replacingOrderCancelTransaction, ImmutableList <string> relatedTransactionIDs, string lastTransactionID) { OrderCancelTransaction = orderCancelTransaction; OrderCreateTransaction = orderCreateTransaction; OrderFillTransaction = orderFillTransaction; OrderReissueTransaction = orderReissueTransaction; OrderReissueRejectTransaction = orderReissueRejectTransaction; ReplacingOrderCancelTransaction = replacingOrderCancelTransaction; RelatedTransactionIDs = relatedTransactionIDs; LastTransactionID = lastTransactionID; }
private async Task <PooledBuffer> DoOutInOpAsync( ClientOp clientOp, Transaction?tx, PooledArrayBufferWriter?request = null) { if (tx == null) { // Use failover socket with reconnect and retry behavior. return(await _table.Socket.DoOutInOpAsync(clientOp, request).ConfigureAwait(false)); } if (tx.FailoverSocket != _table.Socket) { throw new IgniteClientException("Specified transaction belongs to a different IgniteClient instance."); } // Use tx-specific socket without retry and failover. return(await tx.Socket.DoOutInOpAsync(clientOp, request).ConfigureAwait(false)); }
private bool _nextOpcodeMustBeCall; // GAS is allowed only if it followed immediately by a CALL, DELEGATECALL, STATICCALL, or CALLCODE public UserOperationTxTracer( Transaction?transaction, bool paymasterWhitelisted, bool hasInitCode, Address sender, Address paymaster, Address entryPointAddress, ILogger logger) { Success = true; AccessedStorage = new Dictionary <Address, HashSet <UInt256> >(); AccessedAddresses = ImmutableHashSet <Address> .Empty; _paymasterWhitelisted = paymasterWhitelisted; _hasInitCode = hasInitCode; _sender = sender; _paymaster = paymaster; _entryPointAddress = entryPointAddress; _logger = logger; Output = Array.Empty <byte>(); }
internal static Transaction FindOrCreatePromotedTransaction(Guid transactionIdentifier, DistributedTransaction dtx) { Transaction?tx = null; Hashtable promotedTransactionTable = PromotedTransactionTable; lock (promotedTransactionTable) { WeakReference?weakRef = (WeakReference?)promotedTransactionTable[transactionIdentifier]; if (null != weakRef) { tx = weakRef.Target as Transaction; if (null != tx) { // If we found a transaction then dispose it dtx.Dispose(); return(tx.InternalClone()); } else { // an old, moldy weak reference. Let's get rid of it. lock (promotedTransactionTable) { promotedTransactionTable.Remove(transactionIdentifier); } } } tx = new Transaction(dtx); // Since we are adding this reference to the table create an object that will clean that entry up. tx._internalTransaction._finalizedObject = new FinalizedObject(tx._internalTransaction, dtx.Identifier); weakRef = new WeakReference(tx, false); promotedTransactionTable[dtx.Identifier] = weakRef; } dtx.SavedLtmPromotedTransaction = tx; FireDistributedTransactionStarted(tx); return(tx); }
public async Task <IActionResult> Index(Guid id) { Guid userId = this.HttpContext.User.GetId() !.Value; Transaction?transaction = await this.dbContext.Transactions .SingleOrDefaultAsync(t => t.Id == id); if (transaction == null) { return(this.NotFound()); } if (userId == transaction.RecipientId && transaction.Status == Transaction.Statuses.Initialized) { return(this.NotFound()); } if (userId != transaction.InitiatorId && userId != transaction.RecipientId && !this.HttpContext.User.HasRole("admin")) { return(this.BadRequest()); } return(this.View(new TransactionViewModel() { Transaction = transaction, RecipientBooks = transaction.Recipient.BookShelves .SelectMany(b => b.BookShelfBooks) .Where(b => !b.IsLocked && !b.IsRemoved) .Where(b => !transaction.RecipientBooks.Select(b => b.Id).Contains(b.Id)) .ToList(), InitiatorBooks = transaction.Initiator.BookShelves .SelectMany(b => b.BookShelfBooks) .Where(b => !b.IsLocked && !b.IsRemoved) .Where(b => !transaction.InitiatorBooks.Select(b => b.Id).Contains(b.Id)) .ToList() })); }
public bool ShouldTraceTx(Transaction?tx, bool validateChainId) { if (_logger.IsTrace) { _logger.Trace($"Tracing transaction {tx}, from: {tx?.SenderAddress}, to: {tx?.To}, fromAddresses: {_fromAddresses}, toAddresses {_toAddresses}, after {_after}, count {_count}"); } if (tx == null || !TxMatchesAddresses(tx, validateChainId) || (_count <= 0)) { return(false); } if (_after > 0) { --_after; return(false); } --_count; return(true); }
public UserOperationTxTracer( Transaction?transaction, IStateProvider stateProvider, Address sender, Address paymaster, Address create2FactoryAddress, Address entryPointAddress, ILogger logger) { Transaction = transaction; Success = true; AccessedStorage = new Dictionary <Address, HashSet <UInt256> >(); _stateProvider = stateProvider; _sender = sender; _paymaster = paymaster; _create2FactoryAddress = create2FactoryAddress; _entryPointAddress = entryPointAddress; _logger = logger; Output = Array.Empty <byte>(); _excludedAddresses = new[] { _create2FactoryAddress, Address.Zero, _entryPointAddress, _paymaster, _sender }; }
public int CompareTo(Transaction?other) { if (other.Date > Date) { return(1); } if (other.Date < Date) { return(-1); } if (Transaction.GetConvertedPrice(other.Value, other.Currency, other.Currency) > Transaction.GetConvertedPrice(Value, Currency, other.Currency)) { return(-1); } if (Transaction.GetConvertedPrice(other.Value, other.Currency, other.Currency) < Transaction.GetConvertedPrice(Value, Currency, other.Currency)) { return(1); } return(0); }
public void EndTxTrace() { GasUsed += _tracer !.GasSpent; _beneficiaryBalanceBefore ??= (_tracer.BeneficiaryBalanceBefore ?? 0); _beneficiaryBalanceAfter = _tracer.BeneficiaryBalanceAfter; Transaction?tx = _tracer.Transaction; if (tx is not null) { if (tx.TryCalculatePremiumPerGas(_block !.BaseFeePerGas, out UInt256 premiumPerGas)) { UInt256 txFee = (UInt256)_tracer.GasSpent * premiumPerGas; BundleFee += txFee; TxFees[_tracer.Index] = txFee; } TransactionResults[_tracer.Index] = _tracer.Success || (tx is BundleTransaction { CanRevert : true } && _tracer.Error == "revert");
public static int Compare(Transaction?x, Transaction?y, UInt256 baseFee, bool isEip1559Enabled) { if (ReferenceEquals(x, y)) { return(0); } if (ReferenceEquals(null, y)) { return(1); } if (ReferenceEquals(null, x)) { return(-1); } // then by gas price descending // EIP1559 changed the way we're sorting transactions. The transaction with a higher miner tip should go first if (isEip1559Enabled) { UInt256 xGasPrice = UInt256.Min(x.FeeCap, x.GasPremium + baseFee); UInt256 yGasPrice = UInt256.Min(y.FeeCap, y.GasPremium + baseFee); if (xGasPrice < yGasPrice) { return(1); } if (xGasPrice > yGasPrice) { return(-1); } return(y.FeeCap.CompareTo(x.FeeCap)); } // the old way of sorting transactions return(y.GasPrice.CompareTo(x.GasPrice)); }
public bool Equals(Transaction?other) => base.Equals(other);
/// <summary> /// Not supported. Transactions are not supported by the ClickHouse server. /// </summary> /// <exception cref="NotSupportedException">Always throws <see cref="NotSupportedException"/>.</exception> public override void EnlistTransaction(Transaction?transaction) { throw new NotSupportedException(); }
// Since ConensusContext's constructor is internal, it can't be used from neo-express. // CreatePreloadBlock replicates the following logic for creating an empty block with ConensusContext // var ctx = new Neo.Consensus.ConsensusContext(wallet, store); // ctx.Reset(0); // ctx.MakePrepareRequest(); // ctx.MakeCommit(); // ctx.Save(); // Block block = ctx.CreateBlock(); static Block CreatePreloadBlock(Neo.Wallets.Wallet wallet, Random random, Transaction?transaction = null) { using var snapshot = Blockchain.Singleton.GetSnapshot(); var validators = snapshot.GetValidators(); if (validators.Length != 1) { throw new InvalidOperationException("Preload only supported for single-node blockchains"); } var amountNetFee = Block.CalculateNetFee(Enumerable.Empty <Transaction>()); if (amountNetFee != Fixed8.Zero) { throw new InvalidOperationException("amountNetFee must be zero"); } var keyPair = wallet.GetAccount(validators[0]).GetKey(); var prevHash = snapshot.CurrentBlockHash; var prevBlock = snapshot.GetBlock(prevHash); var nonce = NextNonce(random); var minerTx = new MinerTransaction { Nonce = (uint)(nonce % (uint.MaxValue + 1ul)), Attributes = Array.Empty <TransactionAttribute>(), Inputs = Array.Empty <CoinReference>(), Outputs = Array.Empty <TransactionOutput>(), Witnesses = Array.Empty <Witness>() }; var blockTransactions = transaction == null ? new Transaction[] { minerTx } : new Transaction[] { minerTx, transaction }; var txHashes = blockTransactions.Select(tx => tx.Hash).ToArray(); var merkleRoot = MerkleTree.ComputeRoot(txHashes); var nextConsensus = Blockchain.GetConsensusAddress(snapshot.GetValidators(blockTransactions).ToArray()); var consensusData = nonce; var block = new Block() { Version = 0, PrevHash = prevHash, MerkleRoot = merkleRoot, Timestamp = prevBlock.Timestamp + 1, Index = prevBlock.Index + 1, ConsensusData = nonce, NextConsensus = nextConsensus, Transactions = Array.Empty <Transaction>(), }; var commit = new Neo.Consensus.Commit() { ViewNumber = 0, Signature = block.Sign(keyPair) }; var payload = new ConsensusPayload { Version = 0, PrevHash = prevHash, BlockIndex = block.Index, ValidatorIndex = (ushort)0, Data = Neo.IO.Helper.ToArray(commit) }; { var sc = new ContractParametersContext(payload); wallet.Sign(sc); payload.Witness = sc.GetWitnesses()[0]; } { var m = validators.Length - ((validators.Length - 1) / 3); Contract contract = Contract.CreateMultiSigContract(m, validators); ContractParametersContext sc = new ContractParametersContext(block); for (int i = 0, j = 0; i < validators.Length && j < m; i++) { sc.AddSignature(contract, validators[0], payload.GetDeserializedMessage <Neo.Consensus.Commit>().Signature); j++; } block.Witness = sc.GetWitnesses()[0]; block.Transactions = blockTransactions; } return(block); }
public static int Compare(Transaction?x, Transaction?y, in UInt256 baseFee, bool isEip1559Enabled)
public void UpdateFrom(PSBTInput other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } foreach (var uk in other.unknown) { unknown.TryAdd(uk.Key, uk.Value); } if (other.final_script_sig != null) { final_script_sig = other.final_script_sig; } if (other.final_script_witness != null) { final_script_witness = other.final_script_witness; } if (non_witness_utxo == null && other.non_witness_utxo != null) { non_witness_utxo = other.non_witness_utxo; } if (witness_utxo == null && other.witness_utxo != null) { witness_utxo = other.witness_utxo; } if (sighash_type == 0 && other.sighash_type > 0) { sighash_type = other.sighash_type; } if (redeem_script == null && other.redeem_script != null) { redeem_script = other.redeem_script; } if (witness_script == null && other.witness_script != null) { witness_script = other.witness_script; } foreach (var sig in other.partial_sigs) { partial_sigs.TryAdd(sig.Key, sig.Value); } foreach (var keyPath in other.hd_keypaths) { hd_keypaths.TryAdd(keyPath.Key, keyPath.Value); } if (IsFinalized()) { ClearForFinalize(); } }
protected override ParityLikeTxTracer OnStart(Transaction?tx) => new(_block, tx,
public void UpdateFromCoin(ICoin coin) { if (coin == null) { throw new ArgumentNullException(nameof(coin)); } if (coin.Outpoint != PrevOut) { throw new ArgumentException("This coin does not match the input", nameof(coin)); } if (coin is ScriptCoin scriptCoin) { if (scriptCoin.RedeemType == RedeemType.P2SH) { redeem_script = scriptCoin.Redeem; } else if (scriptCoin.RedeemType == RedeemType.WitnessV0) { witness_script = scriptCoin.Redeem; if (scriptCoin.IsP2SH) { redeem_script = witness_script.WitHash.ScriptPubKey; } } } else { if (coin.TxOut.ScriptPubKey.IsScriptType(ScriptType.P2SH) && redeem_script == null) { // Let's try to be smart by finding the redeemScript in the global tx if (Parent.Settings.IsSmart && redeem_script == null) { var redeemScript = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(originalScriptSig, coin.TxOut.ScriptPubKey)?.RedeemScript; if (redeemScript != null) { redeem_script = redeemScript; } } } if (witness_script == null) { // Let's try to be smart by finding the witness script in the global tx if (Parent.Settings.IsSmart && witness_script == null) { var witScriptId = PayToWitScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(coin.TxOut.ScriptPubKey); if (witScriptId == null && redeem_script != null) { witScriptId = PayToWitScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(redeem_script); } if (witScriptId != null) { var redeemScript = PayToWitScriptHashTemplate.Instance.ExtractWitScriptParameters(originalWitScript, witScriptId); if (redeemScript != null) { witness_script = redeemScript; } } } } } if (Parent.Network.Consensus.NeverNeedPreviousTxForSigning || !coin.IsMalleable || witness_script != null) { witness_utxo = coin.TxOut; non_witness_utxo = null; } else { orphanTxOut = coin.TxOut; witness_utxo = null; } if (IsFinalized()) { ClearForFinalize(); } }
public static Transaction GetTransactionFromDtcTransaction(IDtcTransaction transactionNative) { ArgumentNullException.ThrowIfNull(transactionNative, nameof(transactionNative)); TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) { etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromDtcTransaction)}"); } Transaction? transaction = null; bool tooLate = false; TransactionShim?transactionShim = null; Guid txIdentifier = Guid.Empty; OletxTransactionIsolationLevel oletxIsoLevel = OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE; OutcomeEnlistment? outcomeEnlistment = null; RealOletxTransaction?realTx = null; OletxTransaction? oleTx = null; // Let's get the guid of the transaction from the proxy to see if we already have an object. if (transactionNative is not ITransaction myTransactionNative) { throw new ArgumentException(SR.InvalidArgument, nameof(transactionNative)); } OletxXactTransInfo xactInfo; try { myTransactionNative.GetTransactionInfo(out xactInfo); } catch (COMException ex) when(ex.ErrorCode == OletxHelper.XACT_E_NOTRANSACTION) { // If we get here, the transaction has appraently already been committed or aborted. Allow creation of the // OletxTransaction, but it will be marked with a status of InDoubt and attempts to get its Identifier // property will result in a TransactionException. tooLate = true; xactInfo.Uow = Guid.Empty; } OletxTransactionManager oletxTm = TransactionManager.DistributedTransactionManager; if (!tooLate) { // First check to see if there is a promoted LTM transaction with the same ID. If there // is, just return that. transaction = TransactionManager.FindPromotedTransaction(xactInfo.Uow); if (transaction != null) { if (etwLog.IsEnabled()) { etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromDtcTransaction)}"); } return(transaction); } // We need to create a new RealOletxTransaction... oletxTm.DtcTransactionManagerLock.AcquireReaderLock(-1); try { outcomeEnlistment = new OutcomeEnlistment(); oletxTm.DtcTransactionManager.ProxyShimFactory.CreateTransactionShim( transactionNative, outcomeEnlistment, out txIdentifier, out oletxIsoLevel, out transactionShim); } catch (COMException comException) { OletxTransactionManager.ProxyException(comException); throw; } finally { oletxTm.DtcTransactionManagerLock.ReleaseReaderLock(); } // We need to create a new RealOletxTransaction. realTx = new RealOletxTransaction( oletxTm, transactionShim, outcomeEnlistment, txIdentifier, oletxIsoLevel, false); oleTx = new OletxTransaction(realTx); // If a transaction is found then FindOrCreate will Dispose the oletx // created. transaction = TransactionManager.FindOrCreatePromotedTransaction(xactInfo.Uow, oleTx); } else { // It was too late to do a clone of the provided ITransactionNative, so we are just going to // create a RealOletxTransaction without a transaction shim or outcome enlistment. realTx = new RealOletxTransaction( oletxTm, null, null, txIdentifier, OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE, false); oleTx = new OletxTransaction(realTx); transaction = new Transaction(oleTx); TransactionManager.FireDistributedTransactionStarted(transaction); oleTx.SavedLtmPromotedTransaction = transaction; InternalTransaction.DistributedTransactionOutcome(transaction._internalTransaction, TransactionStatus.InDoubt); } if (etwLog.IsEnabled()) { etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromDtcTransaction)}"); } return(transaction); }
public ITxTracer StartNewTxTrace(Transaction?tx) { return(NullTxTracer.Instance); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual void EnlistTransaction(Transaction?transaction) => throw new NotSupportedException(CosmosStrings.TransactionsNotSupported);
protected override ProofTxTracer OnStart(Transaction?tx) => new(_treatSystemAccountDifferently);
internal static void PushServiceDomain(Transaction?newCurrent) { ThrowNotSupported(); }
public FundingParameters(FundingParty offerer, FundingParty acceptor, FeeRate feeRate, Transaction?transactionOverride) { Offerer = offerer; Acceptor = acceptor; FeeRate = feeRate; this.transactionOverride = transactionOverride; }
public ITxTracer StartNewTxTrace(Transaction?tx) { return(tx is null ? new BundleTxTracer(_beneficiary, null, -1) : _tracer = new BundleTxTracer(_beneficiary, tx, _index++)); }
/// <inheritdoc /> public override void WriteJson(JsonWriter writer, Transaction?value, JsonSerializer serializer) { var txHex = value?.ToHex() ?? throw new ArgumentNullException(nameof(value)); writer.WriteValue(txHex); }
public bool TryFinalizeInput([MaybeNullWhen(true)] out IList <PSBTError> errors) { errors = null; if (IsFinalized()) { return(true); } var isSane = this.CheckSanity(); if (isSane.Count != 0) { errors = isSane; return(false); } if (witness_utxo == null && non_witness_utxo == null) { errors = new List <PSBTError>() { new PSBTError(Index, "Neither witness_utxo nor non_witness_output is set") }; return(false); } var coin = this.GetSignableCoin(out var getSignableCoinError) ?? this.GetCoin(); // GetCoin can't be null at this stage. if (coin is null) { throw new InvalidOperationException("Bug in NBitcoin during TryFinalizeInput: Please report it"); } TransactionBuilder transactionBuilder = Parent.CreateTransactionBuilder(); transactionBuilder.AddCoins(coin); foreach (var sig in PartialSigs) { transactionBuilder.AddKnownSignature(sig.Key, sig.Value, coin.Outpoint); } Transaction?signed = null; try { var signedTx = Parent.Settings.IsSmart ? Parent.GetOriginalTransaction() : Transaction.Clone(); signed = transactionBuilder.SignTransaction(signedTx, SigHash.All); } catch (Exception ex) { errors = new List <PSBTError>() { new PSBTError(Index, $"Error while finalizing the input \"{getSignableCoinError ?? ex.Message}\"") }; return(false); } var indexedInput = signed.Inputs.FindIndexedInput(coin.Outpoint); if (!indexedInput.VerifyScript(coin, out var error)) { errors = new List <PSBTError>() { new PSBTError(Index, $"The finalized input script does not properly validate \"{error}\"") }; return(false); } FinalScriptSig = indexedInput.ScriptSig is Script oo && oo != Script.Empty ? oo : null; FinalScriptWitness = indexedInput.WitScript is WitScript o && o != WitScript.Empty ? o : null; if (transactionBuilder.FindSignableCoin(indexedInput) is ScriptCoin scriptCoin) { if (scriptCoin.IsP2SH) { RedeemScript = scriptCoin.GetP2SHRedeem(); } if (scriptCoin.RedeemType == RedeemType.WitnessV0) { WitnessScript = scriptCoin.Redeem; } } ClearForFinalize(); errors = null; return(true); }
internal static Transaction?FastGetTransaction(TransactionScope?currentScope, ContextData contextData, out Transaction?contextTransaction) { Transaction?current = null; contextTransaction = null; contextTransaction = contextData.CurrentTransaction; switch (InteropMode(currentScope)) { case EnterpriseServicesInteropOption.None: current = contextTransaction; // If there is a transaction in the execution context or if there is a current transaction scope // then honer the transaction context. if (current == null && currentScope == null) { // Otherwise check for an external current. if (TransactionManager.s_currentDelegateSet) { current = TransactionManager.s_currentDelegate !(); } else { current = EnterpriseServices.GetContextTransaction(contextData); } } break; case EnterpriseServicesInteropOption.Full: current = EnterpriseServices.GetContextTransaction(contextData); break; case EnterpriseServicesInteropOption.Automatic: if (EnterpriseServices.UseServiceDomainForCurrent()) { current = EnterpriseServices.GetContextTransaction(contextData); } else { current = contextData.CurrentTransaction; } break; } return(current); }
// We don't have a finalizer (~TransactionScope) because all it would be able to do is try to // operate on other managed objects (the transaction), which is not safe to do because they may // already have been finalized. public void Dispose() { bool successful = false; TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) { etwLog.MethodEnter(TraceSourceType.TraceSourceBase, this); } if (_disposed) { if (etwLog.IsEnabled()) { etwLog.MethodExit(TraceSourceType.TraceSourceBase, this); } return; } // Dispose for a scope can only be called on the thread where the scope was created. if ((_scopeThread != Thread.CurrentThread) && !AsyncFlowEnabled) { if (etwLog.IsEnabled()) { etwLog.InvalidOperation("TransactionScope", "InvalidScopeThread"); } throw new InvalidOperationException(SR.InvalidScopeThread); } Exception?exToThrow = null; try { // Single threaded from this point _disposed = true; Debug.Assert(_threadContextData != null); // First, lets pop the "stack" of TransactionScopes and dispose each one that is above us in // the stack, making sure they are NOT consistent before disposing them. // Optimize the first lookup by getting both the actual current scope and actual current // transaction at the same time. TransactionScope?actualCurrentScope = _threadContextData.CurrentScope; Transaction? contextTransaction = null; Transaction? current = Transaction.FastGetTransaction(actualCurrentScope, _threadContextData, out contextTransaction); if (!Equals(actualCurrentScope)) { // Ok this is bad. But just how bad is it. The worst case scenario is that someone is // poping scopes out of order and has placed a new transaction in the top level scope. // Check for that now. if (actualCurrentScope == null) { // Something must have gone wrong trying to clean up a bad scope // stack previously. // Make a best effort to abort the active transaction. Transaction?rollbackTransaction = _committableTransaction; if (rollbackTransaction == null) { rollbackTransaction = _dependentTransaction; } Debug.Assert(rollbackTransaction != null); rollbackTransaction.Rollback(); successful = true; throw TransactionException.CreateInvalidOperationException( TraceSourceType.TraceSourceBase, SR.TransactionScopeInvalidNesting, null, rollbackTransaction.DistributedTxId); } // Verify that expectedCurrent is the same as the "current" current if we the interopOption value is None. else if (EnterpriseServicesInteropOption.None == actualCurrentScope._interopOption) { if (((null != actualCurrentScope._expectedCurrent) && (!actualCurrentScope._expectedCurrent.Equals(current))) || ((null != current) && (null == actualCurrentScope._expectedCurrent)) ) { TransactionTraceIdentifier myId; TransactionTraceIdentifier currentId; if (null == current) { currentId = TransactionTraceIdentifier.Empty; } else { currentId = current.TransactionTraceId; } if (null == _expectedCurrent) { myId = TransactionTraceIdentifier.Empty; } else { myId = _expectedCurrent.TransactionTraceId; } if (etwLog.IsEnabled()) { etwLog.TransactionScopeCurrentChanged(currentId, myId); } exToThrow = TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceBase, SR.TransactionScopeIncorrectCurrent, null, current == null ? Guid.Empty : current.DistributedTxId); // If there is a current transaction, abort it. if (null != current) { try { current.Rollback(); } catch (TransactionException) { // we are already going to throw and exception, so just ignore this one. } catch (ObjectDisposedException) { // Dito } } } } // Now fix up the scopes while (!Equals(actualCurrentScope)) { if (null == exToThrow) { exToThrow = TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceBase, SR.TransactionScopeInvalidNesting, null, current == null ? Guid.Empty : current.DistributedTxId); } if (null == actualCurrentScope !._expectedCurrent) { if (etwLog.IsEnabled()) { etwLog.TransactionScopeNestedIncorrectly(TransactionTraceIdentifier.Empty); } } else { if (etwLog.IsEnabled()) { etwLog.TransactionScopeNestedIncorrectly(actualCurrentScope._expectedCurrent.TransactionTraceId); } } actualCurrentScope._complete = false; try { actualCurrentScope.InternalDispose(); } catch (TransactionException) { // we are already going to throw an exception, so just ignore this one. } actualCurrentScope = _threadContextData.CurrentScope; // We want to fail this scope, too, because work may have been done in one of these other // nested scopes that really should have been done in my scope. _complete = false; } }