Beispiel #1
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);
        }
Beispiel #2
0
        public static ScriptSigs CombineSignatures(Script scriptPubKey, TransactionChecker checker, ScriptSigs input1, ScriptSigs input2)
        {
            if (scriptPubKey == null)
            {
                scriptPubKey = new Script();
            }

            var         scriptSig1  = input1.ScriptSig;
            var         scriptSig2  = input2.ScriptSig;
            HashVersion hashVersion = HashVersion.Original;
            var         isWitness   = input1.WitSig != WitScript.Empty || input2.WitSig != WitScript.Empty;

            if (isWitness)
            {
                scriptSig1  = input1.WitSig.ToScript();
                scriptSig2  = input2.WitSig.ToScript();
                hashVersion = HashVersion.Witness;
            }

            var context = new ScriptEvaluationContext();

            context.ScriptVerify = ScriptVerify.StrictEnc;
            context.EvalScript(scriptSig1, checker, hashVersion);

            var stack1 = context.Stack.AsInternalArray();

            context = new ScriptEvaluationContext();
            context.ScriptVerify = ScriptVerify.StrictEnc;
            context.EvalScript(scriptSig2, checker, hashVersion);

            var stack2 = context.Stack.AsInternalArray();
            var result = CombineSignatures(scriptPubKey, checker, stack1, stack2, hashVersion);

            if (result == null)
            {
                return(scriptSig1.Length < scriptSig2.Length ? input2 : input1);
            }
            if (!isWitness)
            {
                return new ScriptSigs()
                       {
                           ScriptSig = result,
                           WitSig    = WitScript.Empty
                       }
            }
            ;
            else
            {
                return(new ScriptSigs()
                {
                    ScriptSig = input1.ScriptSig.Length < input2.ScriptSig.Length ? input2.ScriptSig : input1.ScriptSig,
                    WitSig = new WitScript(result)
                });
            }
        }
Beispiel #3
0
        private void Code16()
        {
            BitcoinAddress address      = new BitcoinPubKeyAddress("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var            birth        = Encoding.UTF8.GetBytes("18/07/1988");
            var            birthHash    = Hashes.Hash256(birth);
            Script         redeemScript = new Script(
                "OP_IF "
                + "OP_HASH256 " + Op.GetPushOp(birthHash.ToBytes()) + " OP_EQUAL " +
                "OP_ELSE "
                + address.ScriptPubKey + " " +
                "OP_ENDIF");

            var tx = new Transaction();

            tx.Outputs.Add(new TxOut(Money.Parse("0.0001"), redeemScript.Hash));
            ScriptCoin scriptCoin = tx.Outputs.AsCoins().First().ToScriptCoin(redeemScript);

            //Create spending transaction
            Transaction spending = new Transaction();

            spending.AddInput(new TxIn(new OutPoint(tx, 0)));

            ////Option 1 : Spender knows my birthdate
            ScriptEvaluationContext eval = new ScriptEvaluationContext();
            Op     pushBirthdate         = Op.GetPushOp(birth);
            Op     selectIf    = OpcodeType.OP_1; //go to if
            Op     redeemBytes = Op.GetPushOp(redeemScript.ToBytes());
            Script scriptSig   = new Script(pushBirthdate, selectIf, redeemBytes);

            spending.Inputs[0].ScriptSig = scriptSig;

            //Verify the script pass
            var result = eval.VerifyScript(scriptSig, tx.Outputs[0].ScriptPubKey, spending, 0, null);

            Console.WriteLine(result);
            ///////////

            ////Option 2 : Spender knows my private key
            eval = new ScriptEvaluationContext();
            BitcoinSecret secret     = new BitcoinSecret("...");
            var           sig        = spending.SignInput(secret.PrivateKey, scriptCoin);
            var           p2pkhProof = PayToPubkeyHashTemplate
                                       .Instance
                                       .GenerateScriptSig(sig, secret.PrivateKey.PubKey);

            selectIf  = OpcodeType.OP_0; //go to else
            scriptSig = p2pkhProof + selectIf + redeemBytes;
            spending.Inputs[0].ScriptSig = scriptSig;

            //Verify the script pass
            result = eval.VerifyScript(scriptSig, tx.Outputs[0].ScriptPubKey, spending, 0, null);
            Console.WriteLine(result);
            ///////////
        }
Beispiel #4
0
        public static bool IsCanonicalBlockSignature(Block block, bool checkLowS)
        {
            if (BlockStake.IsProofOfWork(block))
            {
                return(block.BlockSignatur.IsEmpty());
            }

            return(checkLowS ?
                   ScriptEvaluationContext.IsLowDerSignature(block.BlockSignatur.Signature) :
                   ScriptEvaluationContext.IsValidSignatureEncoding(block.BlockSignatur.Signature));
        }
Beispiel #5
0
        public static bool VerifyScript(Script scriptSig, Script scriptPubKey, Transaction tx, int i, Money value, ScriptVerify scriptVerify, SigHash sigHash, out ScriptError error)
        {
            var eval = new ScriptEvaluationContext
            {
                SigHash      = sigHash,
                ScriptVerify = scriptVerify
            };
            var result = eval.VerifyScript(scriptSig, scriptPubKey, tx, i, value);

            error = eval.Error;
            return(result);
        }
        /// <inheritdoc/>
        protected override bool CheckInput(Transaction tx, int inputIndexCopy, TxOut txout, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)
        {
            if (txout.ScriptPubKey.IsSmartContractExec() || txout.ScriptPubKey.IsSmartContractInternalCall())
            {
                return(input.ScriptSig.IsSmartContractSpend());
            }

            var checker = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
            var ctx     = new ScriptEvaluationContext(this.Parent.Network);

            ctx.ScriptVerify = flags.ScriptFlags;
            return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
        }
        /// <summary>
        /// Verify that an input may be validly spent as part of the given transaction in the given block.
        /// </summary>
        /// <param name="tx">Transaction to check.</param>
        /// <param name="inputIndexCopy">Index of the input to check.</param>
        /// <param name="txout">Output the input is spending.</param>
        /// <param name="txData">Transaction data for the transaction being checked.</param>
        /// <param name="input">Input to check.</param>
        /// <param name="flags">Deployment flags</param>
        /// <returns>Whether the input is valid.</returns>
        protected virtual bool CheckInput(Transaction tx, int inputIndexCopy, TxOut txout, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)
        {
            var checker = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
            var ctx     = new ScriptEvaluationContext(this.Parent.Network);

            ctx.ScriptVerify = flags.ScriptFlags;
            bool verifyScriptResult = ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker);

            if (verifyScriptResult == false)
            {
                this.Logger.LogTrace("Verify script for transaction '{0}' failed, ScriptSig = '{1}', ScriptPubKey = '{2}', script evaluation error = '{3}'", tx.GetHash(), input.ScriptSig, txout.ScriptPubKey, ctx.Error);
            }

            return(verifyScriptResult);
        }
Beispiel #8
0
        public static bool CheckBlockSignature(Block block)
        {
            if (block.IsProofOfWork())
            {
                return(block.BlockSignatur.IsEmpty());
            }

            if (block.BlockSignatur.IsEmpty())
            {
                return(false);
            }

            var txout = block.Transactions[1].Outputs[1];

            if (PayToPubkeyTemplate.Instance.CheckScriptPubKey(txout.ScriptPubKey))
            {
                var pubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(txout.ScriptPubKey);
                return(pubKey.Verify(block.GetHash(), new ECDSASignature(block.BlockSignatur.Signature)));
            }

            if (IsProtocolV3((int)block.Header.Time))
            {
                // Block signing key also can be encoded in the nonspendable output
                // This allows to not pollute UTXO set with useless outputs e.g. in case of multisig staking

                var ops = txout.ScriptPubKey.ToOps().ToList();
                if (!ops.Any())                 // script.GetOp(pc, opcode, vchPushValue))
                {
                    return(false);
                }
                if (ops.ElementAt(0).Code != OpcodeType.OP_RETURN)                 // OP_RETURN)
                {
                    return(false);
                }
                if (ops.Count < 2)                 // script.GetOp(pc, opcode, vchPushValue)
                {
                    return(false);
                }
                var data = ops.ElementAt(1).PushData;
                if (!ScriptEvaluationContext.IsCompressedOrUncompressedPubKey(data))
                {
                    return(false);
                }
                return(new PubKey(data).Verify(block.GetHash(), new ECDSASignature(block.BlockSignatur.Signature)));
            }

            return(false);
        }
