Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for non-Base58 addresses [Step 2] #1677

Merged
merged 3 commits into from
Jun 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 28 additions & 27 deletions src/base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,46 +311,47 @@ bool CBitcoinAddress::IsStakingAddress() const
return fCorrectSize && vchVersion == Params().Base58Prefix(CChainParams::STAKING_ADDRESS);
}

void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
assert(vchSecret.IsValid());
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
if (vchSecret.IsCompressed())
vchData.push_back(1);
CKey DecodeSecret(const std::string& str)
{
CKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
bool compressed = data.size() == 33 + privkey_prefix.size();
key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
}
}
memory_cleanse(data.data(), data.size());
return key;
}

CKey CBitcoinSecret::GetKey()
std::string EncodeSecret(const CKey& key)
{
CKey ret;
assert(vchData.size() >= 32);
ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
assert(key.IsValid());
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
data.insert(data.end(), key.begin(), key.end());
if (key.IsCompressed()) {
data.push_back(1);
}
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}

bool CBitcoinSecret::IsValid() const
{
bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
return fExpectedFormat && fCorrectVersion;
}

bool CBitcoinSecret::SetString(const char* pszSecret)
{
return CBase58Data::SetString(pszSecret) && IsValid();
}

bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}

CTxDestination DestinationFor(const CKeyID& keyID, const CChainParams::Base58Type addrType)
{
CBitcoinAddress addr(keyID, addrType);
if (!addr.IsValid()) throw std::runtime_error("Error, trying to decode an invalid keyID");
return addr.Get();
}

std::string EncodeDestination(const CTxDestination& dest, bool isStaking)
{
return EncodeDestination(dest, isStaking ? CChainParams::STAKING_ADDRESS : CChainParams::PUBKEY_ADDRESS);
}

std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Base58Type addrType)
{
CBitcoinAddress addr(dest, addrType);
Expand Down
18 changes: 3 additions & 15 deletions src/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,8 @@ class CBitcoinAddress : public CBase58Data
}
};

/**
* A base58-encoded secret key
*/
class CBitcoinSecret : public CBase58Data
{
public:
void SetKey(const CKey& vchSecret);
CKey GetKey();
bool IsValid() const;
bool SetString(const char* pszSecret);
bool SetString(const std::string& strSecret);

CBitcoinSecret(const CKey& vchSecret) { SetKey(vchSecret); }
CBitcoinSecret() {}
};
CKey DecodeSecret(const std::string& str);
std::string EncodeSecret(const CKey& key);

template <typename K, int Size, CChainParams::Base58Type Type>
class CBitcoinExtKeyBase : public CBase58Data
Expand Down Expand Up @@ -184,6 +171,7 @@ typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBL


CTxDestination DestinationFor(const CKeyID& keyID, const CChainParams::Base58Type addrType);
std::string EncodeDestination(const CTxDestination& dest, bool isStaking);
std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS);
// DecodeDestinationisStaking flag is set to true when the string arg is from an staking address
CTxDestination DecodeDestination(const std::string& str, bool& isStaking);
Expand Down
8 changes: 3 additions & 5 deletions src/messagesigner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@

bool CMessageSigner::GetKeysFromSecret(const std::string& strSecret, CKey& keyRet, CPubKey& pubkeyRet)
{
CBitcoinSecret vchSecret;

if(!vchSecret.SetString(strSecret)) return false;
keyRet = DecodeSecret(strSecret);
if (!keyRet.IsValid())
return false;

keyRet = vchSecret.GetKey();
pubkeyRet = keyRet.GetPubKey();

return true;
}

Expand Down
8 changes: 3 additions & 5 deletions src/pivx-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
throw std::runtime_error("privatekey not a string");
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
if (!fGood)
CKey key = DecodeSecret(keysObj[kidx].getValStr());
if (!key.IsValid()) {
throw std::runtime_error("privatekey not valid");

CKey key = vchSecret.GetKey();
}
tempKeystore.AddKey(key);
}

Expand Down
3 changes: 1 addition & 2 deletions src/qt/pivx/masternodewizarddialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,7 @@ bool MasterNodeWizardDialog::createMN()
// create the mn key
CKey secret;
secret.MakeNewKey(false);
CBitcoinSecret mnKey = CBitcoinSecret(secret);
std::string mnKeyString = mnKey.ToString();
std::string mnKeyString = EncodeSecret(secret);

