Esempio n. 1
0
Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<std::string>& errors, uint256& bumped_txid)
{
    LOCK2(cs_main, wallet->cs_wallet);
    if (!errors.empty()) {
        return Result::MISC_ERROR;
    }
    auto it = txid.IsNull() ? wallet->mapWallet.end() : wallet->mapWallet.find(txid);
    if (it == wallet->mapWallet.end()) {
        errors.push_back("Invalid or non-wallet transaction id");
        return Result::MISC_ERROR;
    }
    CWalletTx& oldWtx = it->second;

    // make sure the transaction still has no descendants and hasn't been mined in the meantime
    Result result = PreconditionChecks(wallet, oldWtx, errors);
    if (result != Result::OK) {
        return result;
    }

    CWalletTx wtxBumped(wallet, MakeTransactionRef(std::move(mtx)));
    // commit/broadcast the tx
    CReserveKey reservekey(wallet);
    wtxBumped.mapValue = oldWtx.mapValue;
    wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
    wtxBumped.vOrderForm = oldWtx.vOrderForm;
    wtxBumped.strFromAccount = oldWtx.strFromAccount;
    wtxBumped.fTimeReceivedIsTxTime = true;
    wtxBumped.fFromMe = true;
    CValidationState state;
    if (!wallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
        // NOTE: CommitTransaction never returns false, so this should never happen.
        errors.push_back(strprintf("The transaction was rejected: %s", state.GetRejectReason()));
        return Result::WALLET_ERROR;
    }

    bumped_txid = wtxBumped.GetHash();
    if (state.IsInvalid()) {
        // This can happen if the mempool rejected the transaction.  Report
        // what happened in the "errors" response.
        errors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
    }

    // mark the original tx as bumped
    if (!wallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
        // TODO: see if JSON-RPC has a standard way of returning a response
        // along with an exception. It would be good to return information about
        // wtxBumped to the caller even if marking the original transaction
        // replaced does not succeed for some reason.
        errors.push_back("Created new bumpfee transaction but could not mark the original transaction as replaced");
    }
    return Result::OK;
}
Esempio n. 2
0
bool CFeeBumper::commit(CWallet *pWallet)
{
    AssertLockHeld(pWallet->cs_wallet);
    if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {
        return false;
    }
    if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
        vErrors.push_back("Invalid or non-wallet transaction id");
        currentResult = BumpFeeResult::MISC_ERROR;
        return false;
    }
    CWalletTx& oldWtx = pWallet->mapWallet[txid];

    // make sure the transaction still has no descendants and hasen't been mined in the meantime
    if (!preconditionChecks(pWallet, oldWtx)) {
        return false;
    }

    CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
    // commit/broadcast the tx
    CReserveKey reservekey(pWallet);
    wtxBumped.mapValue = oldWtx.mapValue;
    wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
    wtxBumped.vOrderForm = oldWtx.vOrderForm;
    wtxBumped.strFromAccount = oldWtx.strFromAccount;
    wtxBumped.fTimeReceivedIsTxTime = true;
    wtxBumped.fFromMe = true;
    CValidationState state;
    if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
        // NOTE: CommitTransaction never returns false, so this should never happen.
        vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
        return false;
    }

    bumpedTxid = wtxBumped.GetHash();
    if (state.IsInvalid()) {
        // This can happen if the mempool rejected the transaction.  Report
        // what happened in the "errors" response.
        vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
    }

    // mark the original tx as bumped
    if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
        // TODO: see if JSON-RPC has a standard way of returning a response
        // along with an exception. It would be good to return information about
        // wtxBumped to the caller even if marking the original transaction
        // replaced does not succeed for some reason.
        vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
    }
    return true;
}
Esempio n. 3
0
 CWalletTx& AddTx(CRecipient recipient)
 {
     CWalletTx wtx;
     CReserveKey reservekey(wallet.get());
     CAmount fee;
     int changePos = -1;
     std::string error;
     CCoinControl dummy;
     BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
     CValidationState state;
     BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
     auto it = wallet->mapWallet.find(wtx.GetHash());
     BOOST_CHECK(it != wallet->mapWallet.end());
     CreateAndProcessBlock({CMutableTransaction(*it->second.tx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
     it->second.SetMerkleBranch(chainActive.Tip(), 1);
     return it->second;
 }
void NewAccountDialog::showSyncQr()
{
    WalletModel::UnlockContext ctx(walletModel->requestUnlock());
    if (ctx.isValid()) {
        newAccount = pwalletMain->GenerateNewAccount(ui->newAccountName->text().toStdString(), AccountType::Normal, AccountSubType::Mobi);
        LOCK(pwalletMain->cs_wallet);
        {
            int64_t currentTime = newAccount->getEarliestPossibleCreationTime();

            std::string payoutAddress;
            CReserveKey reservekey(pwalletMain, newAccount, KEYCHAIN_CHANGE);
            CPubKey vchPubKey;
            if (!reservekey.GetReservedKey(vchPubKey))
                return;
            payoutAddress = CBitcoinAddress(vchPubKey.GetID()).ToString();

            QString qrString = QString::fromStdString("guldensync:" + CBitcoinSecretExt(*newAccount->GetAccountMasterPrivKey()).ToString(QString::number(currentTime).toStdString(), payoutAddress));
            ui->scanQRCode->setCode(qrString);

            disconnect(this, SLOT(showSyncQr()));
        }
    }
}
Esempio n. 5
0
UniValue gobject(const JSONRPCRequest& request)
{
    std::string strCommand;
    if (request.params.size() >= 1)
        strCommand = request.params[0].get_str();

    if (request.fHelp  ||
        (
#ifdef ENABLE_WALLET
         strCommand != "prepare" &&
#endif // ENABLE_WALLET
         strCommand != "vote-many" && strCommand != "vote-conf" && strCommand != "vote-name" && strCommand != "submit" && strCommand != "count" &&
         strCommand != "deserialize" && strCommand != "get" && strCommand != "getvotes" && strCommand != "getcurrentvotes" && strCommand != "list" && strCommand != "diff" &&
         strCommand != "check" ))
        throw std::runtime_error(
                "gobject \"command\"...\n"
                "Manage governance objects\n"
                "\nAvailable commands:\n"
                "  check              - Validate governance object data (proposal only)\n"
#ifdef ENABLE_WALLET
                "  prepare            - Prepare governance object by signing and creating tx\n"
#endif // ENABLE_WALLET
                "  submit             - Submit governance object to network\n"
                "  deserialize        - Deserialize governance object from hex string to JSON\n"
                "  count              - Count governance objects and votes (additional param: 'json' or 'all', default: 'json')\n"
                "  get                - Get governance object by hash\n"
                "  getvotes           - Get all votes for a governance object hash (including old votes)\n"
                "  getcurrentvotes    - Get only current (tallying) votes for a governance object hash (does not include old votes)\n"
                "  list               - List governance objects (can be filtered by signal and/or object type)\n"
                "  diff               - List differences since last diff\n"
                "  vote-name         - Vote on a governance object by masternode name (using masternode.conf setup)\n"
                "  vote-conf          - Vote on a governance object by masternode configured in syscoin.conf\n"
                "  vote-many          - Vote on a governance object by all masternodes (using masternode.conf setup)\n"
                );


    if(strCommand == "count") {
        std::string strMode{"json"};

        if (request.params.size() == 2) {
            strMode = request.params[1].get_str();
        }

        if (request.params.size() > 2 || (strMode != "json" && strMode != "all")) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'gobject count ( \"json\"|\"all\" )'");
        }

        return strMode == "json" ? governance.ToJson() : governance.ToString();
    }
    /*
        ------ Example Governance Item ------

        gobject submit 6e622bb41bad1fb18e7f23ae96770aeb33129e18bd9efe790522488e580a0a03 0 1 1464292854 "beer-reimbursement" 5b5b22636f6e7472616374222c207b2270726f6a6563745f6e616d65223a20225c22626565722d7265696d62757273656d656e745c22222c20227061796d656e745f61646472657373223a20225c225879324c4b4a4a64655178657948726e34744744514238626a6876464564615576375c22222c2022656e645f64617465223a202231343936333030343030222c20226465736372697074696f6e5f75726c223a20225c227777772e646173687768616c652e6f72672f702f626565722d7265696d62757273656d656e745c22222c2022636f6e74726163745f75726c223a20225c22626565722d7265696d62757273656d656e742e636f6d2f3030312e7064665c22222c20227061796d656e745f616d6f756e74223a20223233342e323334323232222c2022676f7665726e616e63655f6f626a6563745f6964223a2037342c202273746172745f64617465223a202231343833323534303030227d5d5d1
    */

    // DEBUG : TEST DESERIALIZATION OF GOVERNANCE META DATA
    if(strCommand == "deserialize")
    {
        if (request.params.size() != 2) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'gobject deserialize <data-hex>'");
        }

        std::string strHex = request.params[1].get_str();

        std::vector<unsigned char> v = ParseHex(strHex);
        std::string s(v.begin(), v.end());

        UniValue u(UniValue::VOBJ);
        u.read(s);

        return u.write().c_str();
    }

    // VALIDATE A GOVERNANCE OBJECT PRIOR TO SUBMISSION
    if(strCommand == "check")
    {
        if (request.params.size() != 2) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'gobject check <data-hex>'");
        }

        // ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS

        uint256 hashParent;

        int nRevision = 1;

        int64_t nTime = GetAdjustedTime();
        std::string strDataHex = request.params[1].get_str();

        CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strDataHex);

        if(govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
            CProposalValidator validator(strDataHex);
            if(!validator.Validate())  {
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
            }
        }
        else {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid object type, only proposals can be validated");
        }

        UniValue objResult(UniValue::VOBJ);

        objResult.push_back(Pair("Object status", "OK"));

        return objResult;
    }

