Introduce wrappers around CBitcoinAddress

This patch removes the need for the intermediary Base58 type
CBitcoinAddress, by providing {Encode,Decode,IsValid}Destination
function that directly operate on the conversion between strings
and CTxDestination.
This commit is contained in:
Pieter Wuille 2017-08-22 18:02:33 -07:00
parent 6866b4912b
commit 5c8ff0d448
26 changed files with 299 additions and 277 deletions

View file

@ -318,3 +318,25 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
std::string EncodeDestination(const CTxDestination& dest)
{
CBitcoinAddress addr(dest);
if (!addr.IsValid()) return "";
return addr.ToString();
}
CTxDestination DecodeDestination(const std::string& str)
{
return CBitcoinAddress(str).Get();
}
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
return CBitcoinAddress(str).IsValid(params);
}
bool IsValidDestinationString(const std::string& str)
{
return CBitcoinAddress(str).IsValid();
}

View file

@ -167,4 +167,9 @@ public:
typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey;
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
#endif // BITCOIN_BASE58_H

View file

@ -271,11 +271,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
// extract and validate ADDRESS
std::string strAddr = vStrInputParts[1];
CBitcoinAddress addr(strAddr);
if (!addr.IsValid())
CTxDestination destination = DecodeDestination(strAddr);
if (!IsValidDestination(destination)) {
throw std::runtime_error("invalid TX output address");
// build standard output script via GetScriptForDestination()
CScript scriptPubKey = GetScriptForDestination(addr.Get());
}
CScript scriptPubKey = GetScriptForDestination(destination);
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
@ -314,10 +314,8 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
// Get the address for the redeem script, then call
// GetScriptForDestination() to construct a P2SH scriptPubKey.
CBitcoinAddress redeemScriptAddr(scriptPubKey);
scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());
// 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
@ -381,10 +379,8 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
// Get the address for the redeem script, then call
// GetScriptForDestination() to construct a P2SH scriptPubKey.
CBitcoinAddress addr(scriptPubKey);
scriptPubKey = GetScriptForDestination(addr.Get());
// 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
@ -447,8 +443,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
CBitcoinAddress addr(scriptPubKey);
scriptPubKey = GetScriptForDestination(addr.Get());
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list

View file

@ -148,8 +148,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("type", GetTxnOutputType(type));
UniValue a(UniValue::VARR);
for (const CTxDestination& addr : addresses)
a.push_back(CBitcoinAddress(addr).ToString());
for (const CTxDestination& addr : addresses) {
a.push_back(EncodeDestination(addr));
}
out.pushKV("addresses", a);
}

View file