Beispiel #9
0
        public static bool VerifyScript(Script scriptSig, Transaction tx, int i, TxOut spentOutput, ScriptVerify scriptVerify, SigHash sigHash, out ScriptError error)
        {
            if (spentOutput == null)
            {
                throw new ArgumentNullException(nameof(spentOutput));
            }
            var eval = new ScriptEvaluationContext
            {
                SigHash      = sigHash,
                ScriptVerify = scriptVerify
            };
            var result = eval.VerifyScript(scriptSig, tx, i, spentOutput);

            error = eval.Error;
            return(result);
        }
        /// <inheritdoc/>
        public bool VerifySignature(UnspentOutput coin, Transaction txTo, int txToInN, ScriptVerify flagScriptVerify)
        {
            Guard.NotNull(coin, nameof(coin));
            Guard.NotNull(txTo, nameof(txTo));

            if (txToInN < 0 || txToInN >= txTo.Inputs.Count)
            {
                return(false);
            }

            TxIn input = txTo.Inputs[txToInN];

            //if (input.PrevOut.N >= coin.Outputs.Length)
            //{
            //    this.logger.LogTrace("(-)[OUTPUT_INCORRECT_LENGTH]");
            //    return false;
            //}

            //if (input.PrevOut.Hash != coin.TransactionId)
            if (input.PrevOut.Hash != coin.OutPoint.Hash)
            {
                this.logger.LogTrace("(-)[INCORRECT_TX]");
                return(false);
            }

            TxOut output = coin.Coins.TxOut;//.Outputs[input.PrevOut.N];

            if (output == null)
            {
                this.logger.LogTrace("(-)[OUTPUT_NOT_FOUND]");
                return(false);
            }

            var txData  = new PrecomputedTransactionData(txTo);
            var checker = new TransactionChecker(txTo, txToInN, output.Value, txData);
            var ctx     = new ScriptEvaluationContext(this.chainIndexer.Network)
            {
                ScriptVerify = flagScriptVerify
            };

            bool res = ctx.VerifyScript(input.ScriptSig, output.ScriptPubKey, checker);

            return(res);
        }
Beispiel #11
0
		/// <summary>
		/// Check if valid transaction signature
		/// </summary>
		/// <param name="sig">The signature</param>
		/// <param name="scriptVerify">Verification rules</param>
		/// <param name="error">Error</param>
		/// <returns>True if valid</returns>
		public static bool IsValid(byte[] sig, ScriptVerify scriptVerify, out ScriptError error)
		{
			if(sig == null)
				throw new ArgumentNullException("sig");
			if(sig.Length == 0)
			{
				error = ScriptError.SigDer;
				return false;
			}
			error = ScriptError.OK;
			var ctx = new ScriptEvaluationContext()
			{
				ScriptVerify = scriptVerify
			};
			if(!ctx.CheckSignatureEncoding(sig))
			{
				error = ctx.Error;
				return false;
			}
			return true;
		}
Beispiel #12
0
        public static bool IsCanonicalBlockSignature(PosBlock block, bool checkLowS)
        {
            if (BlockStake.IsProofOfWork(block))
            {
                return(block.BlockSignature.IsEmpty());
            }

            // A signature should have only one representation, or malleability vectors are introduced.
            // Therefore, an ECDSA signature, per BIP66, must be in strict DER encoding.
            // Additionally, the 'S' value of the signature must be the lower of the two possible values.

            // Recall that, for an ECDSA signature, the R and S values are both modulo N (aka the curve order).
            // Further, a signature (R, S) is equivalent to (R, -S mod N).

            // In other words there are always 2 valid S values, call them S and S'.

            // A small example of why S + S' = N:
            // N = 7
            // S = 4
            // ((N - S) % N) = 3 = S', therefore S + S' = 7 = N

            // Given S + S' = N, there will always be one S value greater than half the curve order
            // (N / 2), and one less than this.
            // The canonical signature is required to use the so-called 'low S' value, the one less than N / 2.

            // Therefore to get the other S' value (the complement) we calculate S' = N - S.

            // We can switch between the canonical and non-canonical form by calculating the complement of
            // whichever representation we currently have in a signature.

            // Using N + S will give a valid signature too, but will not give the complement, as (N + S) mod N = S.

            // For POS blocks that have a signature we do not append a SIGHASH type at the end of the signature.
            // Therefore IsValidSignatureEncoding should be called with haveSigHash = false when validating
            // POS blocks.

            return(checkLowS
                ? ScriptEvaluationContext.IsLowDerSignature(block.BlockSignature.Signature, false)
                : ScriptEvaluationContext.IsValidSignatureEncoding(block.BlockSignature.Signature, false));
        }
        /// <summary>
        /// Verifies transaction's signature.
        /// </summary>
        /// <param name="coin">UTXO that is spent in the transaction.</param>
        /// <param name="txTo">Transaction.</param>
        /// <param name="txToInN">Index of the transaction's input.</param>
        /// <param name="flagScriptVerify">Script verification flags.</param>
        /// <returns><c>true</c> if signature is valid.</returns>
        private bool VerifySignature(UnspentOutputs coin, Transaction txTo, int txToInN, ScriptVerify flagScriptVerify)
        {
            this.logger.LogTrace("({0}:'{1}/{2}',{3}:{4},{5}:{6})", nameof(coin), coin.TransactionId, coin.Height, nameof(txToInN), txToInN, nameof(flagScriptVerify), flagScriptVerify);

            TxIn input = txTo.Inputs[txToInN];

            if (input.PrevOut.N >= coin.Outputs.Length)
                return false;

            if (input.PrevOut.Hash != coin.TransactionId)
                return false;

            TxOut output = coin.Outputs[input.PrevOut.N];

            var txData = new PrecomputedTransactionData(txTo);
            var checker = new TransactionChecker(txTo, txToInN, output.Value, txData);
            var ctx = new ScriptEvaluationContext(this.chain.Network) { ScriptVerify = flagScriptVerify };

            bool res = ctx.VerifyScript(input.ScriptSig, output.ScriptPubKey, checker);
            this.logger.LogTrace("(-):{0}", res);
            return res;
        }