#ifdef ENABLE_WALLET
    // PREPARE THE GOVERNANCE OBJECT BY CREATING A COLLATERAL TRANSACTION
    if(strCommand == "prepare")
    {
        if (!EnsureWalletIsAvailable(request.fHelp))
            return NullUniValue;

        if (request.params.size() != 5) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'gobject prepare <parent-hash> <revision> <time> <data-hex>'");
        }

        // ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS

        uint256 hashParent;

        // -- attach to root node (root node doesn't really exist, but has a hash of zero)
        if(request.params[1].get_str() == "0") {
            hashParent = uint256();
        } else {
            hashParent = ParseHashV(request.params[1], "fee-txid, parameter 1");
        }

        std::string strRevision = request.params[2].get_str();
        std::string strTime = request.params[3].get_str();
        int nRevision = atoi(strRevision);
        int64_t nTime = atoi64(strTime);
        std::string strDataHex = request.params[4].get_str();

        // CREATE A NEW COLLATERAL TRANSACTION FOR THIS SPECIFIC OBJECT

        CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strDataHex);

        if(govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
            CProposalValidator validator(strDataHex);
            if(!validator.Validate())  {
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
            }
        }

        if(govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Trigger objects need not be prepared (however only masternodes can create them)");
        }

        if(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Watchdogs are deprecated");
        }
		{
			LOCK(cs_main);
			std::string strError = "";
			if (!govobj.IsValidLocally(strError, false))
				throw JSONRPCError(RPC_INTERNAL_ERROR, "Governance object is not valid - " + govobj.GetHash().ToString() + " - " + strError);
		}
        EnsureWalletIsUnlocked();

        CWalletTx wtx;
        if(!pwalletMain->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), false)) {
            throw JSONRPCError(RPC_INTERNAL_ERROR, "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked.");
        }

        // -- make our change address
        CReserveKey reservekey(pwalletMain);
        // -- send the tx to the network
        CValidationState state;
        if (!pwalletMain->CommitTransaction(wtx, reservekey, g_connman.get(), state, NetMsgType::TX)) {
            throw JSONRPCError(RPC_INTERNAL_ERROR, "CommitTransaction failed! Reason given: " + state.GetRejectReason());
        }

        DBG( std::cout << "gobject: prepare "
             << " GetDataAsPlainString = " << govobj.GetDataAsPlainString()
             << ", hash = " << govobj.GetHash().GetHex()
             << ", txidFee = " << wtx.GetHash().GetHex()
             << std::endl; );

        return wtx.GetHash().ToString();
    }