@ -82,14 +82,14 @@ public:
LOCK(wallet->cs_wallet);
for (const std::pair<CTxDestination, CAddressBookData>& item : wallet->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
bool fMine = IsMine(*wallet, address.Get());
const CTxDestination& address = item.first;
bool fMine = IsMine(*wallet, address);
AddressTableEntry::Type addressType = translateTransactionType(
QString::fromStdString(item.second.purpose), fMine);
const std::string& strName = item.second.name;
cachedAddressTable.append(AddressTableEntry(addressType,
QString::fromStdString(strName),
QString::fromStdString(address.ToString())));
QString::fromStdString(EncodeDestination(address))));
}
}
// qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
@ -246,7 +246,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
if(role == Qt::EditRole)
{
LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */
CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get();
CTxDestination curAddress = DecodeDestination(rec->address.toStdString());
if(index.column() == Label)
{
// Do nothing, if old label == new label
@ -257,7 +257,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
}
wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose);
} else if(index.column() == Address) {
CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get();
CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
if(boost::get<CNoDestination>(&newAddress))
{
@ -358,7 +358,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Check for duplicate addresses
{
LOCK(wallet->cs_wallet);
if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get()))
if(wallet->mapAddressBook.count(DecodeDestination(strAddress)))
{
editStatus = DUPLICATE_ADDRESS;
return QString();
@ -384,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
strAddress = CBitcoinAddress(newKey.GetID()).ToString();
strAddress = EncodeDestination(newKey.GetID());
}
else
{
@ -394,7 +394,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Add entry
{
LOCK(wallet->cs_wallet);
wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel,
wallet->SetAddressBook(DecodeDestination(strAddress), strLabel,
(type == Send ? "send" : "receive"));
}
return QString::fromStdString(strAddress);
@ -412,7 +412,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
}
{
LOCK(wallet->cs_wallet);
wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get());
wallet->DelAddressBook(DecodeDestination(rec->address.toStdString()));
}
return true;
}
@ -423,8 +423,8 @@ QString AddressTableModel::labelForAddress(const QString &address) const
{
{
LOCK(wallet->cs_wallet);
CBitcoinAddress address_parsed(address.toStdString());
std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
CTxDestination destination = DecodeDestination(address.toStdString());
std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(destination);
if (mi != wallet->mapAddressBook.end())
{
return QString::fromStdString(mi->second.name);

View file

@ -89,9 +89,9 @@ QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &po
{
Q_UNUSED(pos);
// Validate the passed Bitcoin address
CBitcoinAddress addr(input.toStdString());
if (addr.IsValid())
if (IsValidDestinationString(input.toStdString())) {
return QValidator::Acceptable;
}
return QValidator::Invalid;
}

View file

@ -660,7 +660,7 @@ void CoinControlDialog::updateView()
QString sAddress = "";
if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress))
{
sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
sAddress = QString::fromStdString(EncodeDestination(outputAddress));
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))

View file

@ -112,8 +112,9 @@ static std::string DummyAddress(const CChainParams &params)
sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
for(int i=0; i<256; ++i) { // Try every trailing byte
std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
if (!CBitcoinAddress(s).IsValid())
if (!IsValidDestinationString(s)) {
return s;
}
sourcedata[sourcedata.size()-1] += 1;
}
return "";
@ -248,7 +249,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
bool isDust(const QString& address, const CAmount& amount)
{
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
CTxDestination dest = DecodeDestination(address.toStdString());
CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script);
return IsDust(txOut, ::dustRelayFee);

View file