Beispiel #14
0
        public static ScriptSigs CombineSignatures(Script scriptPubKey, TransactionChecker checker, ScriptSigs input1,
                                                   ScriptSigs input2)
        {
            if (scriptPubKey == null)
            {
                scriptPubKey = new Script();
            }

            var scriptSig1 = input1.ScriptSig;
            var scriptSig2 = input2.ScriptSig;

            var context = new ScriptEvaluationContext {
                ScriptVerify = ScriptVerify.StrictEnc
            };

            context.EvalScript(scriptSig1, checker);

            var stack1 = context.Stack.AsInternalArray();

            context = new ScriptEvaluationContext {
                ScriptVerify = ScriptVerify.StrictEnc
            };
            context.EvalScript(scriptSig2, checker);

            var stack2 = context.Stack.AsInternalArray();
            var result = CombineSignatures(scriptPubKey, checker, stack1, stack2);

            if (result == null)
            {
                return(scriptSig1.Length < scriptSig2.Length ? input2 : input1);
            }

            return(new ScriptSigs
            {
                ScriptSig = result
            });
        }
        /// <summary>
        /// Check if valid transaction signature
        /// </summary>
        /// <param name="sig">The signature</param>
        /// <param name="scriptVerify">Verification rules</param>
        /// <param name="error">Error</param>
        /// <returns>True if valid</returns>
        public static bool IsValid(byte[] sig, ScriptVerify scriptVerify, out ScriptError error)
        {
            if (sig == null)
            {
                throw new ArgumentNullException("sig");
            }
            if (sig.Length == 0)
            {
                error = ScriptError.SigDer;
                return(false);
            }
            error = ScriptError.OK;
            var ctx = new ScriptEvaluationContext()
            {
                ScriptVerify = scriptVerify
            };

            if (!ctx.CheckSignatureEncoding(sig))
            {
                error = ctx.Error;
                return(false);
            }
            return(true);
        }
        private bool VerifySignature(UnspentOutputs txFrom, Transaction txTo, int txToInN, ScriptVerify flagScriptVerify)
        {
            var input = txTo.Inputs[txToInN];

            if (input.PrevOut.N >= txFrom._Outputs.Length)
            {
                return(false);
            }

            if (input.PrevOut.Hash != txFrom.TransactionId)
            {
                return(false);
            }

            var output = txFrom._Outputs[input.PrevOut.N];

            var txData  = new PrecomputedTransactionData(txTo);
            var checker = new TransactionChecker(txTo, txToInN, output.Value, txData);
            var ctx     = new ScriptEvaluationContext {
                ScriptVerify = flagScriptVerify
            };

            return(ctx.VerifyScript(input.ScriptSig, output.ScriptPubKey, checker));
        }
Beispiel #17
0
		void ReplaceRedeemScript(TxIn input, Script redeemScript)
		{
			ScriptEvaluationContext ctx = new ScriptEvaluationContext();
			ctx.ScriptVerify = ScriptVerify.StrictEnc;
			ctx.EvalScript(input.ScriptSig, new Transaction(), 0);
			var stack = ctx.Stack;
			Assert.True(stack.Count > 0);
			stack.Pop();
			stack.Push(redeemScript.ToBytes());
			input.ScriptSig = PushAll(stack);
		}
Beispiel #18
0
		void CheckWithFlag(Transaction output, Transaction input, ScriptVerify flags, bool success)
		{
			Transaction inputi = input.Clone();
			ScriptEvaluationContext ctx = new ScriptEvaluationContext();
			ctx.ScriptVerify = flags;
			bool ret = ctx.VerifyScript(inputi.Inputs[0].ScriptSig, output.Outputs[0].ScriptPubKey, new TransactionChecker(inputi, 0, output.Outputs[0].Value));
			Assert.True(ret == success);
		}
        /// <inheritdoc />
        public async override Task RunAsync(RuleContext context)
        {
            this.Logger.LogTrace("()");

            this.blockTxsProcessed = new List <Transaction>();
            NBitcoin.Block   block = context.ValidationContext.Block;
            ChainedHeader    index = context.ValidationContext.ChainedHeader;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = ((UtxoRuleContext)context).UnspentOutputSet;

            this.Parent.PerformanceCounter.AddProcessedBlocks(1);

            // Start state from previous block's root
            this.ContractCoinviewRule.OriginalStateRoot.SyncToRoot(((SmartContractBlockHeader)context.ConsensusTip.Header).HashStateRoot.ToBytes());
            IContractState trackedState = this.ContractCoinviewRule.OriginalStateRoot.StartTracking();

            this.receipts = new List <Receipt>();

            this.refundCounter = 1;
            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.Parent.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.SkipValidation)
                {
                    if (!this.IsProtocolTransaction(tx))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!this.IsProtocolTransaction(tx))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.Parent.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                if (txout.ScriptPubKey.IsSmartContractExec() || txout.ScriptPubKey.IsSmartContractInternalCall())
                                {
                                    return(input.ScriptSig.IsSmartContractSpend());
                                }

                                var checker      = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                var ctx          = new ScriptEvaluationContext(this.Parent.Network);
                                ctx.ScriptVerify = flags.ScriptFlags;
                                return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                            });

                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);

                this.blockTxsProcessed.Add(tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            if (new uint256(this.ContractCoinviewRule.OriginalStateRoot.Root) != ((SmartContractBlockHeader)block.Header).HashStateRoot)
            {
                SmartContractConsensusErrors.UnequalStateRoots.Throw();
            }

            ValidateAndStoreReceipts(((SmartContractBlockHeader)block.Header).ReceiptRoot);

            this.ContractCoinviewRule.OriginalStateRoot.Commit();

            this.Logger.LogTrace("(-)");
        }
Beispiel #20
0
		private static Script CombineMultisig(Script scriptPubKey, Transaction transaction, int n, byte[][] sigs1, byte[][] sigs2)
		{
			// Combine all the signatures we've got:
			List<TransactionSignature> allsigs = new List<TransactionSignature>();
			foreach(var v in sigs1)
			{
				if(TransactionSignature.IsValid(v))
				{
					allsigs.Add(new TransactionSignature(v));
				}
			}


			foreach(var v in sigs2)
			{
				if(TransactionSignature.IsValid(v))
				{
					allsigs.Add(new TransactionSignature(v));
				}
			}

			var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
			if(multiSigParams == null)
				throw new InvalidOperationException("The scriptPubKey is not a valid multi sig");

			Dictionary<PubKey, TransactionSignature> sigs = new Dictionary<PubKey, TransactionSignature>();

			foreach(var sig in allsigs)
			{
				foreach(var pubkey in multiSigParams.PubKeys)
				{
					if(sigs.ContainsKey(pubkey))
						continue; // Already got a sig for this pubkey

					ScriptEvaluationContext eval = new ScriptEvaluationContext();
					if(eval.CheckSig(sig.ToBytes(), pubkey.ToBytes(), scriptPubKey, transaction, n))
					{
						sigs.AddOrReplace(pubkey, sig);
					}
				}
			}


			// Now build a merged CScript:
			int nSigsHave = 0;
			Script result = new Script(OpcodeType.OP_0); // pop-one-too-many workaround
			foreach(var pubkey in multiSigParams.PubKeys)
			{
				if(sigs.ContainsKey(pubkey))
				{
					result += Op.GetPushOp(sigs[pubkey].ToBytes());
					nSigsHave++;
				}
				if(nSigsHave >= multiSigParams.SignatureCount)
					break;
			}

			// Fill any missing with OP_0:
			for(int i = nSigsHave ; i < multiSigParams.SignatureCount ; i++)
				result += OpcodeType.OP_0;

			return result;
		}
Beispiel #21
0
		public static bool VerifyScript(Script scriptSig, Script scriptPubKey, Transaction tx, int i, ScriptVerify scriptVerify, SigHash sigHash, out ScriptError error)
		{
			var eval = new ScriptEvaluationContext
			{
				SigHash = sigHash,
				ScriptVerify = scriptVerify
			};
			var result = eval.VerifyScript(scriptSig, scriptPubKey, tx, i);
			error = eval.Error;
			return result;
		}
