private bool ConnectBlock(CBlockStoreItem cursor, ref CBlock block, bool fJustCheck = false)
        {
            // Check it again in case a previous version let a bad block in, but skip BlockSig checking
            if (!block.CheckBlock(!fJustCheck, !fJustCheck, false))
            {
                return false; // Invalid block found.
            }

            bool fScriptChecks = cursor.nHeight >= HashCheckpoints.TotalBlocksEstimate;
            var scriptFlags = scriptflag.SCRIPT_VERIFY_NOCACHE | scriptflag.SCRIPT_VERIFY_P2SH;

            long nFees = 0;
            long nValueIn = 0;
            long nValueOut = 0;
            uint nSigOps = 0;

            var queuedMerkleNodes = new Dictionary<uint256, CMerkleNode>();
            var queuedOutputs = new Dictionary<COutPoint, TxOutItem>();

            for (var nTx = 0; nTx < block.vtx.Length; nTx++)
            {
                var tx = block.vtx[nTx];
                var hashTx = tx.Hash;

                if (!queuedMerkleNodes.ContainsKey(hashTx))
                {
                    var nTxPos = cursor.nBlockPos + block.GetTxOffset(nTx);
                    var mNode = new CMerkleNode(cursor.ItemID, nTxPos, tx);

                    queuedMerkleNodes.Add(hashTx, mNode);
                }

                Dictionary<COutPoint, TxOutItem> txouts;
                if (GetOutputs(hashTx, out txouts))
                {
                    // Do not allow blocks that contain transactions which 'overwrite' older transactions,
                    // unless those are already completely spent.
                    return false;
                }

                nSigOps += tx.LegacySigOpCount;
                if (nSigOps > CBlock.nMaxSigOps)
                {
                    return false; // too many sigops
                }

                var inputs = new Dictionary<COutPoint, TxOutItem>();

                if (tx.IsCoinBase)
                {
                    nValueOut += tx.nValueOut;
                }
                else
                {
                    bool Invalid;
                    if (!FetchInputs(ref tx, ref queuedOutputs, ref inputs, true, out Invalid))
                    {
                        return false; // Unable to fetch some inputs.
                    }

                    // Add in sigops done by pay-to-script-hash inputs;
                    // this is to prevent a "rogue miner" from creating
                    // an incredibly-expensive-to-validate block.
                    nSigOps += tx.GetP2SHSigOpCount(ref inputs);
                    if (nSigOps > CBlock.nMaxSigOps)
                    {
                        return false; // too many sigops
                    }

                    long nTxValueIn = tx.GetValueIn(ref inputs);
                    long nTxValueOut = tx.nValueOut;

                    nValueIn += nTxValueIn;
                    nValueOut += nTxValueOut;

                    if (!tx.IsCoinStake)
                    {
                        nFees += nTxValueIn - nTxValueOut;
                    }

                    if (!ConnectInputs(ref tx, ref inputs, ref queuedOutputs, ref cursor, true, fScriptChecks, scriptFlags))
                    {
                        return false;
                    }
                }

                for (var i = 0u; i < tx.vout.Length; i++)
                {
                    var outKey = new COutPoint(hashTx, i);
                    var outData = new TxOutItem()
                    {
                        nMerkleNodeID = -1,
                        nValue = tx.vout[i].nValue,
                        scriptPubKey = tx.vout[i].scriptPubKey,
                        IsSpent = false,
                        nOut = i
                    };

                    queuedOutputs.Add(outKey, outData);
                }
            }

            if (!block.IsProofOfStake)
            {
                long nBlockReward = CBlock.GetProofOfWorkReward(cursor.nBits, nFees);

                // Check coinbase reward
                if (block.vtx[0].nValueOut > nBlockReward)
                {
                    return false; // coinbase reward exceeded
                }
            }

            cursor.nMint = nValueOut - nValueIn + nFees;
            cursor.nMoneySupply = (cursor.prev != null ? cursor.prev.nMoneySupply : 0) + nValueOut - nValueIn;

            if (!UpdateDBCursor(ref cursor))
            {
                return false; // Unable to commit changes
            }

            if (fJustCheck)
            {
                return true;
            }

            // Flush merkle nodes.
            var savedMerkleNodes = new Dictionary<uint256, CMerkleNode>();
            foreach (var merklePair in queuedMerkleNodes)
            {
                var merkleNode = merklePair.Value;

                if (!SaveMerkleNode(ref merkleNode))
                {
                    // Unable to save merkle tree cursor.
                    return false;
                }

                savedMerkleNodes.Add(merklePair.Key, merkleNode);
            }

            // Write queued transaction changes
            var newOutpointItems = new List<TxOutItem>();
            var updatedOutpointItems = new List<TxOutItem>();
            foreach (var outPair in queuedOutputs)
            {
                var outItem = outPair.Value;

                if (outItem.nMerkleNodeID == -1)
                {
                    // This outpoint doesn't exist yet, adding to insert list.

                    outItem.nMerkleNodeID = savedMerkleNodes[outPair.Key.hash].nMerkleNodeID;
                    newOutpointItems.Add(outItem);
                }
                else
                {
                    // This outpount already exists, adding to update list.

                    updatedOutpointItems.Add(outItem);
                }
            }

            if (updatedOutpointItems.Count != 0 && !UpdateOutpoints(ref updatedOutpointItems))
            {
                return false; // Unable to update outpoints
            }

            if (newOutpointItems.Count != 0 && !InsertOutpoints(ref newOutpointItems))
            {
                return false; // Unable to insert outpoints
            }

            return true;
        }
        /// <summary>
        /// Insert merkle node into db and set actual record id value.
        /// </summary>
        /// <param name="merkleNode">Merkle node object reference.</param>
        /// <returns>Result</returns>
        private bool SaveMerkleNode(ref CMerkleNode merkleNode)
        {
            if (dbConn.Insert(merkleNode) == 0)
            {
                return false;
            }

            merkleNode.nMerkleNodeID = dbPlatform.SQLiteApi.LastInsertRowid(dbConn.Handle);

            return true;
        }