src/omnicore/wallettxbuilder.cpp
/**
 * Creates and sends a raw transaction by selecting all coins from the sender
 * and enough coins from a fee source. Change is sent to the fee source!
 */
Creates and sends a raw transaction by selecting all coins from the sender
and enough coins from a fee source. Change is sent to the fee source!
Creates and sends a raw transaction by selecting all coins from the sender and enough coins from a fee source . Change is sent to the fee source!
int CreateFundedTransaction(
        const std::string& senderAddress,
        const std::string& receiverAddress,
        const std::string& feeAddress,
        const std::vector<unsigned char>& payload,
        uint256& retTxid,
        interfaces::Wallet* iWallet)
{
    if (!iWallet) {
        return MP_ERR_WALLET_ACCESS;
    }
    if (!UseEncodingClassC(payload.size())) {
        return MP_ENCODING_ERROR;
    }
    std::vector<std::pair<CScript, int64_t> > vecSend;
    if (!OmniCore_Encode_ClassC(payload, vecSend)) {
        return MP_ENCODING_ERROR;
    }
    std::vector<CTxOut>::size_type max_outputs = 2;
    if (!receiverAddress.empty() && receiverAddress != feeAddress) {
        max_outputs = 3;
        CScript scriptPubKey = GetScriptForDestination(DecodeDestination(receiverAddress));
        vecSend.push_back(std::make_pair(scriptPubKey, OmniGetDustThreshold(scriptPubKey)));
    }
    std::vector<CRecipient> vecRecipients;
    for (size_t i = 0; i < vecSend.size(); ++i) {
        const std::pair<CScript, int64_t>& vec = vecSend[i];
        CRecipient recipient = {vec.first, vec.second, false};
        vecRecipients.push_back(recipient);
    }
    bool fSuccess = false;
    CAmount nFeeRequired = 0;
    std::string strFailReason;
    int nChangePosRet = 0; 
    CCoinControl coinControl;
    coinControl.destChange = DecodeDestination(feeAddress);
    coinControl.fAllowOtherInputs = true;
    if (!mastercore::SelectAllCoins(*iWallet, senderAddress, coinControl)) {
        PrintToLog("%s: ERROR: sender %s has no coins\n", __func__, senderAddress);
        return MP_INPUTS_INVALID;
    }
    std::set<CTxDestination> feeSources;
    feeSources.insert(DecodeDestination(feeAddress));
    std::vector<COutPoint> vLockedCoins;
    LockUnrelatedCoins(iWallet, feeSources, vLockedCoins);
    auto wtxNew = iWallet->createTransaction(vecRecipients, coinControl, false , nChangePosRet, nFeeRequired, strFailReason, true);
    if (wtxNew) {
        fSuccess = true;
    }
    if (fSuccess && nChangePosRet == -1 && receiverAddress == feeAddress) {
        fSuccess = false;
        strFailReason = "send to self without change";
    }
    if (fSuccess && wtxNew->get().vout.size() > max_outputs)
    {
        strFailReason = "more outputs than expected";
        PrintToLog("%s: ERROR: more outputs than expected (Max expected %d, actual %d)\n Failed transaction: %s\n",
                   __func__, max_outputs, wtxNew->get().vout.size(), wtxNew->get().ToString());
    }
    CMutableTransaction tx;
    if (fSuccess)
    {
        std::vector<COutPoint> vSelectedInputs;
        coinControl.ListSelected(vSelectedInputs);
        for(const COutPoint& txIn : vSelectedInputs) {
            tx.vin.push_back(CTxIn(txIn));
        }
        for(const CTxIn& txin : wtxNew->get().vin) {
            if (!coinControl.IsSelected(txin.prevout)) {
                tx.vin.push_back(txin);
            }
        }
        for(const CTxOut& txOut : wtxNew->get().vout) {
            tx.vout.push_back(txOut);
        }
    }
    UnlockCoins(iWallet, vLockedCoins);
    if (fSuccess) {
        for(const CTxIn& txIn : tx.vin) {
            iWallet->lockCoin(txIn.prevout);
        }
    }
    if (!fSuccess) {
        PrintToLog("%s: ERROR: wallet transaction creation failed: %s\n", __func__, strFailReason);
        return MP_ERR_CREATE_TX;
    }
    CCoinsView viewDummy;
    CCoinsViewCache view(&viewDummy);
    {
        LOCK(mempool.cs);
        CCoinsViewCache &viewChain = *pcoinsTip;
        CCoinsViewMemPool viewMempool(&viewChain, mempool);
        view.SetBackend(viewMempool); 
        for(const CTxIn& txin : tx.vin) {
            const auto& prevout = txin.prevout;
            view.AccessCoin(prevout); 
        }
        view.SetBackend(viewDummy); 
    }
    int nHashType = SIGHASH_ALL;
    for (unsigned int i = 0; i < tx.vin.size(); i++) {
        CTxIn& txin = tx.vin[i];
        const Coin& coin = view.AccessCoin(txin.prevout);
        if (coin.IsSpent()) {
            PrintToLog("%s: ERROR: wallet transaction signing failed: input not found or already spent\n", __func__);
            continue;
        }
        const CScript& prevPubKey = coin.out.scriptPubKey;
        const CAmount& amount = coin.out.nValue;
        SignatureData sigdata;
        if (!iWallet->produceSignature(MutableTransactionSignatureCreator(&tx, i, amount, nHashType), prevPubKey, sigdata)) {
            PrintToLog("%s: ERROR: wallet transaction signing failed\n", __func__);
            return MP_ERR_CREATE_TX;
        }
        UpdateInput(txin, sigdata);
    }
    CValidationState state;
    bool missing_inputs;
    CTransactionRef ctx(MakeTransactionRef(std::move(tx)));
    {
        LOCK(cs_main);
        if (!AcceptToMemoryPool(mempool, state, ctx, &missing_inputs, nullptr, false, DEFAULT_TRANSACTION_MAXFEE)) {
            PrintToLog("%s: ERROR: failed to broadcast transaction: %s\n", __func__, state.GetRejectReason());
            return MP_ERR_COMMIT_TX;
        }
    }
    uint256 txid;
    std::string err_string;
    const TransactionError err = BroadcastTransaction(ctx, txid, err_string, true);
    if (TransactionError::OK != err) {
        LogPrintf("%s: BroadcastTransaction failed error: %s\n", __func__, err_string);
    }
    retTxid = txid;
    return 0;
}
int CreateFundedTransaction ( const std :: string & senderAddress , const std :: string & receiverAddress , const std :: string & feeAddress , const std :: vector < unsigned char > & payload , uint256 & retTxid , interfaces :: Wallet * iWallet ) { if ( ! iWallet ) { return MP_ERR_WALLET_ACCESS ; } if ( ! UseEncodingClassC ( payload . size ( ) ) ) { return MP_ENCODING_ERROR ; } std :: vector < std :: pair < CScript , int64_t > > vecSend ; if ( ! OmniCore_Encode_ClassC ( payload , vecSend ) ) { return MP_ENCODING_ERROR ; } std :: vector < CTxOut > :: size_type max_outputs = 2 ; if ( ! receiverAddress . empty ( ) && receiverAddress != feeAddress ) { max_outputs = 3 ; CScript scriptPubKey = GetScriptForDestination ( DecodeDestination ( receiverAddress ) ) ; vecSend . push_back ( std :: make_pair ( scriptPubKey , OmniGetDustThreshold ( scriptPubKey ) ) ) ; } std :: vector < CRecipient > vecRecipients ; for ( size_t i = 0 ; i < vecSend . size ( ) ; ++ i ) { const std :: pair < CScript , int64_t > & vec = vecSend [ i ] ; CRecipient recipient = { vec . first , vec . second , false } ; vecRecipients . push_back ( recipient ) ; } bool fSuccess = false ; CAmount nFeeRequired = 0 ; std :: string strFailReason ; int nChangePosRet = 0 ; CCoinControl coinControl ; coinControl . destChange = DecodeDestination ( feeAddress ) ; coinControl . fAllowOtherInputs = true ; if ( ! mastercore :: SelectAllCoins ( * iWallet , senderAddress , coinControl ) ) { PrintToLog ( " \n " , __func__ , senderAddress ) ; return MP_INPUTS_INVALID ; } std :: set < CTxDestination > feeSources ; feeSources . insert ( DecodeDestination ( feeAddress ) ) ; std :: vector < COutPoint > vLockedCoins ; LockUnrelatedCoins ( iWallet , feeSources , vLockedCoins ) ; auto wtxNew = iWallet -> createTransaction ( vecRecipients , coinControl , false , nChangePosRet , nFeeRequired , strFailReason , true ) ; if ( wtxNew ) { fSuccess = true ; } if ( fSuccess && nChangePosRet == -1 && receiverAddress == feeAddress ) { fSuccess = false ; strFailReason = " " ; } if ( fSuccess && wtxNew -> get ( ) . vout . size ( ) > max_outputs ) { strFailReason = " " ; PrintToLog ( " \n \n " , __func__ , max_outputs , wtxNew -> get ( ) . vout . size ( ) , wtxNew -> get ( ) . ToString ( ) ) ; } CMutableTransaction tx ; if ( fSuccess ) { std :: vector < COutPoint > vSelectedInputs ; coinControl . ListSelected ( vSelectedInputs ) ; for ( const COutPoint & txIn : vSelectedInputs ) { tx . vin . push_back ( CTxIn ( txIn ) ) ; } for ( const CTxIn & txin : wtxNew -> get ( ) . vin ) { if ( ! coinControl . IsSelected ( txin . prevout ) ) { tx . vin . push_back ( txin ) ; } } for ( const CTxOut & txOut : wtxNew -> get ( ) . vout ) { tx . vout . push_back ( txOut ) ; } } UnlockCoins ( iWallet , vLockedCoins ) ; if ( fSuccess ) { for ( const CTxIn & txIn : tx . vin ) { iWallet -> lockCoin ( txIn . prevout ) ; } } if ( ! fSuccess ) { PrintToLog ( " \n " , __func__ , strFailReason ) ; return MP_ERR_CREATE_TX ; } CCoinsView viewDummy ; CCoinsViewCache view ( & viewDummy ) ; { LOCK ( mempool . cs ) ; CCoinsViewCache & viewChain = * pcoinsTip ; CCoinsViewMemPool viewMempool ( & viewChain , mempool ) ; view . SetBackend ( viewMempool ) ; for ( const CTxIn & txin : tx . vin ) { const auto & prevout = txin . prevout ; view . AccessCoin ( prevout ) ; } view . SetBackend ( viewDummy ) ; } int nHashType = SIGHASH_ALL ; for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i ++ ) { CTxIn & txin = tx . vin [ i ] ; const Coin & coin = view . AccessCoin ( txin . prevout ) ; if ( coin . IsSpent ( ) ) { PrintToLog ( " \n " , __func__ ) ; continue ; } const CScript & prevPubKey = coin . out . scriptPubKey ; const CAmount & amount = coin . out . nValue ; SignatureData sigdata ; if ( ! iWallet -> produceSignature ( MutableTransactionSignatureCreator ( & tx , i , amount , nHashType ) , prevPubKey , sigdata ) ) { PrintToLog ( " \n " , __func__ ) ; return MP_ERR_CREATE_TX ; } UpdateInput ( txin , sigdata ) ; } CValidationState state ; bool missing_inputs ; CTransactionRef ctx ( MakeTransactionRef ( std :: move ( tx ) ) ) ; { LOCK ( cs_main ) ; if ( ! AcceptToMemoryPool ( mempool , state , ctx , & missing_inputs , nullptr , false , DEFAULT_TRANSACTION_MAXFEE ) ) { PrintToLog ( " \n " , __func__ , state . GetRejectReason ( ) ) ; return MP_ERR_COMMIT_TX ; } } uint256 txid ; std :: string err_string ; const TransactionError err = BroadcastTransaction ( ctx , txid , err_string , true ) ; if ( TransactionError :: OK != err ) { LogPrintf ( " \n " , __func__ , err_string ) ; } retTxid = txid ; return 0 ; }
Creates and sends a raw transaction by selecting all coins from the sender
 and enough coins from a fee source.
Creates and sends a raw transaction by selecting all coins from the sender and enough coins from a fee source .
// add payload output // Maximum number of expected outputs // add reference output, if there is one // convert into recipients objects // add change first // set change // prepare sources for fees /* sign */ // to restore the original order of inputs, create a new transaction and add // inputs and outputs step by step // add previously selected coins // add other selected coins // add outputs // restore original locking state // lock selected outputs for this transaction // TODO: could be removed? // sign the transaction // fetch previous transactions (inputs): // temporarily switch cache backend to db+mempool view // this is certainly allowed to fail // switch back to avoid locking mempool for too long // send the transaction