void ReceiveCoinsDialog::generateRequest()
{

    CReserveKey reservekey(pwalletMain, model->getActiveAccount(), KEYCHAIN_EXTERNAL);
    CPubKey vchPubKey;
    if (!reservekey.GetReservedKey(vchPubKey)) {

        return;
    }
    reservekey.KeepKey();

    ui->receiveCoinsStackedWidget->setCurrentIndex(3);
    ui->accountRequestPaymentButtonComposite->setVisible(false);
    ui->accountBuyGuldenButton->setVisible(false);
    ui->accountSaveQRButtonComposite->setVisible(true);
    ui->accountCopyToClipboardButtonComposite->setVisible(true);
    ui->cancelButton->setVisible(false);
    ui->closeButton->setVisible(true);
    ui->cancelButtonGroup->setVisible(true);
    ui->generateRequestButton->setVisible(false);
    ui->generateAnotherRequestButton->setVisible(true);
    ui->accountBuyButton->setVisible(false);

    ui->accountCopyToClipboardButton->setText(tr("Copy request to clipboard"));

    CAmount amount = ui->requestAmount->value();
    if (amount > 0) {
        ui->labelPaymentRequestHeading->setText(tr("Request %1 Gulden").arg(BitcoinUnits::format(BitcoinUnits::BTC, amount, false, BitcoinUnits::separatorStandard, 2)));
    } else {
        ui->labelPaymentRequestHeading->setText(tr("Request Gulden"));
    }

    QString args;
    QString label = QUrl::toPercentEncoding(ui->requestLabel->text());
    QString strAmount;
    if (!label.isEmpty()) {
        label = "label=" + label;
    }
    if (amount > 0) {
        strAmount = "amount=" + QUrl::toPercentEncoding(BitcoinUnits::format(BitcoinUnits::BTC, amount, false, BitcoinUnits::separatorNever, -1));

        while (strAmount.endsWith("0")) {
            strAmount.chop(1);
        }
        if (strAmount.endsWith(".")) {
            strAmount.chop(1);
        }
    }
    if (!strAmount.isEmpty() && !label.isEmpty()) {
        args = "?" + label + "&" + strAmount;
    } else if (!strAmount.isEmpty()) {
        args = "?" + strAmount;
    } else if (!label.isEmpty()) {
        args = "?" + label;
    }

    QString uri = QString("Gulden:") + QString::fromStdString(CBitcoinAddress(vchPubKey.GetID()).ToString()) + args;
    ui->labelPaymentRequest->setText(uri);
    if (!uri.isEmpty()) {

        if (uri.length() > MAX_URI_LENGTH) {
            ui->requestQRImage->setFixedWidth(900);
            ui->requestQRImage->setText(tr("Resulting URI too long, try to reduce the text for the label."));
        } else {
            ui->requestQRImage->setText("");
            ui->requestQRImage->setFixedWidth(ui->requestQRImage->height());
            ui->requestQRImage->setCode(uri);
        }
    }

    pwalletMain->SetAddressBook(CBitcoinAddress(vchPubKey.GetID()).ToString(), ui->requestLabel->text().toStdString(), "receive");
}
Esempio n. 7
0
WalletModel::SendCoinsReturn WalletModel::createRawTransaction(
    const QList<SendCoinsRecipient> &recipients, CTransaction& txNew, const CCoinControl *coinControl, bool isMultiSig)
{
    qint64 total = 0;
    QSet<QString> setAddress;
    QString hex;

    if(recipients.empty())
    {
        return OK;
    }

    // Pre-check input data for validity
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        if(!validateAddress(rcp.address))
        {
            return InvalidAddress;
        }
        setAddress.insert(rcp.address);

        if(rcp.amount <= 0)
        {
            return InvalidAmount;
        }
        total += rcp.amount;
    }

    if(recipients.size() > setAddress.size())
    {
        return DuplicateAddress;
    }

    int64 nBalance;
    if ( isMultiSig )
        nBalance = getSharedBalance(coinControl);
    else
        nBalance = getBalance(coinControl);

    if(total > nBalance)
    {
        return AmountExceedsBalance;
    }

    if((total + nTransactionFee) > nBalance)
    {
        return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
    }

    {
        LOCK2(cs_main, wallet->cs_wallet);

        // Sendmany
        std::vector<std::pair<CScript, int64> > vecSend;
        foreach(const SendCoinsRecipient &rcp, recipients)
        {
            CScript scriptPubKey;
            scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
            vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
        }

        int64 nFeeRequired = 0;
        std::string strFailReason;
        CReserveKey reservekey(wallet);
        bool fCreated = wallet->CreateRawTransaction(vecSend, txNew, nFeeRequired, strFailReason, isMultiSig, reservekey, coinControl);

        if(!fCreated)
        {
            if((total + nFeeRequired) > nBalance)
            {
                return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
            }
            emit message(tr("Send Coins"), QString::fromStdString(strFailReason),
                         CClientUIInterface::MSG_ERROR);
            return TransactionCreationFailed;
        }
        /*if(!uiInterface.ThreadSafeAskFee(nFeeRequired))
        {
            return Aborted;
        }*/
        hex = QString::fromStdString(txNew.GetHash().GetHex());
    }