Major updates integration from all upstreams

This commit is contained in:
miketout
2018-09-18 14:33:53 -07:00
396 changed files with 25517 additions and 6854 deletions

View File

@@ -2,8 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "rpcserver.h"
#include "chain.h"
#include "key_io.h"
#include "rpc/server.h"
#include "init.h"
#include "main.h"
#include "script/script.h"
@@ -112,13 +113,8 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
if (params.size() > 2)
fRescan = params[2].get_bool();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret);
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
CKey key = vchSecret.GetKey();
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
CKey key = DecodeSecret(strSecret);
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
@@ -129,7 +125,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
// Don't throw error in case a key is already there
if (pwalletMain->HaveKey(vchAddress)) {
return CBitcoinAddress(vchAddress).ToString();
return EncodeDestination(vchAddress);
}
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
@@ -145,7 +141,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
}
}
return CBitcoinAddress(vchAddress).ToString();
return EncodeDestination(vchAddress);
}
UniValue importaddress(const UniValue& params, bool fHelp)
@@ -175,9 +171,9 @@ UniValue importaddress(const UniValue& params, bool fHelp)
CScript script;
CBitcoinAddress address(params[0].get_str());
if (address.IsValid()) {
script = GetScriptForDestination(address.Get());
CTxDestination dest = DecodeDestination(params[0].get_str());
if (IsValidDestination(dest)) {
script = GetScriptForDestination(dest);
} else if (IsHex(params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(params[0].get_str()));
script = CScript(data.begin(), data.end());
@@ -199,8 +195,8 @@ UniValue importaddress(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
// add to address book or update label
if (address.IsValid())
pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
if (IsValidDestination(dest))
pwalletMain->SetAddressBook(dest, strLabel, "receive");
// Don't throw error in case an address is already there
if (pwalletMain->HaveWatchOnly(script))
@@ -300,16 +296,18 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
// Let's see if the address is a valid Zcash spending key
if (fImportZKeys) {
try {
CZCSpendingKey spendingkey(vstr[0]);
libzcash::SpendingKey key = spendingkey.Get();
libzcash::PaymentAddress addr = key.address();
if (pwalletMain->HaveSpendingKey(addr)) {
LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", CZCPaymentAddress(addr).ToString());
auto spendingkey = DecodeSpendingKey(vstr[0]);
if (IsValidSpendingKey(spendingkey)) {
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutSpendingKey>(&spendingkey) != nullptr);
auto key = boost::get<libzcash::SproutSpendingKey>(spendingkey);
auto addr = key.address();
if (pwalletMain->HaveSproutSpendingKey(addr)) {
LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", EncodePaymentAddress(addr));
continue;
}
int64_t nTime = DecodeDumpTime(vstr[1]);
LogPrint("zrpc", "Importing zaddr %s...\n", CZCPaymentAddress(addr).ToString());
LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
if (!pwalletMain->AddZKey(key)) {
// Something went wrong
fGood = false;
@@ -318,22 +316,20 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
// Successfully imported zaddr. Now import the metadata.
pwalletMain->mapZKeyMetadata[addr].nCreateTime = nTime;
continue;
}
catch (const std::runtime_error &e) {
LogPrint("zrpc","Importing detected an error: %s\n", e.what());
} else {
LogPrint("zrpc", "Importing detected an error: invalid spending key. Trying as a transparent key...\n");
// Not a valid spending key, so carry on and see if it's a Zcash style address.
}
}
CBitcoinSecret vchSecret;
if (!vchSecret.SetString(vstr[0]))
CKey key = DecodeSecret(vstr[0]);
if (!key.IsValid())
continue;
CKey key = vchSecret.GetKey();
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwalletMain->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]);
@@ -351,7 +347,7 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
fLabel = true;
}
}
LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
LogPrintf("Importing %s...\n", EncodeDestination(keyid));
if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
@@ -388,13 +384,13 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"dumpprivkey \"komodoaddress\"\n"
"\nReveals the private key corresponding to 'komodoaddress'.\n"
"dumpprivkey \"t-addr\"\n"
"\nReveals the private key corresponding to 't-addr'.\n"
"Then the importprivkey can be used with this output\n"
"\nArguments:\n"
"1. \"komodoaddress\" (string, required) The komodo address for the private key\n"
"1. \"t-addr\" (string, required) The transparent address for the private key\n"
"\nResult:\n"
"\"key\" (string) The private key\n"
"\"key\" (string) The private key\n"
"\nExamples:\n"
+ HelpExampleCli("dumpprivkey", "\"myaddress\"")
+ HelpExampleCli("importprivkey", "\"mykey\"")
@@ -405,17 +401,20 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
string strAddress = params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
CKeyID keyID;
if (!address.GetKeyID(keyID))
std::string strAddress = params[0].get_str();
CTxDestination dest = DecodeDestination(strAddress);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid transparent address");
}
const CKeyID *keyID = boost::get<CKeyID>(&dest);
if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
}
CKey vchSecret;
if (!pwalletMain->GetKey(keyID, vchSecret))
if (!pwalletMain->GetKey(*keyID, vchSecret)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
return CBitcoinSecret(vchSecret).ToString();
}
return EncodeSecret(vchSecret);
}
@@ -515,31 +514,31 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
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 (pwalletMain->GetKey(keyid, key)) {
if (pwalletMain->mapAddressBook.count(keyid)) {
file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
file << strprintf("%s %s label=%s # addr=%s\n", EncodeSecret(key), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
} else if (setKeyPool.count(keyid)) {
file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr);
file << strprintf("%s %s reserve=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr);
} else {
file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr);
file << strprintf("%s %s change=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr);
}
}
}
file << "\n";
if (fDumpZKeys) {
std::set<libzcash::PaymentAddress> addresses;
pwalletMain->GetPaymentAddresses(addresses);
std::set<libzcash::SproutPaymentAddress> addresses;
pwalletMain->GetSproutPaymentAddresses(addresses);
file << "\n";
file << "# Zkeys\n";
file << "\n";
for (auto addr : addresses ) {
libzcash::SpendingKey key;
if (pwalletMain->GetSpendingKey(addr, key)) {
libzcash::SproutSpendingKey key;
if (pwalletMain->GetSproutSpendingKey(addr, key)) {
std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime);
file << strprintf("%s %s # zaddr=%s\n", CZCSpendingKey(key).ToString(), strTime, CZCPaymentAddress(addr).ToString());
file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr));
}
}
file << "\n";
@@ -551,6 +550,67 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
return exportfilepath.string();
}
class AddSpendingKeyToWallet : public boost::static_visitor<bool>
{
private:
CWallet *m_wallet;
const Consensus::Params &params;
public:
AddSpendingKeyToWallet(CWallet *wallet, const Consensus::Params &params) :
m_wallet(wallet), params(params) {}
bool operator()(const libzcash::SproutSpendingKey &sk) const {
auto addr = sk.address();
// Don't throw error in case a key is already there
if (m_wallet->HaveSproutSpendingKey(addr)) {
return true;
} else {
m_wallet->MarkDirty();
if (!m_wallet-> AddZKey(sk)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
}
m_wallet->mapZKeyMetadata[addr].nCreateTime = 1;
return false;
}
}
bool operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
auto fvk = sk.expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto addr = sk.DefaultAddress();
{
// Don't throw error in case a key is already there
if (m_wallet->HaveSaplingSpendingKey(fvk)) {
return true;
} else {
m_wallet->MarkDirty();
if (!m_wallet-> AddSaplingZKey(sk, addr)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
}
// Sapling addresses can't have been used in transactions prior to activation.
if (params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = 1;
} else {
// Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = 1540512000;
}
return false;
}
}
}
bool operator()(const libzcash::InvalidEncoding& no) const {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}
};
UniValue z_importkey(const UniValue& params, bool fHelp)
{
@@ -617,32 +677,24 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
}
string strSecret = params[0].get_str();
CZCSpendingKey spendingkey(strSecret);
auto key = spendingkey.Get();
auto addr = key.address();
auto spendingkey = DecodeSpendingKey(strSecret);
if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}
{
// Don't throw error in case a key is already there
if (pwalletMain->HaveSpendingKey(addr)) {
if (fIgnoreExistingKey) {
return NullUniValue;
}
} else {
pwalletMain->MarkDirty();
if (!pwalletMain-> AddZKey(key))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
pwalletMain->mapZKeyMetadata[addr].nCreateTime = 1;
}
// whenever a key is imported, we need to scan the whole chain
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
// We want to scan for transactions and notes
if (fRescan) {
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
}
// Sapling support
auto keyAlreadyExists = boost::apply_visitor(
AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey);
if (keyAlreadyExists && fIgnoreExistingKey) {
return NullUniValue;
}
// whenever a key is imported, we need to scan the whole chain
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
// We want to scan for transactions and notes
if (fRescan) {
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
}
return NullUniValue;
@@ -706,24 +758,29 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
}
string strVKey = params[0].get_str();
CZCViewingKey viewingkey(strVKey);
auto vkey = viewingkey.Get();
auto viewingkey = DecodeViewingKey(strVKey);
if (!IsValidViewingKey(viewingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
}
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutViewingKey>(&viewingkey) != nullptr);
auto vkey = boost::get<libzcash::SproutViewingKey>(viewingkey);
auto addr = vkey.address();
{
if (pwalletMain->HaveSpendingKey(addr)) {
if (pwalletMain->HaveSproutSpendingKey(addr)) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this viewing key");
}
// Don't throw error in case a viewing key is already there
if (pwalletMain->HaveViewingKey(addr)) {
if (pwalletMain->HaveSproutViewingKey(addr)) {
if (fIgnoreExistingKey) {
return NullUniValue;
}
} else {
pwalletMain->MarkDirty();
if (!pwalletMain->AddViewingKey(vkey)) {
if (!pwalletMain->AddSproutViewingKey(vkey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet");
}
}
@@ -763,15 +820,17 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
string strAddress = params[0].get_str();
CZCPaymentAddress address(strAddress);
auto addr = address.Get();
auto address = DecodePaymentAddress(strAddress);
if (!IsValidPaymentAddress(address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
}
libzcash::SpendingKey k;
if (!pwalletMain->GetSpendingKey(addr, k))
// Sapling support
auto sk = boost::apply_visitor(GetSpendingKeyForPaymentAddress(pwalletMain), address);
if (!sk) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
CZCSpendingKey spendingkey(k);
return spendingkey.ToString();
}
return EncodeSpendingKey(sk.get());
}
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
@@ -799,18 +858,22 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
string strAddress = params[0].get_str();
CZCPaymentAddress address(strAddress);
auto addr = address.Get();
auto address = DecodePaymentAddress(strAddress);
if (!IsValidPaymentAddress(address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
}
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
libzcash::ViewingKey vk;
if (!pwalletMain->GetViewingKey(addr, vk)) {
libzcash::SpendingKey k;
if (!pwalletMain->GetSpendingKey(addr, k)) {
libzcash::SproutViewingKey vk;
if (!pwalletMain->GetSproutViewingKey(addr, vk)) {
libzcash::SproutSpendingKey k;
if (!pwalletMain->GetSproutSpendingKey(addr, k)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr");
}
vk = k.viewing_key();
}
CZCViewingKey viewingkey(vk);
return viewingkey.ToString();
return EncodeViewingKey(vk);
}