Merge #11117: Prepare for non-Base58 addresses
864cd2787
Move CBitcoinAddress to base58.cpp (Pieter Wuille)5c8ff0d44
Introduce wrappers around CBitcoinAddress (Pieter Wuille) Pull request description: This patch removes the need for the intermediary Base58 type `CBitcoinAddress`, by providing {`Encode`,`Decode`,`IsValid`}`Destination` functions that directly operate on the conversion between `std::string`s and `CTxDestination`. As a side, it also fixes a number of indentation issues, and removes probably several unnecessary implicit `CTxDestination`<->`CBitcoinAddress` conversions. This change is far from complete. In follow-ups I'd like to: * Split off the specific address and key encoding logic from base58.h, and move it to a address.h or so. * Replace `CTxDestination` with a non-`boost::variant` version (which can be more efficient as `boost::variant` allocates everything on the heap, and remove the need for `boost::get<...>` and `IsValidDestination` calls everywhere). * Do the same for `CBitcoinSecret`, `CBitcoinExtKey`, and `CBitcoinExtPubKey`. However, I've tried to keep this patch to be minimally invasive, but still enough to support non-Base58 addresses. Perhaps a smaller patch is possible to hack Bech32 support into `CBitcoinAddress`, but I would consider that a move in the wrong direction. Tree-SHA512: c2c77ffb57caeadf2429b1c2562ce60e8c7be8aa9f8e51b591f354b6b441162625b2efe14c023a1ae485cf2ed417263afa35c892891dfaa7844e7fbabccab85e
This commit is contained in:
commit
961901f77e
26 changed files with 323 additions and 301 deletions
|
@ -212,6 +212,30 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const
|
|||
|
||||
namespace
|
||||
{
|
||||
/** base58-encoded Bitcoin addresses.
|
||||
* Public-key-hash-addresses have version 0 (or 111 testnet).
|
||||
* The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
||||
* Script-hash-addresses have version 5 (or 196 testnet).
|
||||
* The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
|
||||
*/
|
||||
class CBitcoinAddress : public CBase58Data {
|
||||
public:
|
||||
bool Set(const CKeyID &id);
|
||||
bool Set(const CScriptID &id);
|
||||
bool Set(const CTxDestination &dest);
|
||||
bool IsValid() const;
|
||||
bool IsValid(const CChainParams ¶ms) const;
|
||||
|
||||
CBitcoinAddress() {}
|
||||
CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
|
||||
CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
|
||||
CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
|
||||
|
||||
CTxDestination Get() const;
|
||||
bool GetKeyID(CKeyID &keyID) const;
|
||||
bool IsScript() const;
|
||||
};
|
||||
|
||||
class CBitcoinAddressVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
private:
|
||||
|
@ -318,3 +342,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();
|
||||
}
|
||||
|
|
29
src/base58.h
29
src/base58.h
|
@ -95,30 +95,6 @@ public:
|
|||
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
|
||||
};
|
||||
|
||||
/** base58-encoded Bitcoin addresses.
|
||||
* Public-key-hash-addresses have version 0 (or 111 testnet).
|
||||
* The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
||||
* Script-hash-addresses have version 5 (or 196 testnet).
|
||||
* The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
|
||||
*/
|
||||
class CBitcoinAddress : public CBase58Data {
|
||||
public:
|
||||
bool Set(const CKeyID &id);
|
||||
bool Set(const CScriptID &id);
|
||||
bool Set(const CTxDestination &dest);
|
||||
bool IsValid() const;
|
||||
bool IsValid(const CChainParams ¶ms) const;
|
||||
|
||||
CBitcoinAddress() {}
|
||||
CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
|
||||
CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
|
||||
CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
|
||||
|
||||
CTxDestination Get() const;
|
||||
bool GetKeyID(CKeyID &keyID) const;
|
||||
bool IsScript() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A base58-encoded secret key
|
||||
*/
|
||||
|
@ -167,4 +143,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
|
||||
|
|
|
@ -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
|
||||
|
@ -444,11 +440,10 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
|
|||
}
|
||||
|
||||
if (bSegWit) {
|
||||
scriptPubKey = GetScriptForWitness(scriptPubKey);
|
||||
scriptPubKey = GetScriptForWitness(scriptPubKey);
|
||||
}
|
||||
if (bScriptHash) {
|
||||
CBitcoinAddress addr(scriptPubKey);
|
||||
scriptPubKey = GetScriptForDestination(addr.Get());
|
||||
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
|
||||
}
|
||||
|
||||
// construct TxOut, append to transaction output list
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -112,8 +112,9 @@ static std::string DummyAddress(const CChainParams ¶ms)
|
|||
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);
|
||||
|
|
|
@ -218,17 +218,15 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>";
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
|
||||
CTxDestination destination = DecodeDestination(name_);
|
||||
if (!IsValidDestination(destination)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
|
||||
}
|
||||
|
||||
if (setAddress.count(address))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
|
||||
setAddress.insert(address);
|
||||
if (!destinations.insert(destination).second) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
|
||||
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))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
|
||||
setAddress.insert(address);
|
||||
if (destinations.count(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
|
||||
}
|
||||
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())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str());
|
||||
if (setAddress.count(address))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str());
|
||||
setAddress.insert(address);
|
||||
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 (!destinations.insert(dest).second) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue