public override void CheckTransaction(MempoolValidationContext context)
        {
            // Calculate in-mempool ancestors, up to a limit.
            context.SetAncestors = new TxMempool.SetEntries();
            int nLimitAncestors      = this.settings.LimitAncestors;
            int nLimitAncestorSize   = this.settings.LimitAncestorSize * 1000;
            int nLimitDescendants    = this.settings.LimitDescendants;
            int nLimitDescendantSize = this.settings.LimitDescendantSize * 1000;

            if (!this.mempool.CalculateMemPoolAncestors(context.Entry, context.SetAncestors, nLimitAncestors,
                                                        nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, out string errString))
            {
                this.logger.LogTrace("(-)FAIL_CHAIN_TOO_LONG]");
                context.State.Fail(MempoolErrors.TooLongMempoolChain, errString).Throw();
            }

            // A transaction, that spends outputs that would be replaced by it, is invalid. Now
            // that we have the set of all ancestors we can detect this
            // pathological case by making sure setConflicts and setAncestors don't
            // intersect.
            foreach (TxMempoolEntry ancestorIt in context.SetAncestors)
            {
                uint256 hashAncestor = ancestorIt.TransactionHash;
                if (context.SetConflicts.Contains(hashAncestor))
                {
                    this.logger.LogTrace("(-)[FAIL_BAD_TX_SPENDS_CONFLICTING]");
                    context.State.Fail(MempoolErrors.BadTxnsSpendsConflictingTx,
                                       $"{context.TransactionHash} spends conflicting transaction {hashAncestor}").Throw();
                }
            }
        }
        public override void CheckTransaction(MempoolValidationContext context)
        {
            Transaction transaction = context.Transaction;

            // Coinbase is only valid in a block, not as a loose transaction
            if (context.Transaction.IsCoinBase)
            {
                this.logger.LogTrace("(-)[FAIL_INVALID_COINBASE]");
                context.State.Fail(MempoolErrors.Coinbase).Throw();
            }

            // Coinstake is only valid in a block, not as a loose transaction
            if (transaction.IsCoinStake)
            {
                this.logger.LogTrace("(-)[FAIL_INVALID_COINSTAKE]");
                context.State.Fail(MempoolErrors.Coinstake).Throw();
            }

            this.checkPowTransactionRule.CheckTransaction(this.network, this.network.Consensus.Options, transaction);

            // we do not need the CheckPosTransactionRule, the checks for empty outputs are already in the MainNetOutputNotWhitelistedMempoolRule.

            CheckStandardTransaction(context);

            // ObsidianX behaves according do BIP 113. Since the adoption of BIP 113, the time-based nLockTime is compared to the 11 - block median time past
            // (the median timestamp of the 11 blocks preceding the block in which the transaction is mined), and not the block time itself.
            // The median time past tends to lag the current unix time by about one hour(give or take), but unlike block time it increases monotonically.
            // For transaction relay, nLockTime must be <= the current block's height (block-based) or <= the current median time past (if time based).
            // This ensures that the transaction can be included in the next block.
            if (!CheckFinalTransaction(this.chainIndexer, this.dateTimeProvider, context.Transaction))
            {
                this.logger.LogTrace("(-)[FAIL_NONSTANDARD]");
                context.State.Fail(MempoolErrors.NonFinal).Throw();
            }
        }