Beispiel #22
0
        /// <summary>
        /// Checks if block signature is valid.
        /// </summary>
        /// <param name="block">The block.</param>
        /// <returns><c>true</c> if the signature is valid, <c>false</c> otherwise.</returns>
        private bool CheckBlockSignature(PosBlock block)
        {
            if (BlockStake.IsProofOfWork(block))
            {
                bool res = block.BlockSignature.IsEmpty();
                this.Logger.LogTrace("(-)[POW]:{0}", res);
                return(res);
            }

            if (block.BlockSignature.IsEmpty())
            {
                this.Logger.LogTrace("(-)[EMPTY]:false");
                return(false);
            }

            TxOut txout = block.Transactions[1].Outputs[1];

            if (PayToPubkeyTemplate.Instance.CheckScriptPubKey(txout.ScriptPubKey))
            {
                PubKey pubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(txout.ScriptPubKey);
                bool   res    = pubKey.Verify(block.GetHash(), new ECDSASignature(block.BlockSignature.Signature));
                this.Logger.LogTrace("(-)[P2PK]:{0}", res);
                return(res);
            }

            // Block signing key also can be encoded in the nonspendable output.
            // This allows to not pollute UTXO set with useless outputs e.g. in case of multisig staking.

            List <Op> ops = txout.ScriptPubKey.ToOps().ToList();

            if (!ops.Any()) // script.GetOp(pc, opcode, vchPushValue))
            {
                this.Logger.LogTrace("(-)[NO_OPS]:false");
                return(false);
            }

            if (ops.ElementAt(0).Code != OpcodeType.OP_RETURN) // OP_RETURN)
            {
                this.Logger.LogTrace("(-)[NO_OP_RETURN]:false");
                return(false);
            }

            if (ops.Count != 2)
            {
                this.Logger.LogTrace("(-)[INVALID_OP_COUNT]:false");
                return(false);
            }

            byte[] data = ops.ElementAt(1).PushData;

            if (data.Length > MaxPushDataSize)
            {
                this.Logger.LogTrace("(-)[PUSH_DATA_TOO_LARGE]:false");
                return(false);
            }

            if (!ScriptEvaluationContext.IsCompressedOrUncompressedPubKey(data))
            {
                this.Logger.LogTrace("(-)[NO_PUSH_DATA]:false");
                return(false);
            }

            bool verifyRes = new PubKey(data).Verify(block.GetHash(), new ECDSASignature(block.BlockSignature.Signature));

            return(verifyRes);
        }
Beispiel #23
0
 public static bool VerifyScript(Script scriptSig, Script scriptPubKey, Transaction tx, int i, ScriptVerify scriptVerify = ScriptVerify.StrictEnc | ScriptVerify.P2SH, SigHash sigHash = SigHash.Undefined)
 {
     ScriptEvaluationContext eval = new ScriptEvaluationContext();
     eval.SigHash = sigHash;
     eval.ScriptVerify = scriptVerify;
     return eval.VerifyScript(scriptSig, scriptPubKey, tx, i);
 }
Beispiel #24
0
        /// <inheritdoc />
        public virtual void ExecuteBlock(RuleContext context, TaskScheduler taskScheduler = null)
        {
            this.logger.LogTrace("()");

            Block            block = context.BlockValidationContext.Block;
            ChainedBlock     index = context.BlockValidationContext.ChainedBlock;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = context.Set;

            this.PerformanceCounter.AddProcessedBlocks(1);
            taskScheduler = taskScheduler ?? TaskScheduler.Default;

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.SkipValidation)
                {
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        int[] prevheights;

                        if (!view.HaveInputs(tx))
                        {
                            this.logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    // TODO: Simplify this condition.
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                var checker      = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                var ctx          = new ScriptEvaluationContext();
                                ctx.ScriptVerify = flags.ScriptFlags;
                                return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                            });
                            checkInput.Start(taskScheduler);
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                bool passed = checkInputs.All(c => c.GetAwaiter().GetResult());
                if (!passed)
                {
                    this.logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            this.logger.LogTrace("(-)");
        }
