예제 #1
0
UniValue createrawtransaction(const UniValue& params, bool fHelp)
{
    if (fHelp || (params.size() < 2 || params.size() > 3))
        throw runtime_error(
            "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...} [tx-comment]\n"
            "Create a transaction spending given inputs\n"
            "(array of objects containing transaction id and output number),\n"
            "sending to given address(es).\n"
            "Each <amount> is either an amount to send or {\"count\":c,\"amount\":a,\"locktime\":t}\n"
            "which adds <c> outputs each sending <a> CON with a locktime of <t>.\n"
            "The count <c> and locktime <t> are both optional.\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.");

    RPCTypeCheck(params, list_of(UniValue::VARR)(UniValue::VOBJ));

    UniValue inputs = params[0].get_array();
    UniValue sendTo = params[1].get_obj();

    CTransaction rawTx;

    // set conSpeech when creating a raw transaction
    if (params.size() == 3)
        rawTx.strCONSpeech = params[2].get_str();
    else if (mapArgs["-conspeech"] != "off")
        rawTx.strCONSpeech = GetDefaultConSpeech();

    if (rawTx.strCONSpeech.length() > MAX_TX_COMMENT_LEN)
        rawTx.strCONSpeech.resize(MAX_TX_COMMENT_LEN);

    for (unsigned int idx = 0; idx < inputs.size(); idx++)
    {
        const UniValue& input = inputs[idx];
        const UniValue& o = input.get_obj();

        const UniValue& txid_v = find_value(o, "txid");
        if (txid_v.isNull())
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
        string txid = txid_v.get_str();
        if (!IsHex(txid))
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex 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");

        CTxIn in(COutPoint(uint256(txid), nOutput));
        rawTx.vin.push_back(in);
    }

    // set<CBitcoinAddress> setAddress;
    vector<string> addrList = sendTo.getKeys();
    vector<UniValue> valueList= sendTo.getValues();
    vector<UniValue>::iterator valueList_iterator = valueList.begin();
    BOOST_FOREACH(const string& name_, addrList)
    {
        const UniValue& value_ = *valueList_iterator++;

        CBitcoinAddress address(name_);
        if (!address.IsValid())
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid PayCon address: ")+name_);

        // if (setAddress.count(address))
        //     throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
        // setAddress.insert(address);

        CScript scriptPubKey;
        scriptPubKey.SetDestination(address.Get());

        // we usually want the 2nd parameter to be {"addr1":ammount1,"addr2":ammount2,...}
        // in addition to numerical amounts we now also accept values like:
        //   '{"count":2,"amount":1.3,"locktime":333333}' meaning 'make 2 outputs worth 1.3 CON each, locked until block 333333'
        // "count" is a non-negative integer; 0 works and simply makes no new outputs
        // "locktime" is a non-negative integer; values less than LOCKTIME_THRESHOLD (500,000,000) are block heights; others are epoch timestamps
        if (value_.isObject()) {
            const UniValue& o = value_.get_obj();
            const UniValue& count_v = find_value(o, "count");
            const UniValue& locktime_v = find_value(o, "locktime");
            int64_t count, locktime;

            if (count_v.isNull())
                count = 1;
            else if (count_v.isNum())
                count = count_v.get_int64();
            else
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, count must be integer");

            if (count < 0)
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, count must not be negative");

            if (!locktime_v.isNull()) {
                if (locktime_v.isNum())
                    locktime = locktime_v.get_int64();
                else
                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime must be integer");

                if (locktime < 0)
                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime must not be negative");

                scriptPubKey.SetLockTime(locktime);
            }

            CTxOut out(AmountFromValue(find_value(o, "amount")), scriptPubKey);

            while (count--)
                rawTx.vout.push_back(out);
        } else {
            CTxOut out(AmountFromValue(value_), scriptPubKey);
            rawTx.vout.push_back(out);
        }
    }

    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
    ss << rawTx;
    return HexStr(ss.begin(), ss.end());
}
예제 #2
0
void DBBComServer::startLongPollThread()
{
    std::unique_lock<std::mutex> lock(cs_com);

    if (longPollThread)
        return;

    longPollThread = DBBNetThread::DetachThread();
    longPollThread->currentThread = std::thread([this]() {
        std::string response;
        long httpStatusCode;
        long sequence = 0;
        int errorCounts = 0;
        UniValue jsonOut;

        while(1)
        {
            response = "";
            httpStatusCode = 400;
            {
                // we store the channel ID to detect channelID changes during long poll 
                std::unique_lock<std::mutex> lock(cs_com);
                currentLongPollChannelID = channelID;
                currentLongPollURL = comServerURL;
            }
            SendRequest("post", currentLongPollURL, "c=gd&uuid="+currentLongPollChannelID+"&dt=0&s="+std::to_string(sequence), response, httpStatusCode);
            sequence++;

            if (httpStatusCode >= 300)
            {
                errorCounts++;
                if (errorCounts > 5)
                {
                    DBB::LogPrintDebug("Error, can't connect to the smart verification server");
                    // wait 10 seconds before the next try
                    std::this_thread::sleep_for(std::chrono::milliseconds(10000));
                }
                else
                    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
            }
            else
                errorCounts = 0;

            // ignore the response if the channel has been switched (re-pairing)
            {
                std::unique_lock<std::mutex> lock(cs_com);
                if (currentLongPollChannelID != channelID || currentLongPollURL != comServerURL)
                    continue;
            }

            jsonOut.read(response);
            if (jsonOut.isObject())
            {
                UniValue data = find_value(jsonOut, "data");
                if (data.isArray())
                {
                    for (const UniValue& element : data.getValues())
                    {
                        UniValue payload = find_value(element, "payload");
                        if (payload.isStr())
                        {
                            std::string plaintextPayload;
                            std::string keyS(encryptionKey.begin(), encryptionKey.end());
                            if (DBB::decryptAndDecodeCommand(payload.get_str(), keyS, plaintextPayload, false))
                            {
                                std::unique_lock<std::mutex> lock(cs_com);
                                if (parseMessageCB)
                                    parseMessageCB(this, plaintextPayload, ctx);
                            }

                            // mem-cleanse the key
                            std::fill(keyS.begin(), keyS.end(), 0);
                            keyS.clear();
                        }
                    }
                }
            }
        }
        std::unique_lock<std::mutex> lock(cs_com);
        longPollThread->completed();
    });
}