@ -218,20 +218,18 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
SendCoinsRecipient r;
if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty())
{
CBitcoinAddress address(r.address.toStdString());
auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
if (address.IsValid(*tempChainParams))
{
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::MAIN);
}
else {
} else {
tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
if (address.IsValid(*tempChainParams))
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::TESTNET);
}
}
}
}
else if (QFile::exists(arg)) // Filename
{
savedPaymentRequests.append(arg);
@ -441,8 +439,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
{
CBitcoinAddress address(recipient.address.toStdString());
if (!address.IsValid()) {
if (!IsValidDestinationString(recipient.address.toStdString())) {
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
@ -560,7 +557,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
// Append destination address
addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString()));
addresses.append(QString::fromStdString(EncodeDestination(dest)));
}
else if (!recipient.authenticatedMerchant.isEmpty()) {
// Unauthenticated payment requests to custom bitcoin addresses are not supported

View file

@ -777,19 +777,18 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
CoinControlDialog::coinControl->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
CBitcoinAddress addr = CBitcoinAddress(text.toStdString());
const CTxDestination dest = DecodeDestination(text.toStdString());
if (text.isEmpty()) // Nothing entered
{
ui->labelCoinControlChangeLabel->setText("");
}
else if (!addr.IsValid()) // Invalid address
else if (!IsValidDestination(dest)) // Invalid address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
}
else // Valid address
{
const CTxDestination dest = addr.Get();
if (!model->IsSpendable(dest)) {
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));

View file

@ -117,16 +117,14 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
/* Clear old signature to ensure users don't get confused on error with an old signature displayed */
ui->signatureOut_SM->clear();
CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
if (!addr.IsValid())
{
CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString());
if (!IsValidDestination(destination)) {
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
CKeyID keyID;
if (!addr.GetKeyID(keyID))
{
const CKeyID* keyID = boost::get<CKeyID>(&destination);
if (!keyID) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@ -142,7 +140,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
if (!model->getPrivKey(keyID, key))
if (!model->getPrivKey(*keyID, key))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
@ -197,16 +195,13 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
{
CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
if (!addr.IsValid())
{
CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString());
if (!IsValidDestination(destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
CKeyID keyID;
if (!addr.GetKeyID(keyID))
{
if (!boost::get<CKeyID>(&destination)) {
ui->addressIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@ -237,8 +232,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
if (!(CBitcoinAddress(pubkey.GetID()) == addr))
{
if (!(CTxDestination(pubkey.GetID()) == destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
return;

View file

@ -57,11 +57,11 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false)
}
//! Send coins to address and return txid.
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf)
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
{
QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString()));
entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
sendCoinsDialog.findChild<QFrame*>("frameFee")
->findChild<QFrame*>("frameFeeSelection")
@ -172,8 +172,8 @@ void TestSendCoins()
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105);
uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */);
uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */);
uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
QCOMPARE(transactionTableModel->rowCount({}), 107);
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());

View file

@ -91,9 +91,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (nNet > 0)
{
// Credit
if (CBitcoinAddress(rec->address).IsValid())
{
CTxDestination address = CBitcoinAddress(rec->address).Get();
if (IsValidDestinationString(rec->address)) {
CTxDestination address = DecodeDestination(rec->address);
if (wallet->mapAddressBook.count(address))
{
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
@ -118,7 +117,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
// Online transaction
std::string strAddress = wtx.mapValue["to"];
strHTML += "<b>" + tr("To") + ":</b> ";
CTxDestination dest = CBitcoinAddress(strAddress).Get();
CTxDestination dest = DecodeDestination(strAddress);
if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
@ -189,7 +188,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("To") + ":</b> ";
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE)
strHTML += " (own address)";
else if(toSelf & ISMINE_WATCH_ONLY)
@ -304,7 +303,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
{
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
strHTML += QString::fromStdString(EncodeDestination(address));
}
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";

View file

@ -55,7 +55,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
sub.address = CBitcoinAddress(address).ToString();
sub.address = EncodeDestination(address);
}
else
{
@ -127,7 +127,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
sub.address = CBitcoinAddress(address).ToString();
sub.address = EncodeDestination(address);
}
else
{

View file

@ -188,8 +188,7 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
bool WalletModel::validateAddress(const QString &address)
{
CBitcoinAddress addressParsed(address.toStdString());
return addressParsed.IsValid();
return IsValidDestinationString(address.toStdString());
}
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
@ -247,7 +246,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
setAddress.insert(rcp.address);
++nAddresses;
CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString()));
CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@ -348,7 +347,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
if (!rcp.paymentRequest.IsInitialized())
{
std::string strAddress = rcp.address.toStdString();
CTxDestination dest = CBitcoinAddress(strAddress).Get();
CTxDestination dest = DecodeDestination(strAddress);
std::string strLabel = rcp.label.toStdString();
{
LOCK(wallet->cs_wallet);
@ -464,7 +463,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
const CTxDestination &address, const std::string &label, bool isMine,
const std::string &purpose, ChangeType status)
{
QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString());
QString strAddress = QString::fromStdString(EncodeDestination(address));
QString strLabel = QString::fromStdString(label);
QString strPurpose = QString::fromStdString(purpose);
@ -596,7 +595,7 @@ bool WalletModel::isSpent(const COutPoint& outpoint) const
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
for (auto& group : wallet->ListCoins()) {
auto& resultGroup = mapCoins[QString::fromStdString(CBitcoinAddress(group.first).ToString())];
auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))];
for (auto& coin : group.second) {
resultGroup.emplace_back(std::move(coin));
}
@ -634,7 +633,7 @@ void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
{
CTxDestination dest = CBitcoinAddress(sAddress).Get();
CTxDestination dest = DecodeDestination(sAddress);
std::stringstream ss;
ss << nId;

View file

@ -176,12 +176,13 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
nMaxTries = request.params[2].get_int();
}
CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
CTxDestination destination = DecodeDestination(request.params[1].get_str());
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
}
std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
coinbaseScript->reserveScript = GetScriptForDestination(destination);
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}

View file

@ -152,8 +152,9 @@ public:
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
UniValue a(UniValue::VARR);
for (const CTxDestination& addr : addresses)
a.push_back(CBitcoinAddress(addr).ToString());
for (const CTxDestination& addr : addresses) {
a.push_back(EncodeDestination(addr));
}
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
@ -207,15 +208,14 @@ UniValue validateaddress(const JSONRPCRequest& request)
LOCK(cs_main);
#endif
CBitcoinAddress address(request.params[0].get_str());
bool isValid = address.IsValid();
CTxDestination dest = DecodeDestination(request.params[0].get_str());
bool isValid = IsValidDestination(dest);
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
CTxDestination dest = address.Get();
std::string currentAddress = address.ToString();
std::string currentAddress = EncodeDestination(dest);
ret.push_back(Pair("address", currentAddress));
CScript scriptPubKey = GetScriptForDestination(dest);
@ -230,10 +230,10 @@ UniValue validateaddress(const JSONRPCRequest& request)
if (pwallet && pwallet->mapAddressBook.count(dest)) {
ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
}
CKeyID keyID;
if (pwallet) {
const auto& meta = pwallet->mapKeyMetadata;
auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end();
const CKeyID *keyID = boost::get<CKeyID>(&dest);
auto it = keyID ? meta.find(*keyID) : meta.end();
if (it == meta.end()) {
it = meta.find(CScriptID(scriptPubKey));
}
@ -277,16 +277,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa
const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
CBitcoinAddress address(ks);
if (pwallet && address.IsValid()) {
CKeyID keyID;
if (!address.GetKeyID(keyID))
throw std::runtime_error(
strprintf("%s does not refer to a key",ks));
CTxDestination dest = DecodeDestination(ks);
if (pwallet && IsValidDestination(dest)) {
const CKeyID *keyID = boost::get<CKeyID>(&dest);
if (!keyID) {
throw std::runtime_error(strprintf("%s does not refer to a key", ks));
}
CPubKey vchPubKey;
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
throw std::runtime_error(
strprintf("no full public key for address %s",ks));
if (!pwallet->GetPubKey(*keyID, vchPubKey)) {
throw std::runtime_error(strprintf("no full public key for address %s", ks));
}
if (!vchPubKey.IsFullyValid())
throw std::runtime_error(" Invalid public key: "+ks);
@ -357,10 +356,9 @@ UniValue createmultisig(const JSONRPCRequest& request)
// Construct using pay-to-script-hash:
CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("address", address.ToString()));
result.push_back(Pair("address", EncodeDestination(innerID)));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
@ -395,13 +393,15 @@ UniValue verifymessage(const JSONRPCRequest& request)
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
CTxDestination destination = DecodeDestination(strAddress);
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
CKeyID keyID;
if (!addr.GetKeyID(keyID))
const CKeyID *keyID = boost::get<CKeyID>(&destination);
if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
bool fInvalid = false;
std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
@ -417,7 +417,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
return (pubkey.GetID() == keyID);
return (pubkey.GetID() == *keyID);
}
UniValue signmessagewithprivkey(const JSONRPCRequest& request)

View file

@ -384,7 +384,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
rawTx.vin.push_back(in);
}
std::set<CBitcoinAddress> setAddress;
std::set<CTxDestination> destinations;
std::vector<std::string> addrList = sendTo.getKeys();
for (const std::string& name_ : addrList) {
@ -394,15 +394,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CTxOut out(0, CScript() << OP_RETURN << data);
rawTx.vout.push_back(out);
} else {
CBitcoinAddress address(name_);
if (!address.IsValid())
CTxDestination destination = DecodeDestination(name_);
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
}
if (setAddress.count(address))
if (!destinations.insert(destination).second) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
setAddress.insert(address);
}
CScript scriptPubKey = GetScriptForDestination(address.Get());
CScript scriptPubKey = GetScriptForDestination(destination);
CAmount nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey);
@ -529,7 +530,7 @@ UniValue decodescript(const JSONRPCRequest& request)
if (type.isStr() && type.get_str() != "scripthash") {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script))));
}
return r;