Beispiel #25
0
        public static void Play()
        {
            var tx2 = new Transaction("010000000188932931d6bc23d3182183ab5e9707980ab4aaf9db3c6d3be42e5c0ce783b0ba00000000844730440220100aaa46e8a4f9d4589f935f5457f263a911f3712ee50688732c1274face6bb30220155b48760fd6ffbc0842761db03d824954567e8cd499883318d1f1c705f7d4d7012103dccb6bd324ae3c60afb85d9a0e5f300284faf2d71c40dbb7732d8fa79ee930f71976a914edc80be0e4f342a54a4fbe6e31e8e58b6849972a88acffffffff02204e0000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac70110100000000001976a914edc80be0e4f342a54a4fbe6e31e8e58b6849972a88ac00000000");

            var oo = tx2.GetHash();


            var scriptPubKey             = new Script(Encoders.Hex.DecodeData("a91467c205a82218e3b1327095f1e10dd676c6ce09df87"));
            ScriptEvaluationContext eval = new ScriptEvaluationContext();

            var result = eval.VerifyScript(tx2.Inputs[0].ScriptSig, scriptPubKey, tx2, 0);



            CancellationTokenSource s1 = new CancellationTokenSource();
            CancellationTokenSource s2 = new CancellationTokenSource(TimeSpan.FromSeconds(1));

            try
            {
                Thread.Sleep(3000);
                CancellationTokenSource.CreateLinkedTokenSource(s1.Token, s2.Token).Token.ThrowIfCancellationRequested();
            }
            catch (OperationCanceledException ex)
            {
                bool a = s2.Token == ex.CancellationToken;
            }

            //1,132

            //NodeServer server = new NodeServer(Network.Main);
            //server.RegisterPeerTableRepository(new SqLitePeerTableRepository("PeerCachePlay"));
            //server.BuildChain(new StreamObjectStream<ChainChange>(File.Open("MainChain.dat", FileMode.OpenOrCreate)));

            var from = new DateTimeOffset(new DateTime(2012, 12, 1));
            var to   = new DateTimeOffset(new DateTime(2013, 1, 20));

            var chain  = new Chain(new StreamObjectStream <ChainChange>(File.Open("MainChain.dat", FileMode.OpenOrCreate)));
            var blocks =
                chain.ToEnumerable(false)
                .SkipWhile(c => c.Header.BlockTime < from)
                .TakeWhile(c => c.Header.BlockTime < to)
                .ToArray();

            //index.ReIndex();
            //Console.WriteLine("");


            BlockStore        store = new BlockStore("E:\\Bitcoin\\blocks", Network.Main);
            IndexedBlockStore index = new IndexedBlockStore(new SQLiteNoSqlRepository("PlayIndex"), store);
            var target = Money.Parse("1100");
            var margin = Money.Parse("1");
            var dest   = Network.CreateFromBase58Data <BitcoinAddress>("1FrtkNXastDoMAaorowys27AKQERxgmZjY");
            var en     = new CultureInfo("en-US");

            FileStream fs     = File.Open("logs", FileMode.Create);
            var        writer = new StreamWriter(fs);

            writer.WriteLine("time,height,txid,value");

            var lines = from header in blocks
                        let block = index.Get(header.HashBlock)
                                    from tx in block.Transactions
                                    from txout in tx.Outputs
                                    //where txout.ScriptPubKey.GetDestination() == dest.ID
                                    where target - margin < txout.Value && txout.Value < target + margin
                                    select new
            {
                Block       = block,
                Height      = header.Height,
                Transaction = tx,
                TxOut       = txout
            };

            foreach (var line in lines)
            {
                writer.WriteLine(
                    line.Block.Header.BlockTime.ToString(en) + "," +
                    line.Height + "," +
                    line.Transaction.GetHash() + "," +
                    line.TxOut.Value.ToString());
            }
            writer.Flush();
            Process.Start(@"E:\Chocolatey\lib\notepadplusplus.commandline.6.4.5\tools\notepad++.exe", "\"" + new FileInfo(fs.Name).FullName + "\"");

            //foreach(var b in blocks)
            //{
            //	var block = index.Get(b.HashBlock);
            //	foreach(var tx in block.Transactions)
            //	{
            //		foreach(var txout in tx.Outputs)
            //		{
            //			var pa = new PayToPubkeyHashTemplate()
            //					.ExtractScriptPubKeyParameters(txout.ScriptPubKey);
            //			if(pa != null && pa == dest.ID)
            //			{
            //				if(target - margin < txout.Value && txout.Value < target + margin)
            //				{
            //					writer.WriteLine(b.Header.BlockTime.ToString(en) + "," + b.Height + "," + tx.GetHash() + "," + txout.Value.ToString());
            //				}
            //			}
            //		}
            //	}

            //}

            //They were purchased anonymously at a restaurant halfway between Sandwich, IL, and Chicago, in Naperville, IL, about the second week of December, 2012. Taxing my memory, the total was 1,132 + x(single digit).xxx... and immediately put in a freshly created InstaWallet bitcoin wallet. A couple/three days later I split the three accounts up into 1,000, 132, and x.xxx... wallets, always using InstaWallet while in my possession. Hope that helps with your plans.



            //var txt = File.ReadAllText("data/difficultyhistory.csv");
            //var lines = txt.Split(new string[]{"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
            //StringBuilder builder = new StringBuilder();
            //foreach(var line in lines)
            //{
            //	var fields = line.Split(',');
            //	builder.AppendLine(fields[0] + "," + fields[2]);
            //}
            //File.WriteAllText("targethistory.csv",builder.ToString());
            ////PlaySplit();
            //var oo = new PubKey(TestUtils.ParseHex("02bbc9fccbe03de928fc66fcd176fbe69d3641677970c6f8d558aa72f72e35e0cb")).GetAddress(Network.TestNet);
            //RPCClient client = RPCClientTests.CreateRPCClient();

            ////https://tpfaucet.appspot.com/
            //var scan = new Key(TestUtils.ParseHex("cc411aab02edcd3bccf484a9ba5280d4a774e6f81eac8ebec9cb1c2e8f73020a"));
            //var addr = new BitcoinStealthAddress("waPYjXyrTrvXjZHmMGdqs9YTegpRDpx97H5G3xqLehkgyrrZKsxGCmnwKexpZjXTCskUWwYywdUvrZK7L2vejeVZSYHVns61gm8VfU", Network.TestNet);

            //var sender = new BitcoinSecret("cRjSUV1LqN2F8MsGnLE2JKfCP75kbWGFRroNQeXHC429jqVFgmW3", Network.TestNet);


            //using(var fs = File.Open("Data.txt", FileMode.Create))
            //{
            //	StreamWriter writer = new StreamWriter(fs);
            //	foreach(var c in client.ListUnspent())
            //	{
            //		var ephem = new Key();
            //		writer.WriteLine("---");
            //		writer.WriteLine("Ephem Private key : " + Encoders.Hex.EncodeData(ephem.ToBytes()));
            //		Transaction tx = new Transaction();
            //		tx.Version = 1;
            //		tx.AddInput(new TxIn(c.OutPoint));
            //		var pay = addr.CreatePayment(ephem);

            //		writer.WriteLine("Metadata hash : " + pay.Metadata.Hash);
            //		writer.WriteLine("Metadata script : " + pay.Metadata.Script);
            //		writer.WriteLine("Metadata Nonce : " + pay.Metadata.Nonce);
            //		writer.WriteLine("Metadata Ephem Key : " + pay.Metadata.EphemKey.ToHex());

            //		pay.AddToTransaction(tx, c.Amount);

            //		tx.SignAll(sender);

            //		client.SendRawTransaction(tx);

            //		fs.Flush();
            //	}

            //}

            //var p = new PubKey(Encoders.Hex.DecodeData("03b4e5d3cf889840c75f0dd02ebda946151bf37e56cb888c6002c2ae5288e56de7"));
            //var o = Network.CreateFromBase58Data("mvXf4sF4C1w5KgQyasbEWxqVyqbLNtVdnY");
            //var sender = new BitcoinSecret("cRjSUV1LqN2F8MsGnLE2JKfCP75kbWGFRroNQeXHC429jqVFgmW3", Network.TestNet).Key;
            ////var addr = secret.Key.PubKey.GetAddress(Network.TestNet); //mwdJkHRNJi1fEwHBx6ikWFFuo2rLBdri2h
            //
            //var receiver = new BitcoinStealthAddress("waPV5rHToBq3NoR7y5J9UdE7aUbuqJybNpE88Dve7WgWhEfvMrcuaSvF6tSQ3Fbe8dErL6ks8byJPcp3QCK2HHviGCSjg42VgMAPJb", Network.TestNet);

            //Key ephemKey = new Key(Encoders.Hex.DecodeData("9daed68ad37754305e82740a6252cf80765c36d29a55158b1a19ed29914f0cb1"));
            //var ephemKeyStr = Encoders.Hex.EncodeData(ephemKey.ToBytes());
            //var scanStr = Encoders.Hex.EncodeData(receiver.ScanPubKey.ToBytes());
            //var spendStr = Encoders.Hex.EncodeData(receiver.SpendPubKeys[0].ToBytes());

            //var payment = receiver.CreatePayment(ephemKey);
            //var tx = new Transaction();
            //tx.Version = 1;
            //tx.Inputs.Add(new TxIn(new OutPoint(new uint256("d65e2274f6fde9515a35655d54e79243d5a17355f6943d6c16a63083a8769ea3"), 1)));

            //payment.AddToTransaction(tx, Money.Parse("0.51"));

            //tx.Inputs[0].ScriptSig = new PayToPubkeyHashTemplate().GenerateScriptPubKey(sender.PubKey.GetAddress(Network.TestNet));
            //var hash = tx.Inputs[0].ScriptSig.SignatureHash(tx, 0, SigHash.All);
            //var sig = sender.Sign(hash);
            //tx.Inputs[0].ScriptSig = new PayToPubkeyHashTemplate().GenerateScriptSig(new TransactionSignature(sig, SigHash.All), sender.PubKey);

            //var result = Script.VerifyScript(tx.Inputs[0].ScriptSig, new Script("OP_DUP OP_HASH160 b0b594bb2d2ca509b817f27e9280f6471807af26 OP_EQUALVERIFY OP_CHECKSIG"), tx, 0);

            //var bytes = Encoders.Hex.EncodeData(tx.ToBytes());
            //var client = new NodeServer(Network.TestNet);

            //var node = client.GetNodeByEndpoint(new IPEndPoint(IPAddress.Parse("95.85.39.28"), 18333));
            //node.VersionHandshake();
            //node.SendMessage(new TxPayload(tx));
            ////var store = new BlockStore(@"E:\Bitcoin\blocks", Network.Main);
            ////foreach(var un in store.EnumerateFolder())
            ////{
            //	var expectedSize = un.Header.ItemSize;
            //	var actualSize = un.Item.GetSerializedSize();
            //}

            //var test = new IndexedBlockStore(new SQLiteNoSqlRepository("Play", true), new BlockStore(@"E:\Bitcoin\blocks", Network.Main));
            //test.ReIndex();
            //var i = 0;
            //Stopwatch watch = new Stopwatch();
            //watch.Start();
            //foreach(var b in test.Store.Enumerate(false, new DiskBlockPosRange(new DiskBlockPos(137,0))).Take(144))
            //{
            //	i++;
            //}
            //watch.Stop();
        }
        /// <summary>
        /// Validates transaction inputs against transaction data for a specific set of script verify flags.
        /// Check whether all inputs of this transaction are valid (no double spends, scripts & signatures, amounts)
        /// This does not modify the UTXO set.
        /// </summary>
        /// <seealso>https://github.com/bitcoin/bitcoin/blob/febf3a856bcfb8fef2cb4ddcb8d1e0cab8a22580/src/validation.cpp#L1259</seealso>
        /// <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 (tx.IsCoinBase)
            {
                return(true);
            }

            // TODO: The original code does not appear to do these checks here. Reevaluate if this needs to be done, or perhaps moved to another rule/method.
            this.consensusRuleEngine.GetRule <CoinViewRule>().CheckInputs(context.Transaction, context.View.Set, this.chainIndexer.Height + 1);

            // TODO: Original code has the concept of a script execution cache. This might be worth looking into for performance improvements. Signature checks are expensive.

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

                var checker = new TransactionChecker(tx, iiInput, txout.Value, txData);
                var ctx     = new ScriptEvaluationContext(this.network)
                {
                    ScriptVerify = scriptVerify
                };
                if (!ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker))
                {
                    if ((scriptVerify & ScriptVerify.StandardNotMandatory) == ScriptVerify.StandardNotMandatory)
                    {
                        // 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.

                        // TODO: Investigate whether the checker and context can be reused instead of recreated. Probably not.
                        checker = new TransactionChecker(tx, iiInput, txout.Value, txData);
                        ctx     = new ScriptEvaluationContext(this.network)
                        {
                            ScriptVerify = (scriptVerify & ~ScriptVerify.StandardNotMandatory)
                        };

                        if (ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker))
                        {
                            this.logger.LogTrace("(-)[FAIL_NON_MANDATORY_SCRIPT_VERIFY]");
                            this.logger.LogDebug("Failed non-mandatory script verify: Transaction = {0}, scriptVerify = {1}, ctx.scriptVerify = {2}",
                                                 tx.ToHex(), scriptVerify, ctx.ScriptVerify);

                            // TODO: Check what this actually means in Core's logic. If it is on testnet/regtest and RequireStandard is false, is the transaction still rejected?
                            context.State.Fail(MempoolErrors.NonMandatoryScriptVerifyFlagFailed, ctx.Error.ToString()).Throw();
                        }
                    }

                    // Failures of other flags indicate a transaction that is invalid in new blocks, e.g. an 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.

                    // Further comment from Bitcoin Core:
                    // MANDATORY flag failures correspond to
                    // ValidationInvalidReason::CONSENSUS. Because CONSENSUS
                    // failures are the most serious case of validation
                    // failures, we may need to consider using
                    // RECENT_CONSENSUS_CHANGE for any script failure that
                    // could be due to non-upgraded nodes which we may want to
                    // support, to avoid splitting the network (but this
                    // depends on the details of how net_processing handles
                    // such errors).

                    this.logger.LogTrace("(-)[FAIL_MANDATORY_SCRIPT_VERIFY]");
                    context.State.Fail(MempoolErrors.MandatoryScriptVerifyFlagFailed, ctx.Error.ToString()).Throw();
                }
            }

            return(true);
        }
