Exemple #1
0
void ScriptPubKeyToUniv(const CScript& scriptPubKey,
                        UniValue& out, bool fIncludeHex)
{
    txnouttype type;
    std::vector<CTxDestination> addresses;
    int nRequired;

    out.pushKV("asm", ScriptToAsmStr(scriptPubKey));
    if (fIncludeHex)
        out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()));

    if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
        out.pushKV("type", GetTxnOutputType(type));
        return;
    }

    out.pushKV("reqSigs", nRequired);
    out.pushKV("type", GetTxnOutputType(type));

    UniValue a(UniValue::VARR);
    for (const CTxDestination& addr : addresses)
        a.push_back(CBitcoinAddress(addr).ToString());
    out.pushKV("addresses", a);
}
Exemple #2
0
bool MultisigDialog::createMultisigTransaction(vector<CTxIn> vUserIn, vector<CTxOut> vUserOut, string& feeStringRet, string& errorRet)
{
    try{
        //attempt to access the given inputs
        CCoinsViewCache view = getInputsCoinsViewCache(vUserIn);

        //retrieve total input val and change dest
        CAmount totalIn = 0;
        vector<CAmount> vInputVals;
        CScript changePubKey;
        bool fFirst = true;

        for(CTxIn in : vUserIn){
            const CCoins* coins = view.AccessCoins(in.prevout.hash);
            if(!coins->IsAvailable(in.prevout.n) || coins == NULL){
                continue;
            }
            CTxOut prevout = coins->vout[in.prevout.n];
            CScript privKey = prevout.scriptPubKey;

            vInputVals.push_back(prevout.nValue);
            totalIn += prevout.nValue;

            if(!fFirst){
                if(privKey != changePubKey){
                    throw runtime_error("Address mismatch! Inputs must originate from the same multisignature address.");
                }
            }else{
                fFirst = false;
                changePubKey = privKey;
            }
        }

        CAmount totalOut = 0;

        //retrieve total output val
        for(CTxOut out : vUserOut){
            totalOut += out.nValue;
        }

        if(totalIn < totalOut){
            throw runtime_error("Not enough PIV provided as input to complete transaction (including fee).");
        }

        //calculate change amount
        CAmount changeAmount = totalIn - totalOut;
        CTxOut change(changeAmount, changePubKey);

        //generate random position for change
        unsigned int changeIndex = rand() % (vUserOut.size() + 1);

        //insert change into random position
        if(changeIndex < vUserOut.size()){
            vUserOut.insert(vUserOut.begin() + changeIndex, change);
        }else{
            vUserOut.emplace_back(change);
        }

        //populate tx
        CMutableTransaction tx;
        tx.vin = vUserIn;
        tx.vout = vUserOut;

        const CCoins* coins = view.AccessCoins(tx.vin[0].prevout.hash);

        if(coins == NULL || !coins->IsAvailable(tx.vin[0].prevout.n)){
            throw runtime_error("Coins unavailable (unconfirmed/spent)");
        }

        CScript prevPubKey = coins->vout[tx.vin[0].prevout.n].scriptPubKey;

        //get payment destination
        CTxDestination address;
        if(!ExtractDestination(prevPubKey, address)){
            throw runtime_error("Could not find address for destination.");
        }

        CScriptID hash = boost::get<CScriptID>(address);
        CScript redeemScript;

        if (!pwalletMain->GetCScript(hash, redeemScript)){
            throw runtime_error("could not redeem");
        }
        txnouttype type;
        vector<CTxDestination> addresses;
        int nReq;
        if(!ExtractDestinations(redeemScript, type, addresses, nReq)){
            throw runtime_error("Could not extract destinations from redeem script.");
        }

        for(CTxIn& in : tx.vin){
            in.scriptSig.clear();
            //scale estimate to account for multisig scriptSig
            for(unsigned int i = 0; i < 50*(nReq+addresses.size()); i++){
                in.scriptSig << INT64_MAX;
            }
        }

        //calculate fee
        unsigned int nBytes = tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
        CAmount fee = ::minRelayTxFee.GetFee(nBytes);

        if(tx.vout.at(changeIndex).nValue > fee){
           tx.vout.at(changeIndex).nValue -= fee;
           feeStringRet = strprintf("%d",((double)fee)/COIN).c_str();
        }else{
            throw runtime_error("Not enough PIV provided to cover fee");
        }

        //clear junk from script sigs
        for(CTxIn& in : tx.vin){
            in.scriptSig.clear();
        }
        multisigTx = tx;
    }catch(const runtime_error& e){
        errorRet = e.what();
        return false;
    }
    return true;
}