View file

@ -317,3 +317,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
ret << OP_0 << ToByteVector(hash);
return ret;
}
bool IsValidDestination(const CTxDestination& dest) {
return dest.which() != 0;
}

View file

@ -77,10 +77,13 @@ public:
* * CNoDestination: no destination set
* * CKeyID: TX_PUBKEYHASH destination
* * CScriptID: TX_SCRIPTHASH destination
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);
/** Get the name of a txnouttype as a C string, or nullptr if unknown. */
const char* GetTxnOutputType(txnouttype t);

View file

@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
CBitcoinSecret secret;
CBitcoinAddress addr;
CTxDestination destination;
SelectParams(CBaseChainParams::MAIN);
for (unsigned int idx = 0; idx < tests.size(); idx++) {
@ -145,7 +145,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
// Must be valid private key
// Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
CKey privkey = secret.GetKey();
@ -153,18 +152,17 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
// Private key must be invalid public key
addr.SetString(exp_base58string);
BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
}
else
{
std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
// Must be valid public key
BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
CTxDestination dest = addr.Get();
BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
BOOST_CHECK_MESSAGE((boost::get<CScriptID>(&destination) != nullptr) == (exp_addrType == "script"), "isScript mismatch" + strTest);
BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), destination), "addrType mismatch" + strTest);
// Public key must be invalid private key
secret.SetString(exp_base58string);
@ -226,17 +224,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
BOOST_ERROR("Bad addrtype: " << strTest);
continue;
}
CBitcoinAddress addrOut;
BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
std::string address = EncodeDestination(dest);
BOOST_CHECK_MESSAGE(address == exp_base58string, "mismatch: " + strTest);
}
}
// Visiting a CNoDestination must fail
CBitcoinAddress dummyAddr;
CTxDestination nodest = CNoDestination();
BOOST_CHECK(!dummyAddr.Set(nodest));
SelectParams(CBaseChainParams::MAIN);
}
@ -245,7 +237,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
CBitcoinSecret secret;
CBitcoinAddress addr;
CTxDestination destination;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@ -258,8 +250,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
std::string exp_base58string = test[0].get_str();
// must be invalid as public and as private key
addr.SetString(exp_base58string);
BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
secret.SetString(exp_base58string);
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
}