Пример #3
0
        public override void CheckTransaction(MempoolValidationContext context)
        {
            // We expect a reward claim transaction to have at least 2 outputs.
            bool federationPayment = !(context.Transaction.Outputs.Count < 2);

            // The OP_RETURN output that marks the transaction as cross-chain (and in particular a reward claiming transaction) must be present.
            if (context.Transaction.Outputs.All(o => o.ScriptPubKey != StraxCoinstakeRule.CirrusTransactionTag(((StraxBaseNetwork)(this.network)).CirrusRewardDummyAddress)))
            {
                federationPayment = false;
            }

            // At least one other output must be paying to the multisig.
            if (context.Transaction.Outputs.All(o => o.ScriptPubKey != ((StraxBaseNetwork)(this.network)).Federations.GetOnlyFederation().MultisigScript.PaymentScript))
            {
                federationPayment = false;
            }

            // There must be no other spendable scriptPubKeys.
            if (context.Transaction.Outputs.Any(o => o.ScriptPubKey != ((StraxBaseNetwork)(this.network)).Federations.GetOnlyFederation().MultisigScript.PaymentScript&& !o.ScriptPubKey.IsUnspendable))
            {
                federationPayment = false;
            }

            // We need to bypass the fee checking logic for correctly-formed transactions that pay Cirrus rewards to the federation.
            if (federationPayment)
            {
                return;
            }

            base.CheckTransaction(context);
        }
        public override void CheckTransaction(MempoolValidationContext context)
        {
            Guard.Assert(context.View != null);

            context.LockPoints = new LockPoints();

            // Do we already have it?
            if (context.View.HaveTransaction(context.TransactionHash))
            {
                this.logger.LogTrace("(-)[INVALID_ALREADY_KNOWN]");
                context.State.Invalid(MempoolErrors.AlreadyKnown).Throw();
            }

            // Do all inputs exist?
            foreach (TxIn txin in context.Transaction.Inputs)
            {
                if (!context.View.HaveCoins(txin.PrevOut))
                {
                    // Assume this might be an orphan tx for which we just haven't seen parents yet
                    context.State.MissingInputs = true;
                    this.logger.LogTrace("(-)[FAIL_MISSING_INPUTS]");
                    context.State.Fail(MempoolErrors.MissingOrSpentInputs).Throw();
                }
            }
        }
Пример #5
0
 public override void CheckTransaction(MempoolValidationContext context)
 {
     if (context.Transaction.Inputs.Any(x => x.ScriptSig.IsSmartContractSpend()) || context.Transaction.Outputs.Any(x => x.ScriptPubKey.IsSmartContractSpend()))
     {
         this.Throw();
     }
 }
Пример #6
0
 public void CheckTransaction(MempoolValidationContext context)
 {
     if (context.Transaction.Inputs.Any(x => ContainsOpSpend(x.ScriptSig)) || context.Transaction.Outputs.Any(x => ContainsOpSpend(x.ScriptPubKey)))
     {
         Throw();
     }
 }
Пример #7
0
        public override void CheckTransaction(MempoolValidationContext context)
        {
            var mempoolRejectFee = this.mempool.GetMinFee(this.settings.MaxMempool * 1000000).GetFee(context.EntrySize);

            if (mempoolRejectFee > 0 && context.ModifiedFees < mempoolRejectFee)
            {
                this.logger.LogTrace("(-)[FAIL_MIN_FEE_NOT_MET]");
                context.State.Fail(MempoolErrors.MinFeeNotMet, $" {context.Fees} < {mempoolRejectFee}").Throw();
            }
            else if (this.settings.RelayPriority &&
                     context.ModifiedFees < context.MinRelayTxFee.GetFee(context.EntrySize) &&
                     !TxMempool.AllowFree(context.Entry.GetPriority(this.chainIndexer.Height + 1)))
            {
                this.logger.LogTrace("(-)[FAIL_INSUFFICIENT_PRIORITY]");
                // Require that free transactions have sufficient priority to be mined in the next block.
                context.State.Fail(MempoolErrors.InsufficientPriority).Throw();
            }

            if (context.State.AbsurdFee > 0 && context.Fees > context.State.AbsurdFee)
            {
                this.logger.LogTrace("(-)[INVALID_ABSURD_FEE]");
                context.State.Invalid(MempoolErrors.AbsurdlyHighFee, $"{context.Fees} > {context.State.AbsurdFee}")
                .Throw();
            }
        }
        public override void CheckTransaction(MempoolValidationContext context)
        {
            Guard.Assert(context.View != null);

            context.LockPoints = new LockPoints();

            // Do we already have it?
            if (context.View.HaveTransaction(context.TransactionHash))
            {
                this.logger.LogTrace("(-)[INVALID_ALREADY_KNOWN]");
                context.State.Invalid(MempoolErrors.AlreadyKnown).Throw();
            }

            // Do all inputs exist?
            // Note that this does not check for the presence of actual outputs (see the next check for that),
            // and only helps with filling in pfMissingInputs (to determine missing vs spent).
            foreach (TxIn txin in context.Transaction.Inputs)
            {
                if (!context.View.HaveCoins(txin.PrevOut))
                {
                    context.State.MissingInputs = true;
                    this.logger.LogTrace("(-)[FAIL_MISSING_INPUTS]");
                    context.State.Fail(MempoolErrors.MissingOrSpentInputs).Throw();
                }
            }
        }
 public override void CheckTransaction(MempoolValidationContext context)
 {
     if (!context.Transaction.HasWitness)
     {
         this.logger.LogTrace($"(-)[FAIL_{nameof(X1RequireWitnessMempoolRule)}]".ToUpperInvariant());
         X1ConsensusErrors.MissingWitness.Throw();
     }
 }
