text: // Copyright (c) 2010 Satoshi Nakamoto
  // Copyright (c) 2009-2014 The Bitcoin developers
  // Copyright (c) 2014-2015 The Dash developers
  // Copyright (c) 2015-2020 The PIVX developers
  // Copyright (c) 2020 The Nasda Cash developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include "base58.h"
  #include "core_io.h"
  #include "init.h"
  #include "keystore.h"
  #include "main.h"
  #include "net.h"
  #include "policy/policy.h"
  #include "primitives/transaction.h"
  #include "rpc/server.h"
  #include "script/script.h"
  #include "script/script_error.h"
  #include "script/sign.h"
  #include "script/standard.h"
  #include "swifttx.h"
  #include "uint256.h"
  #include "utilmoneystr.h"
  #ifdef ENABLE_WALLET
  #include "wallet/wallet.h"
  #endif
  
  #include <stdint.h>
  
  #include <boost/assign/list_of.hpp>
  
  #include <univalue.h>
  
  
  void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
  {
      txnouttype type;
      std::vector<CTxDestination> addresses;
      int nRequired;
  
      out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey)));
      if (fIncludeHex)
          out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
  
      if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
          out.push_back(Pair("type", GetTxnOutputType(type)));
          return;
      }
  
      out.push_back(Pair("reqSigs", nRequired));
      out.push_back(Pair("type", GetTxnOutputType(type)));
  
      UniValue a(UniValue::VARR);
      for (const CTxDestination& addr : addresses)
          a.push_back(EncodeDestination(addr));
      out.push_back(Pair("addresses", a));
  }
  
  void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
  {
      // Call into TxToUniv() in bitcoin-common to decode the transaction hex.
      //
      // Blockchain contextual information (confirmations and blocktime) is not
      // available to code in bitcoin-common, so we query them here and push the
      // data into the returned UniValue.
      TxToUniv(tx, uint256(), entry);
  
      if (!hashBlock.IsNull()) {
          entry.push_back(Pair("blockhash", hashBlock.GetHex()));
          BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
          if (mi != mapBlockIndex.end() && (*mi).second) {
              CBlockIndex* pindex = (*mi).second;
              if (chainActive.Contains(pindex)) {
                  entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
                  entry.push_back(Pair("time", pindex->GetBlockTime()));
                  entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
              }
              else
                  entry.push_back(Pair("confirmations", 0));
          }
      }
  }
  
  UniValue getrawtransaction(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
          throw std::runtime_error(
              "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n"
  
              "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
              "or there is an unspent output in the utxo for this transaction. To make it always work,\n"
              "you need to maintain a transaction index, using the -txindex command line option.\n"
  
              "\nReturn the raw transaction data.\n"
              "\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
              "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n"
  
              "\nArguments:\n"
              "1. \"txid\"      (string, required) The transaction id\n"
              "2. verbose     (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
              "3. \"blockhash\" (string, optional) The block in which to look for the transaction\n"
  
              "\nResult (if verbose is not set or set to false):\n"
              "\"data\"      (string) The serialized, hex-encoded data for 'txid'\n"
  
              "\nResult (if verbose is set to true):\n"
              "{\n"
              "  \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
              "  \"hex\" : \"data\",       (string) The serialized, hex-encoded data for 'txid'\n"
              "  \"txid\" : \"id\",        (string) The transaction id (same as provided)\n"
              "  \"size\" : n,             (numeric) The serialized transaction size\n"
              "  \"version\" : n,          (numeric) The version\n"
              "  \"locktime\" : ttt,       (numeric) The lock time\n"
              "  \"vin\" : [               (array of json objects)\n"
              "     {\n"
              "       \"txid\": \"id\",    (string) The transaction id\n"
              "       \"vout\": n,         (numeric) \n"
              "       \"scriptSig\": {     (json object) The script\n"
              "         \"asm\": \"asm\",  (string) asm\n"
              "         \"hex\": \"hex\"   (string) hex\n"
              "       },\n"
              "       \"sequence\": n      (numeric) The script sequence number\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "  \"vout\" : [              (array of json objects)\n"
              "     {\n"
              "       \"value\" : x.xxx,            (numeric) The value in NSDC\n"
              "       \"n\" : n,                    (numeric) index\n"
              "       \"scriptPubKey\" : {          (json object)\n"
              "         \"asm\" : \"asm\",          (string) the asm\n"
              "         \"hex\" : \"hex\",          (string) the hex\n"
              "         \"reqSigs\" : n,            (numeric) The required sigs\n"
              "         \"type\" : \"pubkeyhash\",  (string) The type, eg 'pubkeyhash'\n"
              "         \"addresses\" : [           (json array of string)\n"
              "           \"nasdacashaddress\"        (string) nasdacash address\n"
              "           ,...\n"
              "         ]\n"
              "       }\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "  \"blockhash\" : \"hash\",   (string) the block hash\n"
              "  \"confirmations\" : n,      (numeric) The confirmations\n"
              "  \"time\" : ttt,             (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n"
              "  \"blocktime\" : ttt         (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
              "}\n"
  
              "\nExamples:\n"
              + HelpExampleCli("getrawtransaction", "\"mytxid\"")
              + HelpExampleCli("getrawtransaction", "\"mytxid\" true")
              + HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
              + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
              + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
          );
  
      LOCK(cs_main);
  
      bool in_active_chain = true;
      uint256 hash = ParseHashV(request.params[0], "parameter 1");
      CBlockIndex* blockindex = nullptr;
  
      bool fVerbose = false;
      if (!request.params[1].isNull()) {
          fVerbose = request.params[1].isNum() ? (request.params[1].get_int() != 0) : request.params[1].get_bool();
      }
  
      if (!request.params[2].isNull()) {
          uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
          BlockMap::iterator it = mapBlockIndex.find(blockhash);
          if (it == mapBlockIndex.end()) {
              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
          }
          blockindex = it->second;
          in_active_chain = chainActive.Contains(blockindex);
      }
  
      CTransaction tx;
      uint256 hash_block;
      if (!GetTransaction(hash, tx, hash_block, true, blockindex)) {
          std::string errmsg;
          if (blockindex) {
              if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) {
                  throw JSONRPCError(RPC_MISC_ERROR, "Block not available");
              }
              errmsg = "No such transaction found in the provided block";
          } else {
              errmsg = fTxIndex
                ? "No such mempool or blockchain transaction"
                : "No such mempool transaction. Use -txindex to enable blockchain transaction queries";
          }
          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions.");
      }
  
      if (!fVerbose) {
          return EncodeHexTx(tx);
      }
  
      UniValue result(UniValue::VOBJ);
      if (blockindex) result.push_back(Pair("in_active_chain", in_active_chain));
      TxToJSON(tx, hash_block, result);
      return result;
  }
  
  UniValue createrawtransaction(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
          throw std::runtime_error(
              "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...} ( locktime )\n"
              "\nCreate a transaction spending the given inputs and sending to the given addresses.\n"
              "Returns hex-encoded raw transaction.\n"
              "Note that the transaction's inputs are not signed, and\n"
              "it is not stored in the wallet or transmitted to the network.\n"
  
              "\nArguments:\n"
              "1. \"transactions\"        (string, required) A json array of json objects\n"
              "     [\n"
              "       {\n"
              "         \"txid\":\"id\",  (string, required) The transaction id\n"
              "         \"vout\":n,       (numeric, required) The output number\n"
              "         \"sequence\":n    (numeric, optional) The sequence number\n"
              "       }\n"
              "       ,...\n"
              "     ]\n"
              "2. \"addresses\"           (string, required) a json object with addresses as keys and amounts as values\n"
              "    {\n"
              "      \"address\": x.xxx   (numeric, required) The key is the nasdacash address, the value is the nasdacash amount\n"
              "      ,...\n"
              "    }\n"
              "3. locktime                (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
  
              "\nResult:\n"
              "\"transaction\"            (string) hex string of the transaction\n"
  
              "\nExamples\n" +
              HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\""));
  
      LOCK(cs_main);
      RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM));
      if (request.params[0].isNull() || request.params[1].isNull())
          throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
  
      UniValue inputs = request.params[0].get_array();
      UniValue sendTo = request.params[1].get_obj();
  
      CMutableTransaction rawTx;
  
      if (request.params.size() > 2 && !request.params[2].isNull()) {
          int64_t nLockTime = request.params[2].get_int64();
          if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
          rawTx.nLockTime = nLockTime;
      }
  
      for (unsigned int idx = 0; idx < inputs.size(); idx++) {
          const UniValue& input = inputs[idx];
          const UniValue& o = input.get_obj();
  
          uint256 txid = ParseHashO(o, "txid");
  
          const UniValue& vout_v = find_value(o, "vout");
          if (!vout_v.isNum())
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
          int nOutput = vout_v.get_int();
          if (nOutput < 0)
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
  
          uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
  
          // set the sequence number if passed in the parameters object
          const UniValue& sequenceObj = find_value(o, "sequence");
          if (sequenceObj.isNum()) {
              int64_t seqNr64 = sequenceObj.get_int64();
              if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max())
                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
              else
                  nSequence = (uint32_t)seqNr64;
          }
  
          CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
  
          rawTx.vin.push_back(in);
      }
  
      std::set<CTxDestination> setAddress;
      std::vector<std::string> addrList = sendTo.getKeys();
      for (const std::string& name_ : addrList) {
          CTxDestination address = DecodeDestination(name_);
          if (!IsValidDestination(address))
              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Nasda_Cash address: ")+name_);
  
          if (setAddress.count(address))
              throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
          setAddress.insert(address);
  
          CScript scriptPubKey = GetScriptForDestination(address);
          CAmount nAmount = AmountFromValue(sendTo[name_]);
  
          CTxOut out(nAmount, scriptPubKey);
          rawTx.vout.push_back(out);
      }
  
      return EncodeHexTx(rawTx);
  }
  
  UniValue decoderawtransaction(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() != 1)
          throw std::runtime_error(
              "decoderawtransaction \"hexstring\"\n"
              "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
  
              "\nArguments:\n"
              "1. \"hex\"      (string, required) The transaction hex string\n"
  
              "\nResult:\n"
              "{\n"
              "  \"txid\" : \"id\",        (string) The transaction id\n"
              "  \"size\" : n,             (numeric) The transaction size\n"
              "  \"version\" : n,          (numeric) The version\n"
              "  \"locktime\" : ttt,       (numeric) The lock time\n"
              "  \"vin\" : [               (array of json objects)\n"
              "     {\n"
              "       \"txid\": \"id\",    (string) The transaction id\n"
              "       \"vout\": n,         (numeric) The output number\n"
              "       \"scriptSig\": {     (json object) The script\n"
              "         \"asm\": \"asm\",  (string) asm\n"
              "         \"hex\": \"hex\"   (string) hex\n"
              "       },\n"
              "       \"sequence\": n     (numeric) The script sequence number\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "  \"vout\" : [             (array of json objects)\n"
              "     {\n"
              "       \"value\" : x.xxx,            (numeric) The value in NSDC\n"
              "       \"n\" : n,                    (numeric) index\n"
              "       \"scriptPubKey\" : {          (json object)\n"
              "         \"asm\" : \"asm\",          (string) the asm\n"
              "         \"hex\" : \"hex\",          (string) the hex\n"
              "         \"reqSigs\" : n,            (numeric) The required sigs\n"
              "         \"type\" : \"pubkeyhash\",  (string) The type, eg 'pubkeyhash'\n"
              "         \"addresses\" : [           (json array of string)\n"
              "           \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\"   (string) nasdacash address\n"
              "           ,...\n"
              "         ]\n"
              "       }\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "}\n"
  
              "\nExamples:\n" +
              HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\""));
  
      LOCK(cs_main);
      RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
  
      CTransaction tx;
  
      if (!DecodeHexTx(tx, request.params[0].get_str()))
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
  
      UniValue result(UniValue::VOBJ);
      TxToJSON(tx, UINT256_ZERO, result);
  
      return result;
  }
  
  UniValue decodescript(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() != 1)
          throw std::runtime_error(
              "decodescript \"hex\"\n"
              "\nDecode a hex-encoded script.\n"
  
              "\nArguments:\n"
              "1. \"hex\"     (string) the hex encoded script\n"
  
              "\nResult:\n"
              "{\n"
              "  \"asm\":\"asm\",   (string) Script public key\n"
              "  \"hex\":\"hex\",   (string) hex encoded public key\n"
              "  \"type\":\"type\", (string) The output type\n"
              "  \"reqSigs\": n,    (numeric) The required signatures\n"
              "  \"addresses\": [   (json array of string)\n"
              "     \"address\"     (string) nasdacash address\n"
              "     ,...\n"
              "  ],\n"
              "  \"p2sh\",\"address\" (string) script address\n"
              "}\n"
  
              "\nExamples:\n" +
              HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\""));
  
      LOCK(cs_main);
      RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
  
      UniValue r(UniValue::VOBJ);
      CScript script;
      if (request.params[0].get_str().size() > 0) {
          std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
          script = CScript(scriptData.begin(), scriptData.end());
      } else {
          // Empty scripts are valid
      }
      ScriptPubKeyToJSON(script, r, false);
  
      r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script))));
      return r;
  }
  
  /** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
  static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
  {
      UniValue entry(UniValue::VOBJ);
      entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
      entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
      entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
      entry.push_back(Pair("sequence", (uint64_t)txin.nSequence));
      entry.push_back(Pair("error", strMessage));
      vErrorsRet.push_back(entry);
  }
  
  UniValue fundrawtransaction(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
          throw std::runtime_error(
              "fundrawtransaction \"hexstring\" ( options )\n"
              "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
              "This will not modify existing inputs, and will add one change output to the outputs.\n"
              "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
              "The inputs added will not be signed, use signrawtransaction for that.\n"
              "Note that all existing inputs must have their previous output transaction be in the wallet.\n"
              "Note that all inputs selected must be of standard form and P2SH scripts must be "
              "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
              "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"
  
              "\nArguments:\n"
              "1. \"hexstring\"    (string, required) The hex string of the raw transaction\n"
              "2. options          (object, optional)\n"
              "   {\n"
              "     \"changeAddress\"     (string, optional, default pool address) The Nasda_Cash address to receive the change\n"
              "     \"changePosition\"    (numeric, optional, default random) The index of the change output\n"
              "     \"includeWatching\"   (boolean, optional, default false) Also select inputs which are watch only\n"
              "     \"lockUnspents\"      (boolean, optional, default false) Lock selected unspent outputs\n"
                  " \"feeRate\"           (numeric, optional, default 0=estimate) Set a specific feerate (NSDC per KB)\n"
              "   }\n"
              "\nResult:\n"
              "{\n"
              "  \"hex\":       \"value\", (string)  The resulting raw transaction (hex-encoded string)\n"
              "  \"fee\":       n,         (numeric) The fee added to the transaction\n"
              "  \"changepos\": n          (numeric) The position of the added change output, or -1\n"
              "}\n"
              "\"hex\"             \n"
              "\nExamples:\n"
              "\nCreate a transaction with no inputs\n"
              + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
              "\nAdd sufficient unsigned inputs to meet the output value\n"
              + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
              "\nSign the transaction\n"
              + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
              "\nSend the transaction\n"
              + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
              );
  
      if (!pwalletMain)
          throw std::runtime_error("wallet not initialized");
  
      RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
  
      CTxDestination changeAddress = CNoDestination();
      int changePosition = -1;
      bool includeWatching = false;
      bool lockUnspents = false;
      CFeeRate feeRate = CFeeRate(0);
      bool overrideEstimatedFeerate = false;
  
      if (request.params.size() > 1) {
          RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
          UniValue options = request.params[1];
          RPCTypeCheckObj(options, boost::assign::map_list_of("changeAddress", UniValue::VSTR)("changePosition", UniValue::VNUM)("includeWatching", UniValue::VBOOL)("lockUnspents", UniValue::VBOOL)("feeRate", UniValue::VNUM), true, true);
  
          if (options.exists("changeAddress")) {
              changeAddress = DecodeDestination(options["changeAddress"].get_str());
  
              if (!IsValidDestination(changeAddress))
                  throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid Nasda_Cash address");
          }
  
          if (options.exists("changePosition"))
              changePosition = options["changePosition"].get_int();
  
          if (options.exists("includeWatching"))
              includeWatching = options["includeWatching"].get_bool();
  
          if (options.exists("lockUnspents"))
              lockUnspents = options["lockUnspents"].get_bool();
  
          if (options.exists("feeRate")) {
              feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
              overrideEstimatedFeerate = true;
          }
      }
  
      // parse hex string from parameter
      CTransaction origTx;
      if (!DecodeHexTx(origTx, request.params[0].get_str()))
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
  
      if (origTx.vout.size() == 0)
          throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
  
      if (changePosition != -1 && (changePosition < 0 || (unsigned int) changePosition > origTx.vout.size()))
          throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
  
      CMutableTransaction tx(origTx);
      CAmount nFeeOut;
      std::string strFailReason;
      if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress))
          throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
  
      UniValue result(UniValue::VOBJ);
      result.push_back(Pair("hex", EncodeHexTx(tx)));
      result.push_back(Pair("changepos", changePosition));
      result.push_back(Pair("fee", ValueFromAmount(nFeeOut)));
  
      return result;
  }
  
  UniValue signrawtransaction(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
          throw std::runtime_error(
              "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
              "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
              "The second optional argument (may be null) is an array of previous transaction outputs that\n"
              "this transaction depends on but may not yet be in the block chain.\n"
              "The third optional argument (may be null) is an array of base58-encoded private\n"
              "keys that, if given, will be the only keys used to sign the transaction.\n"
  #ifdef ENABLE_WALLET
              + HelpRequiringPassphrase() + "\n"
  #endif
  
              "\nArguments:\n"
              "1. \"hexstring\"     (string, required) The transaction hex string\n"
              "2. \"prevtxs\"       (string, optional) An json array of previous dependent transaction outputs\n"
              "     [               (json array of json objects, or 'null' if none provided)\n"
              "       {\n"
              "         \"txid\":\"id\",             (string, required) The transaction id\n"
              "         \"vout\":n,                  (numeric, required) The output number\n"
              "         \"scriptPubKey\": \"hex\",   (string, required) script key\n"
              "         \"redeemScript\": \"hex\"    (string, required for P2SH) redeem script\n"
              "       }\n"
              "       ,...\n"
              "    ]\n"
              "3. \"privatekeys\"     (string, optional) A json array of base58-encoded private keys for signing\n"
              "    [                  (json array of strings, or 'null' if none provided)\n"
              "      \"privatekey\"   (string) private key in base58-encoding\n"
              "      ,...\n"
              "    ]\n"
              "4. \"sighashtype\"     (string, optional, default=ALL) The signature hash type. Must be one of\n"
              "       \"ALL\"\n"
              "       \"NONE\"\n"
              "       \"SINGLE\"\n"
              "       \"ALL|ANYONECANPAY\"\n"
              "       \"NONE|ANYONECANPAY\"\n"
              "       \"SINGLE|ANYONECANPAY\"\n"
  
              "\nResult:\n"
              "{\n"
              "  \"hex\" : \"value\",           (string) The hex-encoded raw transaction with signature(s)\n"
              "  \"complete\" : true|false,   (boolean) If the transaction has a complete set of signatures\n"
              "  \"errors\" : [                 (json array of objects) Script verification errors (if there are any)\n"
              "    {\n"
              "      \"txid\" : \"hash\",           (string) The hash of the referenced, previous transaction\n"
              "      \"vout\" : n,                (numeric) The index of the output to spent and used as input\n"
              "      \"scriptSig\" : \"hex\",       (string) The hex-encoded signature script\n"
              "      \"sequence\" : n,            (numeric) Script sequence number\n"
              "      \"error\" : \"text\"           (string) Verification or signing error related to the input\n"
              "    }\n"
              "    ,...\n"
              "  ]\n"
              "}\n"
  
              "\nExamples:\n" +
              HelpExampleCli("signrawtransaction", "\"myhex\"") + HelpExampleRpc("signrawtransaction", "\"myhex\""));
  
  #ifdef ENABLE_WALLET
      LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
  #else
      LOCK(cs_main);
  #endif
      RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
  
      std::vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
      CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
      std::vector<CMutableTransaction> txVariants;
      while (!ssData.empty()) {
          try {
              CMutableTransaction tx;
              ssData >> tx;
              txVariants.push_back(tx);
          } catch (const std::exception&) {
              throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
          }
      }
  
      if (txVariants.empty())
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
  
      // mergedTx will end up with all the signatures; it
      // starts as a clone of the rawtx:
      CMutableTransaction mergedTx(txVariants[0]);
  
      // Fetch previous transactions (inputs):
      std::map<COutPoint, CScript> mapPrevOut;
      if (Params().IsRegTestNet()) {
          for (const CTxIn &txbase : mergedTx.vin)
          {
              CTransaction tempTx;
              uint256 hashBlock;
              if (GetTransaction(txbase.prevout.hash, tempTx, hashBlock, true)) {
                  // Copy results into mapPrevOut:
                  mapPrevOut[txbase.prevout] = tempTx.vout[txbase.prevout.n].scriptPubKey;
              }
          }
      }
      CCoinsView viewDummy;
      CCoinsViewCache view(&viewDummy);
      {
          LOCK(mempool.cs);
          CCoinsViewCache& viewChain = *pcoinsTip;
          CCoinsViewMemPool viewMempool(&viewChain, mempool);
          view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
  
          for (const CTxIn& txin : mergedTx.vin) {
              const uint256& prevHash = txin.prevout.hash;
              CCoins coins;
              view.AccessCoins(prevHash); // this is certainly allowed to fail
          }
  
          view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
      }
  
      bool fGivenKeys = false;
      CBasicKeyStore tempKeystore;
      if (request.params.size() > 2 && !request.params[2].isNull()) {
          fGivenKeys = true;
          UniValue keys = request.params[2].get_array();
          for (unsigned int idx = 0; idx < keys.size(); idx++) {
              UniValue k = keys[idx];
              CKey key = DecodeSecret(k.get_str());
              if (!key.IsValid())
                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
              tempKeystore.AddKey(key);
          }
      }
  #ifdef ENABLE_WALLET
      else if (pwalletMain)
          EnsureWalletIsUnlocked();
  #endif
  
      // Add previous txouts given in the RPC call:
      if (request.params.size() > 1 && !request.params[1].isNull()) {
          UniValue prevTxs = request.params[1].get_array();
          for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
              const UniValue& p = prevTxs[idx];
              if (!p.isObject())
                  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
  
              UniValue prevOut = p.get_obj();
  
              RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR));
  
              uint256 txid = ParseHashO(prevOut, "txid");
  
              int nOut = find_value(prevOut, "vout").get_int();
              if (nOut < 0)
                  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
  
              std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
              CScript scriptPubKey(pkData.begin(), pkData.end());
  
              {
                  CCoinsModifier coins = view.ModifyCoins(txid);
                  if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
                      std::string err("Previous output scriptPubKey mismatch:\n");
                      err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
                          ScriptToAsmStr(scriptPubKey);
                      throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
                  }
                  if ((unsigned int)nOut >= coins->vout.size())
                      coins->vout.resize(nOut + 1);
                  coins->vout[nOut].scriptPubKey = scriptPubKey;
                  coins->vout[nOut].nValue = 0; // we don't know the actual output value
              }
  
              // if redeemScript given and not using the local wallet (private keys
              // given), add redeemScript to the tempKeystore so it can be signed:
              if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) {
                  RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR));
                  UniValue v = find_value(prevOut, "redeemScript");
                  if (!v.isNull()) {
                      std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
                      CScript redeemScript(rsData.begin(), rsData.end());
                      tempKeystore.AddCScript(redeemScript);
                  }
              }
          }
      }
  
  #ifdef ENABLE_WALLET
      const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
  #else
      const CKeyStore& keystore = tempKeystore;
  #endif
  
      int nHashType = SIGHASH_ALL;
      if (request.params.size() > 3 && !request.params[3].isNull()) {
          static std::map<std::string, int> mapSigHashValues =
              boost::assign::map_list_of(std::string("ALL"), int(SIGHASH_ALL))(std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))(std::string("NONE"), int(SIGHASH_NONE))(std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE | SIGHASH_ANYONECANPAY))(std::string("SINGLE"), int(SIGHASH_SINGLE))(std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY));
          std::string strHashType = request.params[3].get_str();
          if (mapSigHashValues.count(strHashType))
              nHashType = mapSigHashValues[strHashType];
          else
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
      }
  
      bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
  
      // Script verification errors
      UniValue vErrors(UniValue::VARR);
  
      // Sign what we can:
      for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
          CTxIn& txin = mergedTx.vin[i];
          const CCoins* coins = view.AccessCoins(txin.prevout.hash);
          if (Params().IsRegTestNet()) {
              if (mapPrevOut.count(txin.prevout) == 0 && (coins == NULL || !coins->IsAvailable(txin.prevout.n)))
              {
                  TxInErrorToJSON(txin, vErrors, "Input not found");
                  continue;
              }
          } else {
              if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
                  TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
                  continue;
              }
          }
          const CScript& prevPubKey = (Params().IsRegTestNet() && mapPrevOut.count(txin.prevout) != 0 ? mapPrevOut[txin.prevout] : coins->vout[txin.prevout.n].scriptPubKey);
  
          txin.scriptSig.clear();
  
          // if this is a P2CS script, select which key to use
          bool fColdStake = false;
          if (prevPubKey.IsPayToColdStaking()) {
              // if we have both keys, sign with the spender key
              fColdStake = !bool(IsMine(keystore, prevPubKey) & ISMINE_SPENDABLE_DELEGATED);
          }
  
          // Only sign SIGHASH_SINGLE if there's a corresponding output:
          if (!fHashSingle || (i < mergedTx.vout.size()))
              SignSignature(keystore, prevPubKey, mergedTx, i, nHashType, fColdStake);
  
          // ... and merge in other signatures:
          for (const CMutableTransaction& txv : txVariants) {
              txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
          }
          ScriptError serror = SCRIPT_ERR_OK;
          if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) {
              TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
          }
      }
      bool fComplete = vErrors.empty();
  
      UniValue result(UniValue::VOBJ);
      result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
      result.push_back(Pair("complete", fComplete));
      if (!vErrors.empty()) {
          result.push_back(Pair("errors", vErrors));
      }
  
      return result;
  }
  
  UniValue sendrawtransaction(const JSONRPCRequest& request)
  {
      if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
          throw std::runtime_error(
              "sendrawtransaction \"hexstring\" ( allowhighfees )\n"
              "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
              "\nAlso see createrawtransaction and signrawtransaction calls.\n"
  
              "\nArguments:\n"
              "1. \"hexstring\"    (string, required) The hex string of the raw transaction)\n"
              "2. allowhighfees    (boolean, optional, default=false) Allow high fees\n"
              "3. swiftx           (boolean, optional, default=false) Use SwiftX to send this transaction\n"
  
              "\nResult:\n"
              "\"hex\"             (string) The transaction hash in hex\n"
  
              "\nExamples:\n"
              "\nCreate a transaction\n" +
              HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
              "Sign the transaction, and get back the hex\n" + HelpExampleCli("signrawtransaction", "\"myhex\"") +
              "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
              "\nAs a json rpc call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\""));
  
      RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
  
      // parse hex string from parameter
      CTransaction tx;
      if (!DecodeHexTx(tx, request.params[0].get_str()))
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
      uint256 hashTx = tx.GetHash();
  
      bool fOverrideFees = false;
      if (request.params.size() > 1)
          fOverrideFees = request.params[1].get_bool();
  
      bool fSwiftX = false;
      if (request.params.size() > 2)
          fSwiftX = request.params[2].get_bool();
  
      AssertLockNotHeld(cs_main);
      CCoinsViewCache& view = *pcoinsTip;
      const CCoins* existingCoins = view.AccessCoins(hashTx);
      bool fHaveMempool = mempool.exists(hashTx);
      bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
      if (!fHaveMempool && !fHaveChain) {
          // push to local node and sync with wallets
          if (fSwiftX) {
              mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx));
              CreateNewLock(tx);
              RelayTransactionLockReq(tx, true);
          }
          CValidationState state;
          bool fMissingInputs;
          if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, !fOverrideFees)) {
              if (state.IsInvalid()) {
                  throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
              } else {
                  if (fMissingInputs) {
                      throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
                  }
                  throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
              }
          }
      } else if (fHaveChain) {
          throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
      }
      RelayTransaction(tx);
  
      return hashTx.GetHex();
  }