static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput) { CAmount value = 0; // separate [VALUE:]DATA in string size_t pos = strInput.find(':'); if (pos==0) throw std::runtime_error("TX output value not specified"); if (pos != std::string::npos) { // extract and validate VALUE std::string strValue = strInput.substr(0, pos); if (!ParseMoney(strValue, value)) throw std::runtime_error("invalid TX output value"); } // extract and validate DATA std::string strData = strInput.substr(pos + 1, std::string::npos); if (!IsHex(strData)) throw std::runtime_error("invalid TX output data"); std::vector<unsigned char> data = ParseHex(strData); CTxOut txout(value, CScript() << OP_RETURN << data); tx.vout.push_back(txout); }
static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) { // separate VALUE:ADDRESS in string size_t pos = strInput.find(':'); if ((pos == std::string::npos) || (pos == 0) || (pos == (strInput.size() - 1))) throw std::runtime_error("TX output missing separator"); // extract and validate VALUE std::string strValue = strInput.substr(0, pos); CAmount value; if (!ParseMoney(strValue, value)) throw std::runtime_error("invalid TX output value"); // extract and validate ADDRESS std::string strAddr = strInput.substr(pos + 1, std::string::npos); CBitcoinAddress addr(strAddr); if (!addr.IsValid()) throw std::runtime_error("invalid TX output address"); // build standard output script via GetScriptForDestination() CScript scriptPubKey = GetScriptForDestination(addr.Get()); // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); }
int CPrivateSend::GetDenominationsByAmounts(const std::vector<CAmount>& vecAmount) { CScript scriptTmp = CScript(); std::vector<CTxOut> vecTxOut; BOOST_REVERSE_FOREACH(CAmount nAmount, vecAmount) { CTxOut txout(nAmount, scriptTmp); vecTxOut.push_back(txout); }
static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) { // separate VALUE:SCRIPT[:FLAGS] std::vector<std::string> vStrInputParts; boost::split(vStrInputParts, strInput, boost::is_any_of(":")); if (vStrInputParts.size() < 2) throw std::runtime_error("TX output missing separator"); // Extract and validate VALUE CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // extract and validate script std::string strScript = vStrInputParts[1]; CScript scriptPubKey = ParseScript(strScript); // Extract FLAGS bool bSegWit = false; bool bScriptHash = false; if (vStrInputParts.size() == 3) { std::string flags = vStrInputParts.back(); bSegWit = (flags.find('W') != std::string::npos); bScriptHash = (flags.find('S') != std::string::npos); } if (scriptPubKey.size() > MAX_SCRIPT_SIZE) { throw std::runtime_error(strprintf( "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE)); } if (bSegWit) { scriptPubKey = GetScriptForWitness(scriptPubKey); } if (bScriptHash) { if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) { throw std::runtime_error(strprintf( "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); }
static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput) { // Separate into VALUE:PUBKEY[:FLAGS] std::vector<std::string> vStrInputParts; boost::split(vStrInputParts, strInput, boost::is_any_of(":")); if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3) throw std::runtime_error("TX output missing or too many separators"); // Extract and validate VALUE CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // Extract and validate PUBKEY CPubKey pubkey(ParseHex(vStrInputParts[1])); if (!pubkey.IsFullyValid()) throw std::runtime_error("invalid TX output pubkey"); CScript scriptPubKey = GetScriptForRawPubKey(pubkey); // Extract and validate FLAGS bool bSegWit = false; bool bScriptHash = false; if (vStrInputParts.size() == 3) { std::string flags = vStrInputParts[2]; bSegWit = (flags.find('W') != std::string::npos); bScriptHash = (flags.find('S') != std::string::npos); } if (bSegWit) { if (!pubkey.IsCompressed()) { throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); } // Call GetScriptForWitness() to build a P2WSH scriptPubKey scriptPubKey = GetScriptForWitness(scriptPubKey); } if (bScriptHash) { // Get the ID for the script, and then construct a P2SH destination for it. scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); }
std::vector<std::shared_ptr<CoinDB::TxOut>> CreateTxDialog::getTxOuts() { std::vector<std::shared_ptr<CoinDB::TxOut>> txouts; std::set<TxOutLayout*> txOutLayoutsCopy = txOutLayouts; for (auto& txOutLayout: txOutLayoutsCopy) { if (txOutLayout->getAddress().isEmpty()) { removeTxOut(txOutLayout); continue; } std::shared_ptr<CoinDB::TxOut> txout(new CoinDB::TxOut(txOutLayout->getValue(), txOutLayout->getScript())); txout->sending_label(txOutLayout->getRecipient().toStdString()); txouts.push_back(txout); } if (txouts.empty()) { addTxOut(); throw std::runtime_error("No outputs entered."); } return txouts; }
void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { if (!model) return; // nPayAmount CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts) { nPayAmount += amount; if (amount > 0) { CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0)); txDummy.vout.push_back(txout); if (txout.IsDust(::minRelayTxFee)) fDust = true; } }
bool TestChainForComputingMediansSetup::GenerateRandomTransaction(CTransaction& txNew) { CAmount amountToSend = 5000; std::vector<CTransaction> res; CKey key; key.MakeNewKey(true); CScript scriptPubKey = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; CBasicKeyStore keystore; keystore.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); CTransaction utxo = coinbaseTxns[0]; coinbaseTxns.erase(coinbaseTxns.begin()); txNew.nLockTime = chainActive.Height(); txNew.vin.clear(); txNew.vout.clear(); for (int j = 0; j < nOutputs; ++j) { CTxOut txout(amountToSend, scriptPubKey); txNew.vout.push_back(txout); } //vin CTxIn vin = CTxIn(utxo.GetHash(), 0, CScript(), std::numeric_limits<unsigned int>::max() - 1); txNew.vin.push_back(vin); //previous tx's script pub key that we need to sign CScript& scriptSigRes = txNew.vin[0].scriptSig; CTransaction txNewConst(txNew); ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0), utxo.vout[0].scriptPubKey, scriptSigRes); res.push_back(txNew); return true; }
static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) { // separate VALUE:SCRIPT in string size_t pos = strInput.find(':'); if ((pos == std::string::npos) || (pos == 0)) throw std::runtime_error("TX output missing separator"); // extract and validate VALUE std::string strValue = strInput.substr(0, pos); CAmount value; if (!ParseMoney(strValue, value)) throw std::runtime_error("invalid TX output value"); // extract and validate script std::string strScript = strInput.substr(pos + 1, std::string::npos); CScript scriptPubKey = ParseScript(strScript); // throws on err // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); }
static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) { // Separate into VALUE:ADDRESS std::vector<std::string> vStrInputParts; boost::split(vStrInputParts, strInput, boost::is_any_of(":")); if (vStrInputParts.size() != 2) throw std::runtime_error("TX output missing or too many separators"); // Extract and validate VALUE CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // extract and validate ADDRESS std::string strAddr = vStrInputParts[1]; CTxDestination destination = DecodeDestination(strAddr); if (!IsValidDestination(destination)) { throw std::runtime_error("invalid TX output address"); } CScript scriptPubKey = GetScriptForDestination(destination); // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); }
void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { if (!model) return; // nPayAmount CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; for (const CAmount &amount : CoinControlDialog::payAmounts) { nPayAmount += amount; if (amount > 0) { CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0)); txDummy.vout.push_back(txout); fDust |= IsDust(txout, ::dustRelayFee); } } CAmount nAmount = 0; CAmount nPayFee = 0; CAmount nAfterFee = 0; CAmount nChange = 0; unsigned int nBytes = 0; unsigned int nBytesInputs = 0; unsigned int nQuantity = 0; bool fWitness = false; std::vector<COutPoint> vCoinControl; std::vector<COutput> vOutputs; coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); for (const COutput& out : vOutputs) { // unselect already spent, very unlikely scenario, this could happen // when selected are spent elsewhere, like rpc or another computer uint256 txhash = out.tx->GetHash(); COutPoint outpt(txhash, out.i); if (model->isSpent(outpt)) { coinControl->UnSelect(outpt); continue; } // Quantity nQuantity++; // Amount nAmount += out.tx->tx->vout[out.i].nValue; // Bytes CTxDestination address; int witnessversion = 0; std::vector<unsigned char> witnessprogram; if (out.tx->tx->vout[out.i].scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { nBytesInputs += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4); fWitness = true; } else if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) { CPubKey pubkey; CKeyID *keyid = boost::get<CKeyID>(&address); if (keyid && model->getPubKey(*keyid, pubkey)) { nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); } else nBytesInputs += 148; // in all error cases, simply assume 148 here } else nBytesInputs += 148; } // calculation if (nQuantity > 0) { // Bytes nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here if (fWitness) { // there is some fudging in these numbers related to the actual virtual transaction size calculation that will keep this estimate from being exact. // usually, the result will be an overestimate within a couple of satoshis so that the confirmation dialog ends up displaying a slightly smaller fee. // also, the witness stack size value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit. nBytes += 2; // account for the serialized marker and flag bytes nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input. } // in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate if (CoinControlDialog::fSubtractFeeFromAmount) if (nAmount - nPayAmount == 0) nBytes -= 34; // Fee nPayFee = CWallet::GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */); if (nPayAmount > 0) { nChange = nAmount - nPayAmount; if (!CoinControlDialog::fSubtractFeeFromAmount) nChange -= nPayFee; // Never create dust outputs; if we would, just add the dust to the fee. if (nChange > 0 && nChange < MIN_CHANGE) { CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0)); if (IsDust(txout, ::dustRelayFee)) { nPayFee += nChange; nChange = 0; if (CoinControlDialog::fSubtractFeeFromAmount) nBytes -= 34; // we didn't detect lack of change above } } if (nChange == 0 && !CoinControlDialog::fSubtractFeeFromAmount) nBytes -= 34; } // after fee nAfterFee = std::max<CAmount>(nAmount - nPayFee, 0); } // actually update labels int nDisplayUnit = WiFicoinUnits::WFC; if (model && model->getOptionsModel()) nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); QLabel *l1 = dialog->findChild<QLabel *>("labelCoinControlQuantity"); QLabel *l2 = dialog->findChild<QLabel *>("labelCoinControlAmount"); QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee"); QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee"); QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes"); QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput"); QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange"); // enable/disable "dust" and "change" dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0); dialog->findChild<QLabel *>("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0); dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0); dialog->findChild<QLabel *>("labelCoinControlChange") ->setEnabled(nPayAmount > 0); // stats l1->setText(QString::number(nQuantity)); // Quantity l2->setText(WiFicoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount l3->setText(WiFicoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee l4->setText(WiFicoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(WiFicoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change if (nPayFee > 0) { l3->setText(ASYMP_UTF8 + l3->text()); l4->setText(ASYMP_UTF8 + l4->text()); if (nChange > 0 && !CoinControlDialog::fSubtractFeeFromAmount) l8->setText(ASYMP_UTF8 + l8->text()); } // turn label red when dust l7->setStyleSheet((fDust) ? "color:red;" : ""); // tool tips QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold."); // how many satoshis the estimated fee can vary per byte we guess wrong double dFeeVary = (double)nPayFee / nBytes; QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary); l3->setToolTip(toolTip4); l4->setToolTip(toolTip4); l7->setToolTip(toolTipDust); l8->setToolTip(toolTip4); dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip()); dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip()); dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip()); dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip()); dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip()); // Insufficient funds QLabel *label = dialog->findChild<QLabel *>("labelCoinControlInsuffFunds"); if (label) label->setVisible(nChange < 0); }
static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput) { // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS] std::vector<std::string> vStrInputParts; boost::split(vStrInputParts, strInput, boost::is_any_of(":")); // Check that there are enough parameters if (vStrInputParts.size()<3) throw std::runtime_error("Not enough multisig parameters"); // Extract and validate VALUE CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // Extract REQUIRED uint32_t required = stoul(vStrInputParts[1]); // Extract NUMKEYS uint32_t numkeys = stoul(vStrInputParts[2]); // Validate there are the correct number of pubkeys if (vStrInputParts.size() < numkeys + 3) throw std::runtime_error("incorrect number of multisig pubkeys"); if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required) throw std::runtime_error("multisig parameter mismatch. Required " \ + std::to_string(required) + " of " + std::to_string(numkeys) + "signatures."); // extract and validate PUBKEYs std::vector<CPubKey> pubkeys; for(int pos = 1; pos <= int(numkeys); pos++) { CPubKey pubkey(ParseHex(vStrInputParts[pos + 2])); if (!pubkey.IsFullyValid()) throw std::runtime_error("invalid TX output pubkey"); pubkeys.push_back(pubkey); } // Extract FLAGS bool bSegWit = false; bool bScriptHash = false; if (vStrInputParts.size() == numkeys + 4) { std::string flags = vStrInputParts.back(); bSegWit = (flags.find('W') != std::string::npos); bScriptHash = (flags.find('S') != std::string::npos); } else if (vStrInputParts.size() > numkeys + 4) { // Validate that there were no more parameters passed throw std::runtime_error("Too many parameters"); } CScript scriptPubKey = GetScriptForMultisig(required, pubkeys); if (bSegWit) { for (CPubKey& pubkey : pubkeys) { if (!pubkey.IsCompressed()) { throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); } } // Call GetScriptForWitness() to build a P2WSH scriptPubKey scriptPubKey = GetScriptForWitness(scriptPubKey); } if (bScriptHash) { if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) { throw std::runtime_error(strprintf( "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } // Get the ID for the script, and then construct a P2SH destination for it. scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); }