Пример #10
0
        public bool TestSequenceLocks(TestContext testContext, ChainedBlock chainedBlock, Transaction tx, Transaction.LockTimeFlags flags, LockPoints uselock = null)
        {
            var context = new MempoolValidationContext(tx, new MempoolValidationState(false));

            context.View = new MempoolCoinView(testContext.cachedCoinView, testContext.mempool, testContext.mempoolLock, null);
            context.View.LoadViewAsync(tx).GetAwaiter().GetResult();
            return(MempoolValidator.CheckSequenceLocks(testContext.network, chainedBlock, context, flags, uselock, false));
        }
Пример #11
0
        public bool TestSequenceLocks(TestContext testContext, ChainedHeader chainedHeader, Transaction tx, Transaction.LockTimeFlags flags, LockPoints uselock = null)
        {
            var context = new MempoolValidationContext(tx, new MempoolValidationState(false));

            context.View = new MempoolCoinView(this.network, testContext.cachedCoinView, testContext.mempool, testContext.mempoolLock, null);
            testContext.mempoolLock.ReadAsync(() => context.View.LoadViewLocked(tx)).GetAwaiter().GetResult();
            return(CreateMempoolEntryMempoolRule.CheckSequenceLocks(testContext.network, chainedHeader, context, flags, uselock, false));
        }
Пример #12
0
        public override void CheckTransaction(MempoolValidationContext context)
        {
            // Only accept BIP68 sequence locked transactions that can be mined in the next
            // block; we don't want our mempool filled up with transactions that can't
            // be mined yet.
            // Must keep pool.cs for this unless we change CheckSequenceLocks to take a
            // CoinsViewCache instead of create its own
            if (!CheckSequenceLocks(this.network, this.chainIndexer.Tip, context,
                                    MempoolValidator.StandardLocktimeVerifyFlags, context.LockPoints))
            {
                this.logger.LogTrace("(-)[FAIL_BIP68_SEQLOCK]");
                context.State.Fail(MempoolErrors.NonBIP68Final).Throw();
            }

            // Check for non-standard pay-to-script-hash in inputs
            if (this.settings.RequireStandard && !AreInputsStandard(this.network, context.Transaction, context.View))
            {
                this.logger.LogTrace("(-)[INVALID_NONSTANDARD_INPUTS]");
                context.State.Invalid(MempoolErrors.NonstandardInputs).Throw();
            }

            // Check for non-standard witness in P2WSH
            if (context.Transaction.HasWitness && this.settings.RequireStandard &&
                !IsWitnessStandard(context.Transaction, context.View))
            {
                this.logger.LogTrace("(-)[INVALID_NONSTANDARD_WITNESS]");
                context.State.Invalid(MempoolErrors.NonstandardWitness).Throw();
            }

            context.SigOpsCost = this.consensusRules.GetRule <CoinViewRule>()
                                 .GetTransactionSignatureOperationCost(context.Transaction, context.View.Set,
                                                                       new DeploymentFlags {
                ScriptFlags = ScriptVerify.Standard
            });

            var nValueIn = context.View.GetValueIn(context.Transaction);

            context.ValueOut = context.Transaction.TotalOut;
            context.Fees     = nValueIn - context.ValueOut;
            // nModifiedFees includes any fee deltas from PrioritiseTransaction
            var    nModifiedFees = context.Fees;
            double priorityDummy = 0;

            this.mempool.ApplyDeltas(context.TransactionHash, ref priorityDummy, ref nModifiedFees);
            context.ModifiedFees = nModifiedFees;

            (var dPriority, var inChainInputValue) =
                context.View.GetPriority(context.Transaction, this.chainIndexer.Height);

            // Keep track of transactions that spend a coinbase, which we re-scan
            // during reorgs to ensure COINBASE_MATURITY is still met.
            var spendsCoinbase = context.View.SpendsCoinBase(context.Transaction);

            context.Entry = new TxMempoolEntry(context.Transaction, context.Fees, context.State.AcceptTime, dPriority,
                                               this.chainIndexer.Height, inChainInputValue,
                                               spendsCoinbase, context.SigOpsCost, context.LockPoints, this.network.Consensus.Options);
            context.EntrySize = (int)context.Entry.GetTxSize();
        }
