private bool ConnectInputs(ref CTransaction tx, ref Dictionary<COutPoint, TxOutItem> inputs, ref Dictionary<COutPoint, TxOutItem> queued, ref CBlockStoreItem cursorBlock, bool fBlock, bool fScriptChecks, scriptflag scriptFlags)
        {
            // Take over previous transactions' spent items
            // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain

            if (!tx.IsCoinBase)
            {
                long nValueIn = 0;
                long nFees = 0;
                for (uint i = 0; i < tx.vin.Length; i++)
                {
                    var prevout = tx.vin[i].prevout;
                    Contract.Assert(inputs.ContainsKey(prevout));
                    var input = inputs[prevout];

                    CBlockStoreItem parentBlockCursor;

                    if (input.nMerkleNodeID == -1)
                    {
                        // This input seems as is confirmed by the same block.

                        if (!queued.ContainsKey(prevout))
                        {
                            return false; // No such output has been queued by this block.
                        }

                        // TODO: Ensure that neither coinbase nor coinstake outputs are
                        //    available for spending in the generation block.
                    }
                    else
                    {
                        // This input has been confirmed by one of the earlier accepted blocks.

                        var merkleItem = GetMerkleCursor(input, out parentBlockCursor);

                        if (merkleItem == null)
                        {
                            return false; // Unable to find merkle node
                        }

                        // If prev is coinbase or coinstake, check that it's matured
                        if (merkleItem.IsCoinBase || merkleItem.IsCoinStake)
                        {
                            if (cursorBlock.nHeight - parentBlockCursor.nHeight < NetInfo.nGeneratedMaturity)
                            {
                                return false; // tried to spend non-matured generation input.
                            }
                        }

                        // check transaction timestamp
                        if (merkleItem.nTime > tx.nTime)
                        {
                            return false; // transaction timestamp earlier than input transaction
                        }
                    }

                    // Check for negative or overflow input values
                    nValueIn += input.nValue;
                    if (!CTransaction.MoneyRange(input.nValue) || !CTransaction.MoneyRange(nValueIn))
                    {
                        return false; // txin values out of range
                    }

                }

                // The first loop above does all the inexpensive checks.
                // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
                // Helps prevent CPU exhaustion attacks.
                for (int i = 0; i < tx.vin.Length; i++)
                {
                    var prevout = tx.vin[i].prevout;
                    Contract.Assert(inputs.ContainsKey(prevout));
                    var input = inputs[prevout];

                    // Check for conflicts (double-spend)
                    if (input.IsSpent)
                    {
                        return false;
                    }

                    // Skip ECDSA signature verification when connecting blocks (fBlock=true)
                    // before the last blockchain checkpoint. This is safe because block merkle hashes are
                    // still computed and checked, and any change will be caught at the next checkpoint.
                    if (fScriptChecks)
                    {
                        // Verify signature
                        if (!ScriptCode.VerifyScript(tx.vin[i].scriptSig, input.scriptPubKey, tx, i, (int)scriptflag.SCRIPT_VERIFY_P2SH, 0))
                        {
                            return false; // VerifyScript failed.
                        }
                    }

                    // Mark outpoint as spent
                    input.IsSpent = true;
                    inputs[prevout] = input;

                    // Write back
                    if (fBlock)
                    {
                        if (input.nMerkleNodeID != -1)
                        {
                            // Input has been confirmed earlier.
                            queued.Add(prevout, input);
                        }
                        else
                        {
                            // Input has been confirmed by current block.
                            queued[prevout] = input;
                        }
                    }
                }

                if (tx.IsCoinStake)
                {
                    if (HashCheckpoints.LastCheckpointTime < tx.nTime)
                    {
                        // Coin stake tx earns reward instead of paying fee
                        long nCoinAge;
                        if (!tx.GetCoinAge(ref inputs, out nCoinAge))
                        {
                            return false; // unable to get coin age for coinstake
                        }

                        long nReward = tx.nValueOut - nValueIn;
                        long nCalculatedReward = CBlock.GetProofOfStakeReward(nCoinAge, cursorBlock.nBits, tx.nTime) - tx.GetMinFee(1, false, CTransaction.MinFeeMode.GMF_BLOCK) + CTransaction.nCent;

                        if (nReward > nCalculatedReward)
                        {
                            return false; // coinstake pays too much
                        }
                    }
                }
                else
                {
                    if (nValueIn < tx.nValueOut)
                    {
                        return false; // value in < value out
                    }

                    // Tally transaction fees
                    long nTxFee = nValueIn - tx.nValueOut;
                    if (nTxFee < 0)
                    {
                        return false; // nTxFee < 0
                    }

                    nFees += nTxFee;

                    if (!CTransaction.MoneyRange(nFees))
                    {
                        return false; // nFees out of range
                    }
                }

            }

            return true;
        }