View file

@ -16,17 +16,16 @@
#include <boost/test/unit_test.hpp>
static const std::string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
static const std::string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
static const std::string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
static const std::string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
static const std::string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
@ -74,10 +73,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
for (int n=0; n<16; n++)
{

View file

@ -181,7 +181,7 @@ UniValue abortrescan(const JSONRPCRequest& request)
return true;
}
void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
{
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
@ -198,7 +198,7 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri
if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel);
ImportAddress(pwallet, CScriptID(script), strLabel);
} else {
CTxDestination destination;
if (ExtractDestination(script, destination)) {
@ -207,13 +207,13 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri
}
}
void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel)
void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel)
{
CScript script = GetScriptForDestination(address.Get());
CScript script = GetScriptForDestination(dest);
ImportScript(pwallet, script, strLabel, false);
// add to address book or update label
if (address.IsValid())
pwallet->SetAddressBook(address.Get(), strLabel, "receive");
if (IsValidDestination(dest))
pwallet->SetAddressBook(dest, strLabel, "receive");
}
UniValue importaddress(const JSONRPCRequest& request)
@ -265,11 +265,12 @@ UniValue importaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
CBitcoinAddress address(request.params[0].get_str());
if (address.IsValid()) {
if (fP2SH)
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (IsValidDestination(dest)) {
if (fP2SH) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
ImportAddress(pwallet, address, strLabel);
}
ImportAddress(pwallet, dest, strLabel);
} else if (IsHex(request.params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);
@ -432,7 +433,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel);
ImportAddress(pwallet, pubKey.GetID(), strLabel);
ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
if (fRescan)
@ -506,7 +507,7 @@ UniValue importwallet(const JSONRPCRequest& request)
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
continue;
}
int64_t nTime = DecodeDumpTime(vstr[1]);
@ -524,7 +525,7 @@ UniValue importwallet(const JSONRPCRequest& request)
fLabel = true;
}
}
LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
LogPrintf("Importing %s...\n", EncodeDestination(keyid));
if (!pwallet->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
@ -573,14 +574,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
std::string strAddress = request.params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
CTxDestination dest = DecodeDestination(strAddress);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CKeyID keyID;
if (!address.GetKeyID(keyID))
}
const CKeyID *keyID = boost::get<CKeyID>(&dest);
if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
}
CKey vchSecret;
if (!pwallet->GetKey(keyID, vchSecret)) {
if (!pwallet->GetKey(*keyID, vchSecret)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
}
return CBitcoinSecret(vchSecret).ToString();
@ -659,7 +662,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
std::string strTime = EncodeDumpTime(it->first);
std::string strAddr = CBitcoinAddress(keyid).ToString();
std::string strAddr = EncodeDestination(keyid);
CKey key;
if (pwallet->GetKey(keyid, key)) {
file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
@ -715,14 +718,14 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
// Parse the output.
CScript script;
CBitcoinAddress address;
CTxDestination dest;
if (!isScript) {
address = CBitcoinAddress(output);
if (!address.IsValid()) {
dest = DecodeDestination(output);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
script = GetScriptForDestination(address.Get());
script = GetScriptForDestination(dest);
} else {
if (!IsHex(output)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
@ -780,8 +783,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript));
CScript redeemDestination = GetScriptForDestination(redeemAddress.Get());
CTxDestination redeem_dest = CScriptID(redeemScript);
CScript redeemDestination = GetScriptForDestination(redeem_dest);
if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@ -794,8 +797,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// add to address book or update label
if (address.IsValid()) {
pwallet->SetAddressBook(address.Get(), label, "receive");
if (IsValidDestination(dest)) {
pwallet->SetAddressBook(dest, label, "receive");
}
// Import private keys.
@ -854,27 +857,25 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
}
CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
scriptAddress = CBitcoinAddress(destination);
if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
}
CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get());
CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@ -887,8 +888,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// add to address book or update label
if (pubKeyAddress.IsValid()) {
pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive");
if (IsValidDestination(pubkey_dest)) {
pwallet->SetAddressBook(pubkey_dest, label, "receive");
}
// TODO Is this necessary?
@ -927,21 +928,19 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
CPubKey pubKey = key.GetPubKey();
assert(key.VerifyPubKey(pubKey));
CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
scriptAddress = CBitcoinAddress(destination);
if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
@ -980,8 +979,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
if (scriptPubKey.getType() == UniValue::VOBJ) {
// add to address book or update label
if (address.IsValid()) {
pwallet->SetAddressBook(address.Get(), label, "receive");
if (IsValidDestination(dest)) {
pwallet->SetAddressBook(dest, label, "receive");
}
}

View file

@ -170,18 +170,18 @@ UniValue getnewaddress(const JSONRPCRequest& request)
pwallet->SetAddressBook(keyID, strAccount, "receive");
return CBitcoinAddress(keyID).ToString();
return EncodeDestination(keyID);
}
CBitcoinAddress GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
CTxDestination GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
{
CPubKey pubKey;
if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
return CBitcoinAddress(pubKey.GetID());
return pubKey.GetID();
}
UniValue getaccountaddress(const JSONRPCRequest& request)
@ -213,7 +213,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
UniValue ret(UniValue::VSTR);
ret = GetAccountAddress(pwallet, strAccount).ToString();
ret = EncodeDestination(GetAccountAddress(pwallet, strAccount));
return ret;
}
@ -252,7 +252,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
CKeyID keyID = vchPubKey.GetID();
return CBitcoinAddress(keyID).ToString();
return EncodeDestination(keyID);
}
@ -277,24 +277,25 @@ UniValue setaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
std::string strAccount;
if (!request.params[1].isNull())
strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
if (IsMine(*pwallet, address.Get())) {
if (IsMine(*pwallet, dest)) {
// Detect when changing the account of an address that is the 'unused current key' of another account:
if (pwallet->mapAddressBook.count(address.Get())) {
std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name;
if (address == GetAccountAddress(pwallet, strOldAccount)) {
if (pwallet->mapAddressBook.count(dest)) {
std::string strOldAccount = pwallet->mapAddressBook[dest].name;
if (dest == GetAccountAddress(pwallet, strOldAccount)) {
GetAccountAddress(pwallet, strOldAccount, true);
}
}
pwallet->SetAddressBook(address.Get(), strAccount, "receive");
pwallet->SetAddressBook(dest, strAccount, "receive");
}
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
@ -325,12 +326,13 @@ UniValue getaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
std::string strAccount;
std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get());
std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
strAccount = (*mi).second.name;
}
@ -367,11 +369,12 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
const CBitcoinAddress& address = item.first;
for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
const CTxDestination& dest = item.first;
const std::string& strName = item.second.name;
if (strName == strAccount)
ret.push_back(address.ToString());
if (strName == strAccount) {
ret.push_back(EncodeDestination(dest));
}
}
return ret;
}
@ -454,9 +457,10 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
// Amount
CAmount nAmount = AmountFromValue(request.params[1]);
@ -493,7 +497,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control);
SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control);
return wtx.GetHash().GetHex();
}
@ -533,16 +537,16 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
UniValue jsonGroupings(UniValue::VARR);
std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
for (CTxDestination address : grouping)
for (const CTxDestination& address : grouping)
{
UniValue addressInfo(UniValue::VARR);
addressInfo.push_back(CBitcoinAddress(address).ToString());
addressInfo.push_back(EncodeDestination(address));
addressInfo.push_back(ValueFromAmount(balances[address]));
{
if (pwallet->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) {
addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
}
}
jsonGrouping.push_back(addressInfo);
@ -587,16 +591,18 @@ UniValue signmessage(const JSONRPCRequest& request)
std::string strAddress = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
CTxDestination dest = DecodeDestination(strAddress);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
CKeyID keyID;
if (!addr.GetKeyID(keyID))
const CKeyID *keyID = boost::get<CKeyID>(&dest);
if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
CKey key;
if (!pwallet->GetKey(keyID, key)) {
if (!pwallet->GetKey(*keyID, key)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
}
@ -642,10 +648,11 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str());
if (!address.IsValid())
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CScript scriptPubKey = GetScriptForDestination(address.Get());
}
CScript scriptPubKey = GetScriptForDestination(dest);
if (!IsMine(*pwallet, scriptPubKey)) {
return ValueFromAmount(0);
}
@ -915,9 +922,10 @@ UniValue sendfrom(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = AccountFromValue(request.params[0]);
CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
CTxDestination dest = DecodeDestination(request.params[1].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
@ -940,7 +948,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
CCoinControl no_coin_control; // This is a deprecated API
SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control);
SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control);
return wtx.GetHash().GetHex();
}
@ -1032,22 +1040,23 @@ UniValue sendmany(const JSONRPCRequest& request)
}
}
std::set<CBitcoinAddress> setAddress;
std::set<CTxDestination> destinations;
std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
std::vector<std::string> keys = sendTo.getKeys();
for (const std::string& name_ : keys)
{
CBitcoinAddress address(name_);
if (!address.IsValid())
for (const std::string& name_ : keys) {
CTxDestination dest = DecodeDestination(name_);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
}
if (setAddress.count(address))
if (destinations.count(dest)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
setAddress.insert(address);
}
destinations.insert(dest);
CScript scriptPubKey = GetScriptForDestination(address.Get());
CScript scriptPubKey = GetScriptForDestination(dest);
CAmount nAmount = AmountFromValue(sendTo[name_]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
@ -1138,7 +1147,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
pwallet->AddCScript(inner);
pwallet->SetAddressBook(innerID, strAccount, "send");
return CBitcoinAddress(innerID).ToString();
return EncodeDestination(innerID);
}
class Witnessifier : public boost::static_visitor<bool>
@ -1226,12 +1235,12 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
}
}
CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
Witnessifier w(pwallet);
CTxDestination dest = address.Get();
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
@ -1239,7 +1248,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
pwallet->SetAddressBook(w.result, "", "receive");
return CBitcoinAddress(w.result).ToString();
return EncodeDestination(w.result);
}
struct tallyitem
@ -1274,7 +1283,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
filter = filter | ISMINE_WATCH_ONLY;
// Tally
std::map<CBitcoinAddress, tallyitem> mapTally;
std::map<CTxDestination, tallyitem> mapTally;
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
@ -1307,10 +1316,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
// Reply
UniValue ret(UniValue::VARR);
std::map<std::string, tallyitem> mapAccountTally;
for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
const CBitcoinAddress& address = item.first;
for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
const CTxDestination& dest = item.first;
const std::string& strAccount = item.second.name;
std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@ -1336,7 +1345,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("address", EncodeDestination(dest)));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
@ -1461,9 +1470,9 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
CBitcoinAddress addr;
if (addr.Set(dest))
entry.push_back(Pair("address", addr.ToString()));
if (IsValidDestination(dest)) {
entry.push_back(Pair("address", EncodeDestination(dest)));
}
}
/**
@ -2717,18 +2726,19 @@ UniValue listunspent(const JSONRPCRequest& request)
nMaxDepth = request.params[1].get_int();
}
std::set<CBitcoinAddress> setAddress;
std::set<CTxDestination> destinations;
if (!request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
CTxDestination dest = DecodeDestination(input.get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
if (setAddress.count(address))
}
if (!destinations.insert(dest).second) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
setAddress.insert(address);
}
}
}
@ -2770,7 +2780,7 @@ UniValue listunspent(const JSONRPCRequest& request)
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))
if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
UniValue entry(UniValue::VOBJ);
@ -2778,7 +2788,7 @@ UniValue listunspent(const JSONRPCRequest& request)
entry.push_back(Pair("vout", out.i));
if (fValidAddress) {
entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
entry.push_back(Pair("address", EncodeDestination(address)));
if (pwallet->mapAddressBook.count(address)) {
entry.push_back(Pair("account", pwallet->mapAddressBook[address].name));
@ -2901,12 +2911,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
true, true);
if (options.exists("changeAddress")) {
CBitcoinAddress address(options["changeAddress"].get_str());
CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
if (!address.IsValid())
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
}
coinControl.destChange = address.Get();
coinControl.destChange = dest;
}
if (options.exists("changePosition"))

View file

@ -307,7 +307,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString();
std::string strAddr = EncodeDestination(CScriptID(redeemScript));
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
@ -3072,9 +3072,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
}
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(EncodeDestination(address), strPurpose))
return false;
return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName);
return CWalletDB(*dbw).WriteName(EncodeDestination(address), strName);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
@ -3083,7 +3083,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
LOCK(cs_wallet); // mapAddressBook
// Delete destdata tuples associated with address
std::string strAddress = CBitcoinAddress(address).ToString();
std::string strAddress = EncodeDestination(address);
for (const std::pair<std::string, std::string> &item : mapAddressBook[address].destdata)
{
CWalletDB(*dbw).EraseDestData(strAddress, item.first);
@ -3093,8 +3093,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString());
return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
CWalletDB(*dbw).ErasePurpose(EncodeDestination(address));
return CWalletDB(*dbw).EraseName(EncodeDestination(address));
}
const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
@ -3711,14 +3711,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
return false;
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value);
}
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
{
if (!mapAddressBook[dest].destdata.erase(key))
return false;
return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key);
return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key);
}
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)

View file

@ -253,13 +253,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{
std::string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
}
else if (strType == "purpose")
{
std::string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
}
else if (strType == "tx")
{
@ -493,7 +493,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> strAddress;
ssKey >> strKey;
ssValue >> strValue;
if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue))
{
strErr = "Error reading wallet database: LoadDestData failed";
return false;