Пример #13
0
        /// <inheritdoc />
        public override void CheckFee(MempoolValidationContext context)
        {
            base.CheckFee(context);

            foreach (ISmartContractMempoolRule rule in feeTxRules)
            {
                rule.CheckTransaction(context);
            }
        }
        /// <inheritdoc />
        protected override void PreMempoolChecks(MempoolValidationContext context)
        {
            base.PreMempoolChecks(context);

            foreach (ISmartContractMempoolRule rule in this.preTxRules)
            {
                rule.CheckTransaction(context);
            }
        }
Пример #15
0
        /// <summary>
        /// Validates transaction inputs against transaction data for a specific script verify flag.
        /// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
        /// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
        /// instead of being performed inline.
        /// </summary>
        /// <param name="ruleContext">Current mempool rule context.</param>
        /// <param name="context">Current validation context.</param>
        /// <param name="scriptVerify">Script verify flag.</param>
        /// <param name="txData">Transaction data.</param>
        /// <returns>Whether inputs are valid.</returns>
        private bool CheckInputs(MempoolValidationContext context, ScriptVerify scriptVerify,
                                 PrecomputedTransactionData txData)
        {
            Transaction tx = context.Transaction;

            if (!context.Transaction.IsCoinBase)
            {
                this.consensusRuleEngine.GetRule <CoinViewRule>().CheckInputs(context.Transaction, context.View.Set, this.chainIndexer.Height + 1);

                for (int iInput = 0; iInput < tx.Inputs.Count; iInput++)
                {
                    TxIn  input    = tx.Inputs[iInput];
                    int   iiIntput = iInput;
                    TxOut txout    = context.View.GetOutputFor(input);

                    var checker = new TransactionChecker(tx, iiIntput, txout.Value, txData);
                    var ctx     = new ScriptEvaluationContext(this.network);
                    ctx.ScriptVerify = scriptVerify;
                    if (ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker))
                    {
                        this.logger.LogTrace("(-)[SCRIPT_VERIFIED]:true");
                        return(true);
                    }
                    else
                    {
                        //TODO:

                        //if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS)
                        //{
                        //  // Check whether the failure was caused by a
                        //  // non-mandatory script verification check, such as
                        //  // non-standard DER encodings or non-null dummy
                        //  // arguments; if so, don't trigger DoS protection to
                        //  // avoid splitting the network between upgraded and
                        //  // non-upgraded nodes.
                        //  CScriptCheck check2(*coins, tx, i,
                        //          flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
                        //  if (check2())
                        //      return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
                        //}
                        //// Failures of other flags indicate a transaction that is
                        //// invalid in new blocks, e.g. a invalid P2SH. We DoS ban
                        //// such nodes as they are not following the protocol. That
                        //// said during an upgrade careful thought should be taken
                        //// as to the correct behavior - we may want to continue
                        //// peering with non-upgraded nodes even after soft-fork
                        //// super-majority signaling has occurred.
                        this.logger.LogTrace("(-)[FAIL_SCRIPT_VERIFY]");
                        context.State.Fail(MempoolErrors.MandatoryScriptVerifyFlagFailed, ctx.Error.ToString()).Throw();
                    }
                }
            }

            return(true);
        }
