예제 #1
0
        public TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }

            spentCoins = spentCoins ?? new ICoin[0];

            List <TransactionPolicyError> errors = new List <TransactionPolicyError>();



            foreach (var input in transaction.Inputs.AsIndexedInputs())
            {
                var coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
                if (coin != null)
                {
                    if (ScriptVerify != null)
                    {
                        ScriptError error;
                        if (!VerifyScript(input, coin.TxOut.ScriptPubKey, coin.TxOut.Value, ScriptVerify.Value, out error))
                        {
                            errors.Add(new ScriptPolicyError(input, error, ScriptVerify.Value, coin.TxOut.ScriptPubKey));
                        }
                    }
                }

                var txin = input.TxIn;
                if (txin.ScriptSig.Length > MaxScriptSigLength)
                {
                    errors.Add(new InputPolicyError("Max scriptSig length exceeded actual is " + txin.ScriptSig.Length + ", max is " + MaxScriptSigLength, input));
                }
                if (!txin.ScriptSig.IsPushOnly)
                {
                    errors.Add(new InputPolicyError("All operation should be push", input));
                }
                if (!txin.ScriptSig.HasCanonicalPushes)
                {
                    errors.Add(new InputPolicyError("All operation should be canonical push", input));
                }
            }

            if (CheckScriptPubKey)
            {
                foreach (var txout in transaction.Outputs.AsCoins())
                {
                    var template = StandardScripts.GetTemplateFromScriptPubKey(txout.ScriptPubKey);
                    if (template == null)
                    {
                        errors.Add(new OutputPolicyError("Non-Standard scriptPubKey", (int)txout.Outpoint.N));
                    }
                }
            }

            int txSize = transaction.GetSerializedSize();

            if (MaxTransactionSize != null)
            {
                if (txSize >= MaxTransactionSize.Value)
                {
                    errors.Add(new TransactionSizePolicyError(txSize, MaxTransactionSize.Value));
                }
            }

            var fees = transaction.GetFee(spentCoins);

            if (fees != null)
            {
                if (CheckFee)
                {
                    if (MaxTxFee != null)
                    {
                        var max = MaxTxFee.GetFee(txSize);
                        if (fees > max)
                        {
                            errors.Add(new FeeTooHighPolicyError(fees, max));
                        }
                    }

                    if (MinRelayTxFee != null)
                    {
                        if (MinRelayTxFee != null)
                        {
                            var min = MinRelayTxFee.GetFee(txSize);
                            if (fees < min)
                            {
                                errors.Add(new FeeTooLowPolicyError(fees, min));
                            }
                        }
                    }
                }
            }
            if (MinRelayTxFee != null)
            {
                foreach (var output in transaction.Outputs)
                {
                    var bytes = output.ScriptPubKey.ToBytes(true);
                    if (output.IsDust(MinRelayTxFee) && !IsOpReturn(bytes))
                    {
                        errors.Add(new DustPolicyError(output.Value, output.GetDustThreshold(MinRelayTxFee)));
                    }
                }
            }
            var opReturnCount = transaction.Outputs.Select(o => o.ScriptPubKey.ToBytes(true)).Count(b => IsOpReturn(b));

            if (opReturnCount > 1)
            {
                errors.Add(new TransactionPolicyError("More than one op return detected"));
            }
            return(errors.ToArray());
        }
예제 #2
0
        public TransactionPolicyError[] Check(TransactionValidator validator)
        {
            if (validator == null)
            {
                throw new ArgumentNullException(nameof(validator));
            }
            var transaction = validator.Transaction;
            List <TransactionPolicyError> errors = new List <TransactionPolicyError>();

            foreach (var input in validator.Transaction.Inputs.AsIndexedInputs())
            {
                if (this.ScriptVerify is NBitcoin.ScriptVerify)
                {
                    ScriptError?error;
                    if (!VerifyScript(validator, (int)input.Index, out error) && error is ScriptError err)
                    {
                        errors.Add(new ScriptPolicyError(input, err, validator.ScriptVerify, validator.SpentOutputs[input.Index].ScriptPubKey));
                    }
                }
                var txin = input.TxIn;
                if (txin.ScriptSig.Length > MaxScriptSigLength)
                {
                    errors.Add(new InputPolicyError("Max scriptSig length exceeded actual is " + txin.ScriptSig.Length + ", max is " + MaxScriptSigLength, input));
                }
                if (!txin.ScriptSig.IsPushOnly)
                {
                    errors.Add(new InputPolicyError("All operation should be push", input));
                }
                if (!txin.ScriptSig.HasCanonicalPushes)
                {
                    errors.Add(new InputPolicyError("All operation should be canonical push", input));
                }
            }

            if (CheckScriptPubKey)
            {
                foreach (var txout in transaction.Outputs.AsCoins())
                {
                    if (!Strategy.IsStandardOutput(txout.TxOut))
                    {
                        errors.Add(new OutputPolicyError("Non-Standard scriptPubKey", (int)txout.Outpoint.N));
                    }
                }
            }

            int txSize = transaction.GetSerializedSize();

            if (MaxTransactionSize != null)
            {
                if (txSize >= MaxTransactionSize.Value)
                {
                    errors.Add(new TransactionSizePolicyError(txSize, MaxTransactionSize.Value));
                }
            }

            var fees = transaction.GetFee(validator.SpentOutputs);

            if (fees != null)
            {
                var virtualSize = transaction.GetVirtualSize();
                if (CheckFee)
                {
                    if (MaxTxFee != null)
                    {
                        var max = MaxTxFee.GetFee(virtualSize);
                        if (fees > max)
                        {
                            errors.Add(new FeeTooHighPolicyError(fees, max));
                        }
                    }

                    if (MinFee != null)
                    {
                        if (fees < MinFee)
                        {
                            errors.Add(new FeeTooLowPolicyError(fees, MinFee));
                        }
                    }

                    if (MinRelayTxFee != null)
                    {
                        if (MinRelayTxFee != null)
                        {
                            var min = MinRelayTxFee.GetFee(virtualSize);
                            if (fees < min)
                            {
                                errors.Add(new FeeTooLowPolicyError(fees, min));
                            }
                        }
                    }
                }
            }
            if (CheckDust)
            {
                foreach (var output in transaction.Outputs)
                {
                    var bytes = output.ScriptPubKey.ToBytes(true);
                    if (output.IsDust() && !IsOpReturn(bytes))
                    {
                        errors.Add(new DustPolicyError(output.Value, output.GetDustThreshold()));
                    }
                }
            }
            var opReturnCount = transaction.Outputs.Select(o => o.ScriptPubKey.ToBytes(true)).Count(b => IsOpReturn(b));

            if (opReturnCount > 1)
            {
                errors.Add(new TransactionPolicyError("More than one op return detected"));
            }
            return(errors.ToArray());
        }