Beispiel #27
0
		public static ScriptSigs CombineSignatures(Script scriptPubKey, TransactionChecker checker, ScriptSigs input1, ScriptSigs input2)
		{
			if(scriptPubKey == null)
				scriptPubKey = new Script();

			var scriptSig1 = input1.ScriptSig;
			var scriptSig2 = input2.ScriptSig;
			HashVersion hashVersion = HashVersion.Original;
			var isWitness = input1.WitSig != WitScript.Empty || input2.WitSig != WitScript.Empty;
			if(isWitness)
			{
				scriptSig1 = input1.WitSig.ToScript();
				scriptSig2 = input2.WitSig.ToScript();
				hashVersion = HashVersion.Witness;
			}

			var context = new ScriptEvaluationContext();
			context.ScriptVerify = ScriptVerify.StrictEnc;
			context.EvalScript(scriptSig1, checker, hashVersion);

			var stack1 = context.Stack.AsInternalArray();
			context = new ScriptEvaluationContext();
			context.ScriptVerify = ScriptVerify.StrictEnc;
			context.EvalScript(scriptSig2, checker, hashVersion);

			var stack2 = context.Stack.AsInternalArray();
			var result = CombineSignatures(scriptPubKey, checker, stack1, stack2, hashVersion);
			if(result == null)
				return scriptSig1.Length < scriptSig2.Length ? input2 : input1;
			if(!isWitness)
				return new ScriptSigs()
				{
					ScriptSig = result,
					WitSig = WitScript.Empty
				};
			else
			{
				return new ScriptSigs()
				{
					ScriptSig = input1.ScriptSig.Length < input2.ScriptSig.Length ? input2.ScriptSig : input1.ScriptSig,
					WitSig = new WitScript(result)
				};
			}
		}