Пример #16
0
        public override void CheckTransaction(MempoolValidationContext context)
        {
            context.SetConflicts = new List <uint256>();
            foreach (var txin in context.Transaction.Inputs)
            {
                var itConflicting = this.mempool.MapNextTx.Find(f => f.OutPoint == txin.PrevOut);
                if (itConflicting != null)
                {
                    var ptxConflicting = itConflicting.Transaction;
                    if (!context.SetConflicts.Contains(ptxConflicting.GetHash()))
                    {
                        // Allow opt-out of transaction replacement by setting
                        // nSequence >= maxint-1 on all inputs.
                        //
                        // maxint-1 is picked to still allow use of nLockTime by
                        // non-replaceable transactions. All inputs rather than just one
                        // is for the sake of multi-party protocols, where we don't
                        // want a single party to be able to disable replacement.
                        //
                        // The opt-out ignores descendants as anyone relying on
                        // first-seen mempool behavior should be checking all
                        // unconfirmed ancestors anyway; doing otherwise is hopelessly
                        // insecure.
                        var replacementOptOut = true;
                        if (this.settings.EnableReplacement)
                        {
                            foreach (var txiner in ptxConflicting.Inputs)
                            {
                                if (txiner.Sequence < Sequence.Final - 1)
                                {
                                    replacementOptOut = false;
                                    break;
                                }
                            }
                        }

                        if (replacementOptOut)
                        {
                            this.logger.LogTrace(
                                "New transaction '{0}' and existing mempool transaction '{1}' both consume the same PrevOut: '{2}-{3}'",
                                context.Transaction.GetHash(), ptxConflicting.GetHash(), txin.PrevOut.Hash,
                                txin.PrevOut.N);
                            this.logger.LogTrace("New transaction = {0}", context.Transaction.ToString(this.network));
                            this.logger.LogTrace("Old transaction = {0}", ptxConflicting.ToString(this.network));
                            this.logger.LogTrace("(-)[INVALID_CONFLICT]");
                            context.State.Invalid(MempoolErrors.Conflict).Throw();
                        }

                        context.SetConflicts.Add(ptxConflicting.GetHash());
                    }
                }
            }
        }
Пример #17
0
 public void CheckTransaction(MempoolValidationContext context)
 {
     // If wanting to execute a contract, we must be able to get the sender.
     if (context.Transaction.Outputs.Any(x => x.ScriptPubKey.IsSmartContractExec()))
     {
         GetSenderResult result = this.senderRetriever.GetSender(context.Transaction, context.View);
         if (!result.Success)
         {
             new ConsensusError("cant-get-sender", "smart contract output without a P2PKH as the first input to the tx.").Throw();
         }
     }
 }
Пример #18
0
        public void CheckTxOutDustRule_TxOut_Is_OpReturn_Pass()
        {
            var rule        = new CheckTxOutDustRule(this.network, this.txMempool, new MempoolSettings(this.nodeSettings), this.chainIndexer, this.loggerFactory);
            var transaction = CreateTransaction(Money.Coins(1), true);
            var mempoolValidationContext = new MempoolValidationContext(transaction, new MempoolValidationState(false))
            {
                MinRelayTxFee = this.nodeSettings.MinRelayTxFeeRate,
                ValueOut      = transaction.TotalOut
            };

            rule.CheckTransaction(mempoolValidationContext);
            Assert.Null(mempoolValidationContext.State.Error);
        }
Пример #19
0
 public override void CheckTransaction(MempoolValidationContext context)
 {
     // Check that the transaction doesn't have an excessive number of
     // sigops, making it impossible to mine. Since the coinbase transaction
     // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
     // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
     // merely non-standard transaction.
     if (context.SigOpsCost > this.network.Consensus.Options.MaxStandardTxSigopsCost)
     {
         this.logger.LogTrace("(-)[FAIL_TOO_MANY_SIGOPS]");
         context.State.Fail(MempoolErrors.TooManySigops).Throw();
     }
 }
Пример #20
0
        public void CheckTxOutDustRule_Fail()
        {
            var rule        = new CheckTxOutDustRule(this.network, this.txMempool, new MempoolSettings(this.nodeSettings), this.chainIndexer, this.loggerFactory);
            var transaction = CreateTransaction(Money.Coins(0.000001m));
            var mempoolValidationContext = new MempoolValidationContext(transaction, new MempoolValidationState(false))
            {
                MinRelayTxFee = this.nodeSettings.MinRelayTxFeeRate,
                ValueOut      = transaction.TotalOut
            };

            Assert.Throws <MempoolErrorException>(() => rule.CheckTransaction(mempoolValidationContext));
            Assert.NotNull(mempoolValidationContext.State.Error);
            Assert.Equal(MempoolErrors.TransactionContainsDustTxOuts, mempoolValidationContext.State.Error);
        }
        /// <inheritdoc/>
        public override void CheckTransaction(MempoolValidationContext context)
        {
            TxOut scTxOut = context.Transaction.TryGetSmartContractTxOut();

            if (scTxOut == null)
            {
                // No SC output to validate.
                return;
            }

            ContractTxData txData = ContractTransactionChecker.GetContractTxData(this.callDataSerializer, scTxOut);

            SmartContractFormatLogic.Check(txData, context.Fees);
        }