// Look for a valid collateral utxo
COutPoint collateralOut;
Expand Down
2 changes: 1 addition & 1 deletion src/qt/pivx/sendconfirmdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ void TxDetailDialog::onOutputsClicked()
CTxDestination dest;
bool isCsAddress = out.scriptPubKey.IsPayToColdStaking();
if (ExtractDestination(out.scriptPubKey, dest, isCsAddress)) {
std::string address = ((isCsAddress) ? CBitcoinAddress::newCSInstance(dest) : CBitcoinAddress::newInstance(dest)).ToString();
std::string address = EncodeDestination(dest, isCsAddress);
labelRes = QString::fromStdString(address);
labelRes = labelRes.left(16) + "..." + labelRes.right(16);
} else {
Expand Down
17 changes: 8 additions & 9 deletions src/qt/pivx/settings/settingsbittoolwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,15 @@ void SettingsBitToolWidget::onEncryptKeyButtonENCClicked()
return;
}

CBitcoinAddress addr(ui->addressIn_ENC->text().toStdString());
if (!addr.IsValid()) {
CTxDestination dest = DecodeDestination(ui->addressIn_ENC->text().toStdString());
if (!IsValidDestination(dest)) {
ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_ENC->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}

CKeyID keyID;
if (!addr.GetKeyID(keyID)) {
CKeyID keyID = *boost::get<CKeyID>(&dest);
if (!keyID) {
//ui->addressIn_ENC->setValid(false);
ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_ENC->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
Expand All @@ -172,7 +172,7 @@ void SettingsBitToolWidget::onEncryptKeyButtonENCClicked()
return;
}

std::string encryptedKey = BIP38_Encrypt(addr.ToString(), qstrPassphrase.toStdString(), key.GetPrivKey_256(), key.IsCompressed());
std::string encryptedKey = BIP38_Encrypt(EncodeDestination(dest), qstrPassphrase.toStdString(), key.GetPrivKey_256(), key.IsCompressed());
ui->encryptedKeyOut_ENC->setText(QString::fromStdString(encryptedKey));

ui->statusLabel_ENC->setStyleSheet("QLabel { color: green; }");
Expand Down Expand Up @@ -265,8 +265,7 @@ void SettingsBitToolWidget::onDecryptClicked()

key.Set(privKey.begin(), privKey.end(), fCompressed);
CPubKey pubKey = key.GetPubKey();
CBitcoinAddress address(pubKey.GetID());
ui->lineEditDecryptResult->setText(QString::fromStdString(address.ToString()));
ui->lineEditDecryptResult->setText(QString::fromStdString(EncodeDestination(pubKey.GetID())));
ui->pushButtonImport->setVisible(true);
}

Expand All @@ -279,10 +278,10 @@ void SettingsBitToolWidget::importAddressFromDecKey()
return;
}

CBitcoinAddress address(ui->lineEditDecryptResult->text().toStdString());
CTxDestination dest = DecodeDestination(ui->lineEditDecryptResult->text().toStdString());
CPubKey pubkey = key.GetPubKey();