Beispiel #28
0
        public virtual void ExecuteBlock(ContextInformation context, TaskScheduler taskScheduler)
        {
            Block            block = context.BlockResult.Block;
            ChainedBlock     index = context.BlockResult.ChainedBlock;
            ConsensusFlags   flags = context.Flags;
            UnspentOutputSet view  = context.Set;

            this.PerformanceCounter.AddProcessedBlocks(1);
            taskScheduler = taskScheduler ?? TaskScheduler.Default;
            if (flags.EnforceBIP30)
            {
                foreach (var tx in block.Transactions)
                {
                    var coins = view.AccessCoins(tx.GetHash());
                    if (coins != null && !coins.IsPrunable)
                    {
                        ConsensusErrors.BadTransactionBIP30.Throw();
                    }
                }
            }
            long  nSigOpsCost = 0;
            Money nFees       = Money.Zero;
            List <Task <bool> > checkInputs = new List <Task <bool> >();

            for (int i = 0; i < block.Transactions.Count; i++)
            {
                this.PerformanceCounter.AddProcessedTransactions(1);
                var tx = block.Transactions[i];
                if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                {
                    int[] prevheights;

                    if (!view.HaveInputs(tx))
                    {
                        ConsensusErrors.BadTransactionMissingInput.Throw();
                    }

                    prevheights = new int[tx.Inputs.Count];
                    // Check that transaction is BIP68 final
                    // BIP68 lock checks (as opposed to nLockTime checks) must
                    // be in ConnectBlock because they require the UTXO set
                    for (var j = 0; j < tx.Inputs.Count; j++)
                    {
                        prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                    }

                    if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                    {
                        ConsensusErrors.BadTransactionNonFinal.Throw();
                    }
                }
                // GetTransactionSigOpCost counts 3 types of sigops:
                // * legacy (always)
                // * p2sh (when P2SH enabled in flags and excludes coinbase)
                // * witness (when witness enabled in flags and excludes coinbase)
                nSigOpsCost += this.GetTransactionSigOpCost(tx, view, flags);
                if (nSigOpsCost > this.consensusOptions.MAX_BLOCK_SIGOPS_COST)
                {
                    ConsensusErrors.BadBlockSigOps.Throw();
                }

                if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                {
                    this.CheckInputs(tx, view, index.Height);
                    nFees += view.GetValueIn(tx) - tx.TotalOut;
                    int ii      = i;
                    var localTx = tx;
                    PrecomputedTransactionData txData = new PrecomputedTransactionData(tx);
                    for (int iInput = 0; iInput < tx.Inputs.Count; iInput++)
                    {
                        this.PerformanceCounter.AddProcessedInputs(1);
                        var input      = tx.Inputs[iInput];
                        int iiIntput   = iInput;
                        var txout      = view.GetOutputFor(input);
                        var checkInput = new Task <bool>(() =>
                        {
                            if (this.UseConsensusLib)
                            {
                                Script.BitcoinConsensusError error;
                                return(Script.VerifyScriptConsensus(txout.ScriptPubKey, tx, (uint)iiIntput, flags.ScriptFlags, out error));
                            }
                            else
                            {
                                var checker      = new TransactionChecker(tx, iiIntput, txout.Value, txData);
                                var ctx          = new ScriptEvaluationContext();
                                ctx.ScriptVerify = flags.ScriptFlags;
                                return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                            }
                        });
                        checkInput.Start(taskScheduler);
                        checkInputs.Add(checkInput);
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            this.CheckBlockReward(context, nFees, index, block);

            var passed = checkInputs.All(c => c.GetAwaiter().GetResult());

            if (!passed)
            {
                ConsensusErrors.BadTransactionScriptError.Throw();
            }
        }
Beispiel #29
0
		public void script_PushData()
		{
			// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
			// the stack as the 1-75 opcodes do.
			var direct = new Script(new byte[] { 1, 0x5a });
			var pushdata1 = new Script(new byte[] { (byte)OpcodeType.OP_PUSHDATA1, 1, 0x5a });
			var pushdata2 = new Script(new byte[] { (byte)OpcodeType.OP_PUSHDATA2, 1, 0, 0x5a });
			var pushdata4 = new Script(new byte[] { (byte)OpcodeType.OP_PUSHDATA4, 1, 0, 0, 0, 0x5a });

			var context = new ScriptEvaluationContext()
				{
					ScriptVerify = ScriptVerify.P2SH,
					SigHash = 0
				};
			var directStack = context.Clone();
			Assert.True(directStack.EvalScript(direct, new Transaction(), 0));

			var pushdata1Stack = context.Clone();
			Assert.True(pushdata1Stack.EvalScript(pushdata1, new Transaction(), 0));
			AssertEx.StackEquals(pushdata1Stack.Stack, directStack.Stack);


			var pushdata2Stack = context.Clone();
			Assert.True(pushdata2Stack.EvalScript(pushdata2, new Transaction(), 0));
			AssertEx.StackEquals(pushdata2Stack.Stack, directStack.Stack);

			var pushdata4Stack = context.Clone();
			Assert.True(pushdata4Stack.EvalScript(pushdata4, new Transaction(), 0));
			AssertEx.StackEquals(pushdata4Stack.Stack, directStack.Stack);
		}
Beispiel #30
0
        public ViewResult TransactionCheck(TransactionCheckModel model)
        {
            model = model ?? new TransactionCheckModel();
            QBitNinjaClient client = new QBitNinjaClient(Network.TestNet);

            if (model.Transaction != null)
            {
                Transaction tx = null;
                try
                {
                    tx = new Transaction(model.Transaction);
                }
                catch (FormatException ex)
                {
                    ModelState.AddModelError("Transaction", "Can't parse transaction (" + ex.Message + ")");
                    return(View(model));
                }
                var totalSize = tx.ToBytes().Length;
                var coreSize  = tx.WithOptions(TransactionOptions.None).ToBytes().Length;
                model.WitnessSize     = totalSize - coreSize;
                model.CoreSize        = coreSize;
                model.TransactionCost = coreSize * 4 + model.WitnessSize;
                model.HasWitness      = tx.HasWitness;
                if (model.HasWitness)
                {
                    model.EstimatedCostNoWit = (coreSize + model.WitnessSize) * 4;
                    model.Saving             = (int)(((decimal)(model.EstimatedCostNoWit - model.TransactionCost) / model.EstimatedCostNoWit) * 100);
                }
                else
                {
                    model.ScriptSigSize    = tx.Inputs.Select(i => i.ScriptSig.Length).Sum();
                    model.EstimatedCostWit = (coreSize - model.ScriptSigSize) * 4 + model.ScriptSigSize;
                    model.Saving           = (int)(((decimal)(model.TransactionCost - model.EstimatedCostWit) / model.TransactionCost) * 100);
                }
                model.Result         = new CheckResult();
                model.Result.Success = true;
                model.Result.Id      = tx.GetHash();
                foreach (var input in tx.Inputs.AsIndexedInputs())
                {
                    if (tx.IsCoinBase)
                    {
                        break;
                    }
                    InputCheckResult inputCheck = new InputCheckResult();
                    inputCheck.PrevOut   = input.PrevOut;
                    inputCheck.Witness   = input.WitScript;
                    inputCheck.ScriptSig = input.ScriptSig;

                    var previous = client.GetTransaction(input.PrevOut.Hash).Result;
                    model.Result.InputResults.Add(inputCheck);
                    if (previous == null || previous.Transaction.Outputs.Count <= input.PrevOut.N)
                    {
                        model.Result.Success   = false;
                        inputCheck.ScriptError = "Previous output not found";
                        ModelState.AddModelError("Transaction", "Previous output not found (" + input.PrevOut + ")");
                        continue;
                    }
                    var output = previous.Transaction.Outputs[input.PrevOut.N];
                    inputCheck.ScriptPubKey = output.ScriptPubKey;
                    inputCheck.Amount       = output.Value;
                    ScriptEvaluationContext evaluator = new ScriptEvaluationContext();
                    evaluator.VerifyScript(input.ScriptSig, output.ScriptPubKey, new TransactionChecker(tx, (int)input.Index, output.Value));
                    if (evaluator.Error != ScriptError.OK)
                    {
                        inputCheck.ScriptError = Enum.GetName(typeof(ScriptError), evaluator.Error);
                        model.Result.Success  &= false;
                    }

                    var scriptId = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(inputCheck.ScriptPubKey);
                    if (scriptId != null)
                    {
                        var s = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(input.ScriptSig, scriptId);
                        inputCheck.P2SHRedeemScript = s == null ? null : s.RedeemScript;
                    }
                    inputCheck.SignatureHash = evaluator.SignedHashes.FirstOrDefault();
                }
            }
            return(View(model));
        }
Beispiel #31
0
		public static Script CombineSignatures(Script scriptPubKey, Transaction transaction, int n, Script scriptSig1, Script scriptSig2)
		{
			if(scriptPubKey == null)
				scriptPubKey = new Script();
			var context = new ScriptEvaluationContext();
			context.ScriptVerify = ScriptVerify.StrictEnc;
			context.EvalScript(scriptSig1, transaction, n);

			var stack1 = context.Stack.AsInternalArray();
			context = new ScriptEvaluationContext();
			context.ScriptVerify = ScriptVerify.StrictEnc;
			context.EvalScript(scriptSig2, transaction, n);

			var stack2 = context.Stack.AsInternalArray();

			return CombineSignatures(scriptPubKey, transaction, n, stack1, stack2);
		}
Beispiel #32
0
        public ActionResult ScriptCheck(ScriptCheckModel model)
        {
            if (!string.IsNullOrEmpty(model.Share))
            {
                return(SaveScript(model));
            }

            model.ScriptPubKey = model.ScriptPubKey ?? "";
            model.ScriptSig    = model.ScriptSig ?? "";
            bool parseProblem = false;

            Dictionary <string, Keyset> sets = new Dictionary <string, Keyset>();

            try
            {
                model.ExecutedScriptPubKey = GetExecutedScript(model.ScriptPubKey, Script.Empty, sets);
            }
            catch (FormatException)
            {
                ModelState.AddModelError("ScriptPubKey", "Parsing error");
                parseProblem = true;
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("ScriptPubKey", ex.Message);
                parseProblem = true;
            }

            try
            {
                model.ExecutedScriptSig = GetExecutedScript(model.ScriptSig, model.ExecutedScriptPubKey ?? Script.Empty, sets);
            }
            catch (FormatException)
            {
                ModelState.AddModelError("ScriptSig", "Parsing error");
                parseProblem = true;
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("ScriptSig", ex.Message);
                parseProblem = true;
            }

            if (parseProblem)
            {
                return(View(model));
            }

            ScriptEvaluationContext ctx = new ScriptEvaluationContext();

            model.Result = new ScriptResultModel();
            var tx = Keyset.DummyTransaction();

            model.Result.Success     = ctx.VerifyScript(model.ExecutedScriptSig, model.ExecutedScriptPubKey, tx, 0, Money.Zero);
            model.Result.Error       = ctx.Error.ToString();
            model.Result.StackValues = ctx.Stack.Select(b =>
            {
                var hex     = Encoders.Hex.EncodeData(b);
                var boolean = CastToBool(b);
                var bignum  = Utils.BytesToBigInteger(b);
                return(new StackValueModel()
                {
                    Bool = boolean.ToString(),
                    Hex = hex,
                    Number = bignum.ToString()
                });
            }).ToArray();

            model.Result.CheckSigs = ctx.SignedHashes.Select(b =>
            {
                return(new CheckSigsModel()
                {
                    SignedHash = b.Hash,
                    ScriptCode = b.ScriptCode,
                    Signature = Encoders.Hex.EncodeData(b.Signature.ToBytes())
                });
            }).ToArray();
            tx.Inputs[0].ScriptSig = model.ExecutedScriptSig;
            model.Transaction      = tx.ToHex();
            return(View(model));
        }
Beispiel #33
0
        private static Script CombineMultisig(Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
        {
            // Combine all the signatures we've got:
            List <TransactionSignature> allsigs = new List <TransactionSignature>();

            foreach (var v in sigs1)
            {
                if (TransactionSignature.IsValid(v))
                {
                    allsigs.Add(new TransactionSignature(v));
                }
            }


            foreach (var v in sigs2)
            {
                if (TransactionSignature.IsValid(v))
                {
                    allsigs.Add(new TransactionSignature(v));
                }
            }

            var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);

            if (multiSigParams == null)
            {
                throw new InvalidOperationException("The scriptPubKey is not a valid multi sig");
            }

            Dictionary <PubKey, TransactionSignature> sigs = new Dictionary <PubKey, TransactionSignature>();

            foreach (var sig in allsigs)
            {
                foreach (var pubkey in multiSigParams.PubKeys)
                {
                    if (sigs.ContainsKey(pubkey))
                    {
                        continue;                         // Already got a sig for this pubkey
                    }
                    ScriptEvaluationContext eval = new ScriptEvaluationContext();
                    if (eval.CheckSig(sig, pubkey, scriptPubKey, checker, hashVersion))
                    {
                        sigs.AddOrReplace(pubkey, sig);
                    }
                }
            }


            // Now build a merged CScript:
            int    nSigsHave = 0;
            Script result    = new Script(OpcodeType.OP_0);          // pop-one-too-many workaround

            foreach (var pubkey in multiSigParams.PubKeys)
            {
                if (sigs.ContainsKey(pubkey))
                {
                    result += Op.GetPushOp(sigs[pubkey].ToBytes());
                    nSigsHave++;
                }
                if (nSigsHave >= multiSigParams.SignatureCount)
                {
                    break;
                }
            }

            // Fill any missing with OP_0:
            for (int i = nSigsHave; i < multiSigParams.SignatureCount; i++)
            {
                result += OpcodeType.OP_0;
            }

            return(result);
        }
Beispiel #34
0
 public bool SignedByMe(Transaction tx)
 {
     for(int i = 0 ; i < tx.Inputs.Count ; i++)
     {
         var vin = tx.Inputs[i];
         var key = GetKey(vin.ScriptSig.GetSourcePubKey());
         if(key == null)
             return false;
         var pubkeyScript = new PayToPubkeyHashTemplate().GenerateScriptPubKey(key.PubKey);
         var eval = new ScriptEvaluationContext();
         eval.SigHash = SigHash.All;
         if(!eval.VerifyScript(vin.ScriptSig, pubkeyScript, tx, i))
             return false;
     }
     return true;
 }
        /// <summary>
        /// Whether transaction inputs are standard.
        /// Check for standard transaction types.
        /// </summary>
        /// <seealso>https://github.com/bitcoin/bitcoin/blob/febf3a856bcfb8fef2cb4ddcb8d1e0cab8a22580/src/policy/policy.cpp#L156</seealso>
        /// <param name="tx">Transaction to verify.</param>
        /// <param name="mapInputs">Map of previous transactions that have outputs we're spending.</param>
        /// <returns>Whether all inputs (scriptSigs) use only standard transaction forms.</returns>
        private bool AreInputsStandard(Network network, Transaction tx, MempoolCoinView mapInputs)
        {
            if (tx.IsCoinBase)
            {
                this.logger.LogTrace("(-)[IS_COINBASE]:true");
                return(true); // Coinbases don't use vin normally.
            }

            for (int i = 0; i < tx.Inputs.Count; i++)
            {
                TxIn           txin     = tx.Inputs[i];
                TxOut          prev     = mapInputs.GetOutputFor(txin);
                ScriptTemplate template = network.StandardScriptsRegistry.GetTemplateFromScriptPubKey(prev.ScriptPubKey);
                if (template == null) // i.e. the TX_NONSTANDARD case
                {
                    this.logger.LogTrace("(-)[BAD_SCRIPT_TEMPLATE]:false");
                    return(false);
                }

                /* Check transaction inputs to mitigate two potential denial-of-service attacks:
                 *
                 * 1. scriptSigs with extra data stuffed into them, not consumed by scriptPubKey (or P2SH script)
                 * 2. P2SH scripts with a crazy number of expensive CHECKSIG/CHECKMULTISIG operations
                 *
                 * Why bother? To avoid denial-of-service attacks; an attacker can submit a standard HASH... OP_EQUAL transaction,
                 * which will get accepted into blocks. The redemption script can be anything; an attacker could use a very
                 * expensive-to-check-upon-redemption script like:
                 *   DUP CHECKSIG DROP ... repeated 100 times... OP_1
                 */
                if (template.Type == TxOutType.TX_SCRIPTHASH)
                {
                    // Convert the scriptSig into a stack, so we can inspect the redeemScript.
                    var ctx = new ScriptEvaluationContext(this.network)
                    {
                        ScriptVerify = ScriptVerify.None
                    };

                    if (!ctx.EvalScript(txin.ScriptSig, tx, i)) // TODO: Check the semantics of SigVersion::BASE from original code
                    {
                        return(false);
                    }

                    // TODO: Investigate why IsEmpty is failing to return true when there is nothing on the stack. It is possible that nowhere else in the codebase is using IsEmpty on an IEnumerable
                    if (ctx.Stack.IsEmpty() || ctx.Stack.Count == 0)
                    {
                        return(false);
                    }

                    // Get redeemScript from stack.
                    var redeemScript = new Script(ctx.Stack.Top(-1));

                    // TODO: Move this into a network-specific rule so that it only applies to Strax (the Cirrus validator already allows non-standard transactions)
                    if (redeemScript.GetSigOpCount(true, this.network) > MaxP2SHSigOps)
                    {
                        this.logger.LogTrace("(-)[SIG_OP_MAX]:false");
                        return(false);
                    }
                }
            }

            return(true);
        }
Beispiel #36
0
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            this.Logger.LogTrace("()");

            Block            block = context.ValidationContext.Block;
            ChainedHeader    index = context.ValidationContext.ChainedHeader;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            this.Parent.PerformanceCounter.AddProcessedBlocks(1);

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.Parent.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.SkipValidation)
                {
                    if (!this.IsProtocolTransaction(tx))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.PowConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!this.IsProtocolTransaction(tx))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.Parent.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                var checker             = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                var ctx                 = new ScriptEvaluationContext(this.Parent.Network);
                                ctx.ScriptVerify        = flags.ScriptFlags;
                                bool verifyScriptResult = ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker);

                                if (verifyScriptResult == false)
                                {
                                    this.Logger.LogTrace("Verify script for transaction '{0}' failed, ScriptSig = '{1}', ScriptPubKey = '{2}', script evaluation error = '{3}'", tx.GetHash(), input.ScriptSig, txout.ScriptPubKey, ctx.Error);
                                }

                                return(verifyScriptResult);
                            });
                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            this.Logger.LogTrace("(-)");
        }