Пример #22
0
        public override void CheckTransaction(MempoolValidationContext context)
        {
            Debug.Assert(((X1Main)this.network).AbsoluteMinTxFee.HasValue);

            long consensusRejectFee = ((X1Main)this.network).AbsoluteMinTxFee.Value;

            if (context.Fees < consensusRejectFee)
            {
                this.logger.LogTrace("(-)[FAIL_ABSOLUTE_MIN_TX_FEE_NOT_MET]");
                context.State.Fail(MempoolErrors.MinFeeNotMet, $" {context.Fees} < {consensusRejectFee}").Throw();
            }

            // calling the base class here allows for customized behavior above the AbsoluteMinTxFee threshold.
            base.CheckTransaction(context);
        }
        /// <inheritdoc/>
        public override void CheckTransaction(MempoolValidationContext context)
        {
            TxOut scTxOut = context.Transaction.TryGetSmartContractTxOut();

            if (scTxOut == null)
            {
                // No SC output to validate.
                return;
            }

            ContractTxData txData = ContractTransactionChecker.GetContractTxData(this.callDataSerializer, scTxOut);

            // Delegate to full validation rule. The full validation rule will differ for PoA/PoS.
            this.contractTransactionFullValidationRule.CheckContractTransaction(txData, null, this.chainIndexer.Tip.Height);
        }
        /// <inheritdoc />
        public override void CheckTransaction(MempoolValidationContext context)
        {
            foreach (var txOut in context.Transaction.Outputs)
            {
                if (StandardTransactionPolicy.IsOpReturn(txOut.ScriptPubKey.ToBytes()))
                {
                    continue;
                }

                if (txOut.IsDust(context.MinRelayTxFee))
                {
                    this.logger.LogTrace("(-)[TX_CONTAINS_DUST_TXOUTS]");
                    context.State.Fail(MempoolErrors.TransactionContainsDustTxOuts, $"{context.Transaction.GetHash()} contains a dust TxOut {txOut.ScriptPubKey.ToString()}.").Throw();
                }
            }
        }
        /// <inheritdoc/>
        public override void CheckTransaction(MempoolValidationContext context)
        {
            if (context.Transaction.IsCoinBase || context.Transaction.IsCoinStake)
            {
                return;
            }

            // This will raise a consensus error if there is a voting request and it can't be decoded.
            JoinFederationRequest request = JoinFederationRequestBuilder.Deconstruct(context.Transaction, this.encoder);

            if (request == null)
            {
                return;
            }

            if (this.federationManager.IsMultisigMember(request.PubKey))
            {
                this.logger.LogTrace("(-)[INVALID_MULTISIG_VOTING]");
                context.State.Fail(MempoolErrors.VotingRequestInvalidMultisig, $"{context.Transaction.GetHash()} has an invalid voting request for a multisig member.").Throw();
            }

            // Check collateral amount.
            var collateralAmount = CollateralFederationMember.GetCollateralAmountForPubKey((PoANetwork)this.network, request.PubKey);

            if (request.CollateralAmount.ToDecimal(MoneyUnit.BTC) != collateralAmount)
            {
                this.logger.LogTrace("(-)[INVALID_COLLATERAL_REQUIREMENT]");
                context.State.Fail(MempoolErrors.InvalidCollateralRequirement, $"{context.Transaction.GetHash()} has a voting request with an invalid colateral requirement.").Throw();
            }

            if (!(this.federationManager is CollateralFederationManager federationManager))
            {
                return;
            }

            // Prohibit re-use of collateral addresses.
            Script script                    = PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(request.CollateralMainchainAddress);
            string collateralAddress         = script.GetDestinationAddress(this.network).ToString();
            CollateralFederationMember owner = federationManager.CollateralAddressOwner(this.votingManager, VoteKey.AddFederationMember, collateralAddress);

            if (owner != null && owner.PubKey != request.PubKey)
            {
                this.logger.LogTrace("(-)[INVALID_COLLATERAL_REUSE]");
                context.State.Fail(MempoolErrors.VotingRequestInvalidCollateralReuse, $"{context.Transaction.GetHash()} has a voting request that's re-using collateral.").Throw();
            }
        }