if (!address.IsValid() || !key.IsValid() || CBitcoinAddress(pubkey.GetID()).ToString() != address.ToString()) {
if (!IsValidDestination(dest) || !key.IsValid() || EncodeDestination(pubkey.GetID()) != EncodeDestination(dest)) {
ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_DEC->setText(tr("Data Not Valid.") + QString(" ") + tr("Please try again."));
return;
Expand Down
8 changes: 4 additions & 4 deletions src/qt/pivx/settings/settingsmultisendwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ void SettingsMultisendWidget::onAddRecipientClicked()
void SettingsMultisendWidget::addMultiSend(QString address, int percentage, QString addressLabel)
{
std::string strAddress = address.toStdString();
if (!CBitcoinAddress(strAddress).IsValid()) {
CTxDestination destAddress = DecodeDestination(strAddress);
if (!IsValidDestination(destAddress)) {
inform(tr("The entered address: %1 is invalid.\nPlease check the address and try again.").arg(address));
return;
}
Expand All @@ -311,9 +312,8 @@ void SettingsMultisendWidget::addMultiSend(QString address, int percentage, QStr

if (walletModel && walletModel->getAddressTableModel()) {
// update the address book with the label given or no label if none was given.
CBitcoinAddress address(strAddress);
std::string userInputLabel = addressLabel.toStdString();
walletModel->updateAddressBookLabels(address.Get(), (userInputLabel.empty()) ? "(no label)" : userInputLabel,
walletModel->updateAddressBookLabels(destAddress, (userInputLabel.empty()) ? "(no label)" : userInputLabel,
AddressBook::AddressBookPurpose::SEND);
}

Expand All @@ -337,7 +337,7 @@ void SettingsMultisendWidget::activate()
strRet = tr("Unable to activate MultiSend, no available recipients");
else if (!(ui->checkBoxStake->isChecked() || ui->checkBoxRewards->isChecked())) {
strRet = tr("Unable to activate MultiSend\nCheck one or both of the check boxes to send on stake and/or masternode rewards");
} else if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) {
} else if (IsValidDestinationString(pwalletMain->vMultiSend[0].first)) {
pwalletMain->fMultiSendStake = ui->checkBoxStake->isChecked();
pwalletMain->fMultiSendMasternodeReward = ui->checkBoxRewards->isChecked();

Expand Down
18 changes: 9 additions & 9 deletions src/qt/transactiondesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco
// Offline transaction
if (nNet > 0) {
// Credit
if (CBitcoinAddress(rec->address).IsValid()) {
CTxDestination address = CBitcoinAddress(rec->address).Get();
if (wallet->mapAddressBook.count(address)) {
CTxDestination dest = DecodeDestination(rec->address);
if (IsValidDestination(dest)) {
if (wallet->mapAddressBook.count(dest)) {
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
strHTML += "<b>" + tr("To") + ":</b> ";
strHTML += GUIUtil::HtmlEscape(rec->address);
QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
if (!wallet->mapAddressBook[address].name.empty())
strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
QString addressOwned = (::IsMine(*wallet, dest) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
if (!wallet->mapAddressBook[dest].name.empty())
strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + ")";
else
strHTML += " (" + addressOwned + ")";
strHTML += "<br>";
Expand All @@ -137,7 +137,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>";
Expand Down Expand Up @@ -197,7 +197,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)
Expand Down Expand Up @@ -301,7 +301,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco
if (ExtractDestination(vout.scriptPubKey, address)) {
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"));
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ UniValue createmasternodekey (const UniValue& params, bool fHelp)
CKey secret;
secret.MakeNewKey(false);

return CBitcoinSecret(secret).ToString();
return EncodeSecret(secret);
}

UniValue getmasternodeoutputs (const UniValue& params, bool fHelp)
Expand Down
8 changes: 2 additions & 6 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,13 +674,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
UniValue keys = params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
UniValue k = keys[idx];
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
CKey key = vchSecret.GetKey();
CKey key = DecodeSecret(k.get_str());
if (!key.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
tempKeystore.AddKey(key);
}
}
Expand Down
28 changes: 11 additions & 17 deletions src/test/base58_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,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)));
std::vector<unsigned char> result;
CBitcoinSecret secret;
CKey privkey;
CTxDestination destination;
SelectParams(CBaseChainParams::MAIN);

Expand All @@ -143,22 +143,18 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
SelectParams(CBaseChainParams::TESTNET);
else
SelectParams(CBaseChainParams::MAIN);
if(isPrivkey)
{
if(isPrivkey) {
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
// Must be valid private key
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
CKey privkey = secret.GetKey();
privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
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
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
}
else
{
} else {
std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
// Must be valid public key
destination = DecodeDestination(exp_base58string);
Expand All @@ -167,8 +163,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), destination), "addrType mismatch" + strTest);

// Public key must be invalid private key
secret.SetString(exp_base58string);
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest);
}
}
}
Expand Down Expand Up @@ -202,9 +198,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CKey key;
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
assert(key.IsValid());
CBitcoinSecret secret;
secret.SetKey(key);
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest);
}
else
{
Expand Down Expand Up @@ -240,7 +234,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
std::vector<unsigned char> result;
CBitcoinSecret secret;
CKey privkey;
CTxDestination destination;

for (unsigned int idx = 0; idx < tests.size(); idx++) {
Expand All @@ -256,8 +250,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
// must be invalid as public and as private key
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
secret.SetString(exp_base58string);
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest);
}
}

Expand Down
Loading