Пример #26
0
        public override void CheckTransaction(MempoolValidationContext context)
        {
            var scriptVerifyFlags = ScriptVerify.Standard;

            if (!this.settings.RequireStandard)
            {
                // TODO: implement -promiscuousmempoolflags
                // scriptVerifyFlags = GetArg("-promiscuousmempoolflags", scriptVerifyFlags);
            }

            // Check against previous transactions
            // This is done last to help prevent CPU exhaustion denial-of-service attacks.
            var txdata = new PrecomputedTransactionData(context.Transaction);

            if (!this.CheckInputs(context, scriptVerifyFlags, txdata))
            {
                // TODO: Implement Witness Code
                //// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
                //// need to turn both off, and compare against just turning off CLEANSTACK
                //// to see if the failure is specifically due to witness validation.
                //if (!tx.HasWitness() && CheckInputs(Trx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
                //  !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata))
                //{
                //  // Only the witness is missing, so the transaction itself may be fine.
                //  state.SetCorruptionPossible();
                //}

                this.logger.LogTrace("(-)[FAIL_INPUTS_PREV_TXS]");
                context.State.Fail(new MempoolError()).Throw();
            }

            // Check again against just the consensus-critical mandatory script
            // verification flags, in case of bugs in the standard flags that cause
            // transactions to pass as valid when they're actually invalid. For
            // instance the STRICTENC flag was incorrectly allowing certain
            // CHECKSIG NOT scripts to pass, even though they were invalid.
            //
            // There is a similar check in CreateNewBlock() to prevent creating
            // invalid blocks, however allowing such transactions into the mempool
            // can be exploited as a DoS attack.
            if (!this.CheckInputs(context, ScriptVerify.P2SH, txdata))
            {
                this.logger.LogTrace("(-)[FAIL_SCRIPT_VERIFY]");
                context.State.Fail(new MempoolError(), $"CheckInputs: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags {context.TransactionHash}").Throw();
            }
        }
        /// <summary>
        /// Validate the transaction is a standard transaction. Checks the version number, transaction size, input signature size,
        /// output script template, single output, & dust outputs.
        /// <seealso>
        ///     <cref>https://github.com/bitcoin/bitcoin/blob/aa624b61c928295c27ffbb4d27be582f5aa31b56/src/policy/policy.cpp##L82-L144</cref>
        /// </seealso>
        /// </summary>
        /// <remarks>Note that, unfortunately, this does not constitute everything that can be non-standard about a transaction.
        /// For example, there may be script verification flags that are not consensus-mandatory but are part of the standardness checks.
        /// These verify flags are checked elsewhere.</remarks>
        /// <param name="context">Current validation context.</param>
        private void CheckStandardTransaction(MempoolValidationContext context)
        {
            Transaction tx = context.Transaction;

            if (tx.Version > this.network.Consensus.Options.MaxStandardVersion || tx.Version < 1)
            {
                this.logger.LogTrace("(-)[FAIL_TX_VERSION]");
                context.State.Fail(MempoolErrors.Version).Throw();
            }

            int dataOut = 0;

            foreach (TxOut txOut in tx.Outputs)
            {
                // this rule runs very early in the validation pipeline, check basics as well.
                if (txOut?.ScriptPubKey == null || txOut.ScriptPubKey.Length < 1)
                {
                    this.logger.LogTrace("(-)[FAIL_EMPTY_SCRIPTPUBKEY]");
                    context.State.Fail(MempoolErrors.Scriptpubkey).Throw();
                }

                // Output checking is already implemented in the MainNetOutputNotWhitelistedRule
                // and MainNetOutputNotWhitelistedMempoolRule.

                // OP_RETURN
                byte[] raw = txOut.ScriptPubKey.ToBytes();
                if (raw[0] == (byte)OpcodeType.OP_RETURN)
                {
                    dataOut++;
                }

                if (txOut.IsDust(this.nodeSettings.MinRelayTxFeeRate))
                {
                    this.logger.LogTrace("(-)[FAIL_DUST]");
                    context.State.Fail(MempoolErrors.Dust).Throw();
                }
            }

            // Only one OP_RETURN txOut is permitted
            if (dataOut > 1)
            {
                this.logger.LogTrace("(-)[FAIL_MULTI_OPRETURN]");
                context.State.Fail(MempoolErrors.MultiOpReturn).Throw();
            }
        }
        public override void CheckTransaction(MempoolValidationContext context)
        {
            if (context.Transaction.IsCoinStake || (context.Transaction.IsCoinBase && context.Transaction.Outputs[0].IsEmpty)) // also check the coinbase tx in PoW blocks
            {
                return;
            }

            foreach (var output in context.Transaction.Outputs)
            {
                if (XdsOutputNotWhitelistedRule.IsOutputWhitelisted(output))
                {
                    continue;
                }

                this.logger.LogTrace($"(-)[FAIL_{nameof(XdsOutputNotWhitelistedMempoolRule)}]".ToUpperInvariant());
                context.State.Fail(new MempoolError(XdsConsensusErrors.OutputNotWhitelisted)).Throw();
            }
        }
Пример #29
0
        /// <seealso>https://github.com/bitcoin/bitcoin/blob/febf3a856bcfb8fef2cb4ddcb8d1e0cab8a22580/src/validation.cpp#L770</seealso>
        public override void CheckTransaction(MempoolValidationContext context)
        {
            // TODO: How should the RequireStandard setting interact with this?
            var scriptVerifyFlags = ScriptVerify.Standard;

            // Check against previous transactions.
            // This is done last to help prevent CPU exhaustion denial-of-service attacks.
            var txdata = new PrecomputedTransactionData(context.Transaction);

            if (!CheckInputs(context, scriptVerifyFlags, txdata))
            {
                // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
                // need to turn both off, and compare against just turning off CLEANSTACK
                // to see if the failure is specifically due to witness validation.
                if (!context.Transaction.HasWitness &&
                    CheckInputs(context, scriptVerifyFlags & ~(ScriptVerify.Witness | ScriptVerify.CleanStack),
                                txdata) && !CheckInputs(context, scriptVerifyFlags & ~ScriptVerify.CleanStack, txdata))
                {
                    // Only the witness is missing, so the transaction itself may be fine.
                    this.logger.LogTrace("(-)[FAIL_WITNESS_MUTATED]");
                    context.State.Fail(MempoolErrors.WitnessMutated).Throw();
                }

                this.logger.LogTrace("(-)[FAIL_INPUTS_PREV_TXS]");
                context.State.Fail(new MempoolError()).Throw();
            }

            // Check again against just the consensus-critical mandatory script verification flags, in case of bugs in the standard flags that cause
            // transactions to pass as valid when they're actually invalid. For instance the STRICTENC flag was incorrectly allowing certain
            // CHECKSIG NOT scripts to pass, even though they were invalid.
            //
            // There is a similar check during block creation to prevent creating invalid blocks, however allowing such transactions into the mempool
            // can be exploited as a DoS attack.

            var flags = this.nodeDeployments.GetFlags(this.chainIndexer.Tip);

            if (!CheckInputs(context, flags.ScriptFlags, txdata))
            {
                this.logger.LogTrace("(-)[FAIL_SCRIPT_VERIFY]");
                context.State.Fail(new MempoolError(),
                                   $"CheckInputs: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags {context.TransactionHash}")
                .Throw();
            }
        }
        private void CheckMinGasLimit(MempoolValidationContext context)
        {
            Transaction transaction = context.Transaction;

            if (!transaction.IsSmartContractExecTransaction())
            {
                return;
            }

            // We know it has passed SmartContractFormatRule so we can deserialize it easily.
            TxOut scTxOut = transaction.TryGetSmartContractTxOut();
            Result <ContractTxData> callDataDeserializationResult = this.callDataSerializer.Deserialize(scTxOut.ScriptPubKey.ToBytes());
            ContractTxData          callData = callDataDeserializationResult.Value;

            if (callData.GasPrice < MinGasPrice)
            {
                context.State.Fail(MempoolErrors.InsufficientFee, $"Gas price {callData.GasPrice} is below required price: {MinGasPrice}").Throw();
            }
        }