diff --git a/src/Makefile.am b/src/Makefile.am index 1e99260b2..bf6007949 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -381,6 +381,11 @@ libdynamic_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) libdynamic_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdynamic_wallet_a_SOURCES = \ bdap/stealth.cpp \ + bdap/wallet/keys.cpp \ + bdap/wallet/wallet.cpp \ + bdap/wallet/linkmanager.cpp \ + bdap/wallet/utils.cpp \ + bdap/wallet/vgp.cpp \ keepass.cpp \ policy/rbf.cpp \ privatesend-client.cpp \ @@ -475,6 +480,7 @@ libdynamic_common_a_SOURCES = \ base58.cpp \ bdap/stealth.cpp \ bip39.cpp \ + bdap/wallet/keys.cpp \ chainparams.cpp \ coins.cpp \ compressor.cpp \ @@ -628,6 +634,7 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a CLEANFILES += *.gcda *.gcno CLEANFILES += bdap/*.gcda bdap/*.gcno CLEANFILES += bdap/vgp/*.gcda bdap/vgp/*.gcno +CLEANFILES += bdap/wallet/*.gcda bdap/wallet/*.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno diff --git a/src/bdap/linkmanager.cpp b/src/bdap/linkmanager.cpp index 4faea4ab3..173860a7c 100644 --- a/src/bdap/linkmanager.cpp +++ b/src/bdap/linkmanager.cpp @@ -15,8 +15,6 @@ CLinkManager* pLinkManager = NULL; -//#ifdef ENABLE_WALLET - std::string CLink::LinkState() const { if (nLinkState == 0) { @@ -104,76 +102,6 @@ std::string CLink::RecipientPubKeyString() const return stringFromVch(RecipientPubKey); } -#ifdef ENABLE_WALLET -bool CLinkManager::IsLinkFromMe(const std::vector& vchLinkPubKey) -{ - if (!pwalletMain) - return false; - - CKeyID keyID(Hash160(vchLinkPubKey.begin(), vchLinkPubKey.end())); - CKeyEd25519 keyOut; - if (pwalletMain->GetDHTKey(keyID, keyOut)) - return true; - - return false; -} - -bool CLinkManager::IsLinkForMe(const std::vector& vchLinkPubKey, const std::vector& vchSharedPubKey) -{ - if (!pwalletMain) - return false; - - std::vector> vvchMyDHTPubKeys; - if (!pwalletMain->GetDHTPubKeys(vvchMyDHTPubKeys)) - return false; - - if (vvchMyDHTPubKeys.size() == 0) - return false; - - for (const std::vector& vchMyDHTPubKey : vvchMyDHTPubKeys) { - CKeyID keyID(Hash160(vchMyDHTPubKey.begin(), vchMyDHTPubKey.end())); - CKeyEd25519 dhtKey; - if (pwalletMain->GetDHTKey(keyID, dhtKey)) { - std::vector vchGetSharedPubKey = GetLinkSharedPubKey(dhtKey, vchLinkPubKey); - if (vchGetSharedPubKey == vchSharedPubKey) - return true; - } - } - - return false; -} - -bool CLinkManager::GetLinkPrivateKey(const std::vector& vchSenderPubKey, const std::vector& vchSharedPubKey, std::array& sharedSeed, std::string& strErrorMessage) -{ - if (!pwalletMain) - return false; - - std::vector> vvchDHTPubKeys; - if (!pwalletMain->GetDHTPubKeys(vvchDHTPubKeys)) { - strErrorMessage = "Failed to get DHT key vector."; - return false; - } - // loop through each account key to check if it matches the shared key - for (const std::vector& vchPubKey : vvchDHTPubKeys) { - CDomainEntry entry; - if (pDomainEntryDB->ReadDomainEntryPubKey(vchPubKey, entry)) { - CKeyEd25519 dhtKey; - CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); - if (pwalletMain->GetDHTKey(keyID, dhtKey)) { - if (vchSharedPubKey == GetLinkSharedPubKey(dhtKey, vchSenderPubKey)) { - sharedSeed = GetLinkSharedPrivateKey(dhtKey, vchSenderPubKey); - return true; - } - } - else { - strErrorMessage = strErrorMessage + "Error getting DHT private key.\n"; - } - } - } - return false; -} -#endif // ENABLE_WALLET - bool CLinkManager::FindLink(const uint256& id, CLink& link) { if (m_Links.count(id) > 0) { @@ -196,38 +124,13 @@ bool CLinkManager::FindLinkBySubjectID(const uint256& subjectID, CLink& getLink) return false; } -#ifdef ENABLE_WALLET -void CLinkManager::ProcessQueue() -{ - if (!pwalletMain) - return; - - if (pwalletMain->IsLocked()) - return; - - // make sure we are not stuck in an infinite loop - size_t size = QueueSize(); - size_t counter = 0; - LogPrintf("CLinkManager::%s -- Start links in queue = %d\n", __func__, size); - while (!linkQueue.empty() && size > counter) - { - // TODO (BDAP): Do we need to lock the queue while processing? - CLinkStorage storage = linkQueue.front(); - ProcessLink(storage); - linkQueue.pop(); - counter++; - } - LogPrintf("CLinkManager::%s -- Finished links in queue = %d\n", __func__, QueueSize()); -} -#else +#ifndef ENABLE_WALLET void CLinkManager::ProcessQueue() { return; } #endif // ENABLE_WALLET - - bool CLinkManager::ListMyPendingRequests(std::vector& vchLinks) { for (const std::pair& link : m_Links) @@ -265,485 +168,13 @@ bool CLinkManager::ListMyCompleted(std::vector& vchLinks) return true; } +#ifndef ENABLE_WALLET bool CLinkManager::ProcessLink(const CLinkStorage& storage, const bool fStoreInQueueOnly) { - -#ifndef ENABLE_WALLET - linkQueue.push(storage); - return true; -#else - if (!pwalletMain) { - linkQueue.push(storage); - return true; - } - - if (fStoreInQueueOnly || pwalletMain->IsLocked()) { linkQueue.push(storage); return true; - } - int nDataVersion = -1; - if (!storage.Encrypted()) - { - if (storage.nType == 1) // Clear text link request - { - std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); - CLinkRequest link(vchData, storage.txHash); - LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - link.nHeight = storage.nHeight; - link.txHash = storage.txHash; - link.nExpireTime = storage.nExpireTime; - CDomainEntry entry; - if (GetDomainEntry(link.RequestorFullObjectPath, entry)) { - if (SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { - bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); - LogPrint("bdap", "%s -- Link request from me found with a valid signature proof. Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - uint256 linkID = GetLinkID(link); - CLink record; - std::map::iterator it = m_Links.find(linkID); - if (it != m_Links.end()) { - record = it->second; - } - record.LinkID = linkID; - record.fRequestFromMe = fIsLinkFromMe; - if (record.nHeightAccept > 0) { - record.nLinkState = 2; - } - else { - record.nLinkState = 1; - } - record.RequestorFullObjectPath = link.RequestorFullObjectPath; - record.RecipientFullObjectPath = link.RecipientFullObjectPath; - record.RequestorPubKey = link.RequestorPubKey; - record.SharedRequestPubKey = link.SharedPubKey; - record.LinkMessage = link.LinkMessage; - record.nHeightRequest = link.nHeight; - record.nExpireTimeRequest = link.nExpireTime; - record.txHashRequest = link.txHash; - record.RequestorWalletAddress = entry.WalletAddress; - if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) - { - std::string strErrorMessage = ""; - if (!GetMessageInfo(record, strErrorMessage)) - { - LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); - } - else - { - pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); - m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; - } - //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); - } - LogPrint("bdap", "%s -- Clear text link request added to map id = %s\n", __func__, linkID.ToString()); - m_Links[linkID] = record; - - } - else - LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - } - else { - LogPrintf("%s -- Link request GetDomainEntry failed.\n", __func__); - return false; - } - } - else if (storage.nType == 2) // Clear text accept - { - std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); - CLinkAccept link(vchData, storage.txHash); - LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - link.nHeight = storage.nHeight; - link.txHash = storage.txHash; - link.nExpireTime = storage.nExpireTime; - CDomainEntry entry; - if (GetDomainEntry(link.RecipientFullObjectPath, entry)) { - if (SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { - bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); - //bool fIsLinkForMe = IsLinkForMe(storage.vchLinkPubKey, storage.vchSharedPubKey); - LogPrint("bdap", "%s -- Link accept from me found with a valid signature proof. Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - uint256 linkID = GetLinkID(link); - CLink record; - std::map::iterator it = m_Links.find(linkID); - if (it != m_Links.end()) { - record = it->second; - } - record.LinkID = linkID; - record.fAcceptFromMe = fIsLinkFromMe; - record.nLinkState = 2; - record.RequestorFullObjectPath = link.RequestorFullObjectPath; - record.RecipientFullObjectPath = link.RecipientFullObjectPath; - record.RecipientPubKey = link.RecipientPubKey; - record.SharedAcceptPubKey = link.SharedPubKey; - record.nHeightAccept = link.nHeight; - record.nExpireTimeAccept = link.nExpireTime; - record.txHashAccept = link.txHash; - record.RecipientWalletAddress = entry.WalletAddress; - if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) - { - std::string strErrorMessage = ""; - if (!GetMessageInfo(record, strErrorMessage)) - { - LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); - } - else - { - pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); - m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; - } - //LogPrintf("%s -- link accept = %s\n", __func__, record.ToString()); - } - LogPrint("bdap", "%s -- Clear text accept added to map id = %s, %s\n", __func__, linkID.ToString(), record.ToString()); - m_Links[linkID] = record; - } - else - LogPrintf("%s -- Warning! Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - } - else { - LogPrintf("%s -- Link accept GetDomainEntry failed.\n", __func__); - return false; - } - } - } - else if (storage.Encrypted() && !pwalletMain->IsLocked()) - { - bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); - bool fIsLinkForMe = IsLinkForMe(storage.vchLinkPubKey, storage.vchSharedPubKey); - if (!fIsLinkFromMe && !fIsLinkForMe) { - // This happens if you lose your DHT private key but have the BDAP account link wallet private key. - LogPrintf("%s -- ** Warning: Encrypted link received but can not process it: TxID = %s\n", __func__, storage.txHash.ToString()); - return false; - } - - if (storage.nType == 1 && fIsLinkFromMe) // Encrypted link request from me - { - //LogPrintf("%s -- Version 1 link request from me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); - CKeyEd25519 privDHTKey; - CKeyID keyID(Hash160(storage.vchLinkPubKey.begin(), storage.vchLinkPubKey.end())); - if (pwalletMain->GetDHTKey(keyID, privDHTKey)) { - std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); - std::string strMessage = ""; - std::vector dataDecrypted; - if (DecryptBDAPData(privDHTKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { - std::vector vchData, vchHash; - CScript scriptData; - scriptData << OP_RETURN << dataDecrypted; - if (GetBDAPData(scriptData, vchData, vchHash)) { - CLinkRequest link(dataDecrypted, storage.txHash); - LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - CDomainEntry entry; - if (!GetDomainEntry(link.RequestorFullObjectPath, entry)) { - LogPrintf("%s -- Failed to get link requestor %s\n", __func__, stringFromVch(link.RequestorFullObjectPath)); - return false; - } - if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { - LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - return false; - } - link.nHeight = storage.nHeight; - link.nExpireTime = storage.nExpireTime; - uint256 linkID = GetLinkID(link); - CLink record; - std::map::iterator it = m_Links.find(linkID); - if (it != m_Links.end()) { - record = it->second; - } - record.LinkID = linkID; - record.fRequestFromMe = fIsLinkFromMe; - record.fAcceptFromMe = (fIsLinkFromMe && fIsLinkForMe); - if (record.nHeightAccept > 0) { - record.nLinkState = 2; - } - else { - record.nLinkState = 1; - } - record.RequestorFullObjectPath = link.RequestorFullObjectPath; - record.RecipientFullObjectPath = link.RecipientFullObjectPath; - record.RequestorPubKey = link.RequestorPubKey; - record.SharedRequestPubKey = link.SharedPubKey; - record.LinkMessage = link.LinkMessage; - record.nHeightRequest = link.nHeight; - record.nExpireTimeRequest = link.nExpireTime; - record.txHashRequest = link.txHash; - record.RequestorWalletAddress = entry.WalletAddress; - if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) - { - std::string strErrorMessage = ""; - if (!GetMessageInfo(record, strErrorMessage)) - { - LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); - } - else - { - pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); - m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; - } - //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); - } - LogPrint("bdap", "%s -- Encrypted link request from me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); - m_Links[linkID] = record; - } - else { - LogPrintf("%s -- Link request GetBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link request DecryptBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link request GetDHTKey failed.\n", __func__); - return false; - } - } - else if (storage.nType == 1 && !fIsLinkFromMe && fIsLinkForMe) // Encrypted link request for me - { - //LogPrintf("%s -- Version 1 link request for me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); - CKeyEd25519 sharedDHTKey; - std::array sharedSeed; - std::string strErrorMessage; - if (GetLinkPrivateKey(storage.vchLinkPubKey, storage.vchSharedPubKey, sharedSeed, strErrorMessage)) { - CKeyEd25519 sharedKey(sharedSeed); - std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); - std::string strMessage = ""; - std::vector dataDecrypted; - if (DecryptBDAPData(sharedKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { - std::vector vchData, vchHash; - CScript scriptData; - scriptData << OP_RETURN << dataDecrypted; - if (GetBDAPData(scriptData, vchData, vchHash)) { - CLinkRequest link(dataDecrypted, storage.txHash); - LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - CDomainEntry entry; - if (!GetDomainEntry(link.RequestorFullObjectPath, entry)) { - LogPrintf("%s -- Failed to get link requestor %s\n", __func__, stringFromVch(link.RequestorFullObjectPath)); - return false; - } - if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { - LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - return false; - } - link.nHeight = storage.nHeight; - link.nExpireTime = storage.nExpireTime; - uint256 linkID = GetLinkID(link); - CLink record; - std::map::iterator it = m_Links.find(linkID); - if (it != m_Links.end()) { - record = it->second; - } - - record.LinkID = linkID; - record.fRequestFromMe = fIsLinkFromMe; - if (record.nHeightAccept > 0) { - record.nLinkState = 2; - } - else { - record.nLinkState = 1; - } - record.RequestorFullObjectPath = link.RequestorFullObjectPath; - record.RecipientFullObjectPath = link.RecipientFullObjectPath; - record.RequestorPubKey = link.RequestorPubKey; - record.SharedRequestPubKey = link.SharedPubKey; - record.LinkMessage = link.LinkMessage; - record.nHeightRequest = link.nHeight; - record.nExpireTimeRequest = link.nExpireTime; - record.txHashRequest = link.txHash; - record.RequestorWalletAddress = entry.WalletAddress; - if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) - { - std::string strErrorMessage = ""; - if (!GetMessageInfo(record, strErrorMessage)) - { - LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); - } - else - { - pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); - m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; - } - //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); - } - LogPrint("bdap", "%s -- Encrypted link request for me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); - m_Links[linkID] = record; - } - else { - LogPrintf("%s -- Link request GetBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link request DecryptBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link request GetLinkPrivateKey failed.\n", __func__); - return false; - } - } - else if (storage.nType == 2 && fIsLinkFromMe) // Link accept from me - { - //LogPrintf("%s -- Version 1 encrypted link accept from me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); - CKeyEd25519 privDHTKey; - CKeyID keyID(Hash160(storage.vchLinkPubKey.begin(), storage.vchLinkPubKey.end())); - if (pwalletMain->GetDHTKey(keyID, privDHTKey)) { - std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); - std::string strMessage = ""; - std::vector dataDecrypted; - if (DecryptBDAPData(privDHTKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { - std::vector vchData, vchHash; - CScript scriptData; - scriptData << OP_RETURN << dataDecrypted; - if (GetBDAPData(scriptData, vchData, vchHash)) { - CLinkAccept link(dataDecrypted, storage.txHash); - LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - CDomainEntry entry; - if (!GetDomainEntry(link.RecipientFullObjectPath, entry)) { - LogPrintf("%s -- Failed to get link recipient %s\n", __func__, stringFromVch(link.RecipientFullObjectPath)); - return false; - } - if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { - LogPrintf("%s ***** Warning. Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - return false; - } - link.nHeight = storage.nHeight; - link.nExpireTime = storage.nExpireTime; - uint256 linkID = GetLinkID(link); - CLink record; - std::map::iterator it = m_Links.find(linkID); - if (it != m_Links.end()) { - record = it->second; - } - record.LinkID = linkID; - record.fRequestFromMe = (fIsLinkFromMe && fIsLinkForMe); - record.fAcceptFromMe = fIsLinkFromMe; - record.nLinkState = 2; - record.RequestorFullObjectPath = link.RequestorFullObjectPath; - record.RecipientFullObjectPath = link.RecipientFullObjectPath; - record.RecipientPubKey = link.RecipientPubKey; - record.SharedAcceptPubKey = link.SharedPubKey; - record.nHeightAccept = link.nHeight; - record.nExpireTimeAccept = link.nExpireTime; - record.txHashAccept = link.txHash; - record.RecipientWalletAddress = entry.WalletAddress; - if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) - { - std::string strErrorMessage = ""; - if (!GetMessageInfo(record, strErrorMessage)) - { - LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); - } - else - { - pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); - m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; - } - //LogPrintf("%s -- accept request = %s\n", __func__, record.ToString()); - } - LogPrint("bdap", "%s -- Encrypted link accept from me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); - m_Links[linkID] = record; - } - else { - LogPrintf("%s -- Link accept GetBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link accept DecryptBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link accept GetDHTKey failed.\n", __func__); - return false; - } - } - else if (storage.nType == 2 && !fIsLinkFromMe && fIsLinkForMe) // Link accept for me - { - //LogPrintf("%s -- Version 1 link accept for me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); - CKeyEd25519 sharedDHTKey; - std::array sharedSeed; - std::string strErrorMessage; - if (GetLinkPrivateKey(storage.vchLinkPubKey, storage.vchSharedPubKey, sharedSeed, strErrorMessage)) { - CKeyEd25519 sharedKey(sharedSeed); - std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); - std::string strMessage = ""; - std::vector dataDecrypted; - if (DecryptBDAPData(sharedKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { - std::vector vchData, vchHash; - CScript scriptData; - scriptData << OP_RETURN << dataDecrypted; - if (GetBDAPData(scriptData, vchData, vchHash)) { - CLinkAccept link(dataDecrypted, storage.txHash); - LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - CDomainEntry entry; - if (!GetDomainEntry(link.RecipientFullObjectPath, entry)) { - LogPrintf("%s -- Failed to get link recipient %s\n", __func__, stringFromVch(link.RecipientFullObjectPath)); - return false; - } - if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { - LogPrintf("%s ***** Warning. Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); - return false; - } - link.nHeight = storage.nHeight; - link.nExpireTime = storage.nExpireTime; - uint256 linkID = GetLinkID(link); - CLink record; - std::map::iterator it = m_Links.find(linkID); - if (it != m_Links.end()) { - record = it->second; - } - record.LinkID = linkID; - record.fAcceptFromMe = fIsLinkFromMe; - record.nLinkState = 2; - record.RequestorFullObjectPath = link.RequestorFullObjectPath; - record.RecipientFullObjectPath = link.RecipientFullObjectPath; - record.RecipientPubKey = link.RecipientPubKey; - record.SharedAcceptPubKey = link.SharedPubKey; - record.nHeightAccept = link.nHeight; - record.nExpireTimeAccept = link.nExpireTime; - record.txHashAccept = link.txHash; - record.RecipientWalletAddress = entry.WalletAddress; - if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) - { - std::string strErrorMessage = ""; - if (!GetMessageInfo(record, strErrorMessage)) - { - LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); - } - else - { - pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); - m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; - } - //LogPrintf("%s -- accept request = %s\n", __func__, record.ToString()); - } - LogPrint("bdap", "%s -- Encrypted link accept for me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); - m_Links[linkID] = record; - } - else { - LogPrintf("%s -- Link accept GetBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link accept DecryptBDAPData failed.\n", __func__); - return false; - } - } - else { - LogPrintf("%s -- Link accept GetLinkPrivateKey failed.\n", __func__); - return false; - } - } - else - { - linkQueue.push(storage); - } - } - return true; -#endif // ENABLE_WALLET } +#endif // ENABLE_WALLET std::vector CLinkManager::GetCompletedLinkInfo(const std::vector& vchFullObjectPath) { @@ -828,161 +259,6 @@ uint256 GetLinkID(const std::string& account1, const std::string& account2) return uint256(); } -#ifdef ENABLE_WALLET -bool GetSharedPrivateSeed(const CLink& link, std::array& seed, std::string& strErrorMessage) -{ - if (!pwalletMain) - return false; - - if (link.nLinkState != 2) - return false; - - //LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); - std::array sharedSeed1; - std::array sharedSeed2; - CDomainEntry entry; - if (pDomainEntryDB->GetDomainEntryInfo(link.RecipientFullObjectPath, entry)) { - if (link.fRequestFromMe) // Requestor - { - // first key exchange: requestor link pubkey + recipient account pubkey - std::vector vchRecipientPubKey = entry.DHTPublicKey; - std::vector vchRequestorPubKey = link.RequestorPubKey; - CKeyEd25519 reqKey; - CKeyID reqKeyID(Hash160(vchRequestorPubKey.begin(), vchRequestorPubKey.end())); - if (pwalletMain->GetDHTKey(reqKeyID, reqKey)) { - std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(reqKey, vchRecipientPubKey); - if (link.SharedRequestPubKey == vchGetLinkSharedPubKey) - { - sharedSeed1 = GetLinkSharedPrivateKey(reqKey, vchRecipientPubKey); - } - else - { - strErrorMessage = strprintf("Requestor SharedRequestPubKey (%s) does not match derived shared request public key (%s).", - stringFromVch(link.SharedRequestPubKey), stringFromVch(vchGetLinkSharedPubKey)); - return false; - } - } - else { - strErrorMessage = strprintf("Failed to get reqKey %s DHT private key.", stringFromVch(vchRequestorPubKey)); - return false; - } - // second key exchange: recipient link pubkey + requestor account pubkey - CDomainEntry entryRequestor; - if (pDomainEntryDB->GetDomainEntryInfo(link.RequestorFullObjectPath, entryRequestor)) - { - std::vector vchReqPubKey = entryRequestor.DHTPublicKey; - std::vector vchLinkPubKey = link.RecipientPubKey; - CKeyEd25519 linkKey; - CKeyID linkKeyID(Hash160(vchReqPubKey.begin(), vchReqPubKey.end())); - if (pwalletMain->GetDHTKey(linkKeyID, linkKey)) { - std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(linkKey, vchLinkPubKey); - if (link.SharedAcceptPubKey == vchGetLinkSharedPubKey) - { - sharedSeed2 = GetLinkSharedPrivateKey(linkKey, vchLinkPubKey); - } - else - { - strErrorMessage = strprintf("Requestor SharedAcceptPubKey (%s) does not match derived shared link public key (%s).", - stringFromVch(link.SharedAcceptPubKey), stringFromVch(vchGetLinkSharedPubKey)); - return false; - } - } - else { - strErrorMessage = strprintf("Failed to get requestor link Key %s DHT private key.", stringFromVch(vchLinkPubKey)); - return false; - } - } - else - { - strErrorMessage = strprintf("Can not find %s link requestor record.", stringFromVch(link.RequestorFullObjectPath)); - return false; - } - } - else // Recipient - { - // first key exchange: requestor link pubkey + recipient account pubkey - std::vector vchRecipientPubKey = entry.DHTPublicKey; - std::vector vchRequestorPubKey = link.RequestorPubKey; - CKeyEd25519 recKey; - CKeyID recKeyID(Hash160(vchRecipientPubKey.begin(), vchRecipientPubKey.end())); - if (pwalletMain->GetDHTKey(recKeyID, recKey)) - { - std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(recKey, vchRequestorPubKey); - if (link.SharedRequestPubKey == vchGetLinkSharedPubKey) { - sharedSeed1 = GetLinkSharedPrivateKey(recKey, vchRequestorPubKey); - } - else - { - strErrorMessage = strprintf("Recipient SharedRequestPubKey (%s) does not match derived shared request public key (%s).", - stringFromVch(link.SharedRequestPubKey), stringFromVch(vchGetLinkSharedPubKey)); - return false; - } - } - else { - strErrorMessage = strprintf("Failed to get recKey %s DHT private key.", stringFromVch(vchRecipientPubKey)); - return false; - } - // second key exchange: recipient link pubkey + requestor account pubkey - CDomainEntry entryRequestor; - if (pDomainEntryDB->GetDomainEntryInfo(link.RequestorFullObjectPath, entryRequestor)) - { - std::vector vchLinkPubKey = link.RecipientPubKey; - std::vector vchReqPubKey = entryRequestor.DHTPublicKey; - CKeyEd25519 linkKey; - CKeyID linkKeyID(Hash160(vchLinkPubKey.begin(), vchLinkPubKey.end())); - if (pwalletMain->GetDHTKey(linkKeyID, linkKey)) - { - std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(linkKey, vchReqPubKey); - if (link.SharedAcceptPubKey == vchGetLinkSharedPubKey) { - sharedSeed2 = GetLinkSharedPrivateKey(linkKey, vchReqPubKey); - } - else - { - strErrorMessage = strprintf("Recipient SharedAcceptPubKey (%s) does not match derived shared link public key (%s).", - stringFromVch(link.SharedAcceptPubKey), stringFromVch(vchGetLinkSharedPubKey)); - return false; - } - } - else { - strErrorMessage = strprintf("Failed to get recipient linkKey %s DHT private key.", stringFromVch(vchLinkPubKey)); - return false; - } - } - else - { - strErrorMessage = strprintf("Can not find %s link requestor record.", stringFromVch(link.RequestorFullObjectPath)); - return false; - } - } - } - else - { - strErrorMessage = strprintf("Can not find %s link recipient record.", stringFromVch(link.RecipientFullObjectPath)); - return false; - } - CKeyEd25519 sharedKey1(sharedSeed1); - CKeyEd25519 sharedKey2(sharedSeed2); - // third key exchange: shared link request pubkey + shared link accept pubkey - // Only the link recipient and requestor can derive this secret key. - // the third shared public key is not on the blockchain and should only be known by the participants. - seed = GetLinkSharedPrivateKey(sharedKey1, sharedKey2.GetPubKey()); - return true; -} - -bool GetMessageInfo(CLink& link, std::string& strErrorMessage) -{ - std::array seed; - if (!GetSharedPrivateSeed(link, seed, strErrorMessage)) - { - return false; - } - CKeyEd25519 key(seed); - link.vchSecretPubKeyBytes = key.GetPubKeyBytes(); - link.SubjectID = Hash(link.vchSecretPubKeyBytes.begin(), link.vchSecretPubKeyBytes.end()); - return true; -} -#endif // ENABLE_WALLET - uint256 GetMessageID(const std::vector& vchPubKey, const int64_t& timestamp) { CScript scriptMessage; @@ -994,5 +270,3 @@ uint256 GetMessageID(const CKeyEd25519& key, const int64_t& timestamp) { return GetMessageID(key.GetPubKeyBytes(), timestamp); } - -//#endif // ENABLE_WALLET \ No newline at end of file diff --git a/src/bdap/utils.cpp b/src/bdap/utils.cpp index 4f63c4f3c..ebdb8c671 100644 --- a/src/bdap/utils.cpp +++ b/src/bdap/utils.cpp @@ -4,6 +4,7 @@ #include "bdap/utils.h" +#include "base58.h" #include "chainparams.h" #include "coins.h" #include "core_io.h" @@ -198,24 +199,6 @@ bool GetBDAPData(const CTxOut& out, std::vector& vchData, std::ve return GetBDAPData(out.scriptPubKey, vchData, vchHash); } -void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient) -{ - CRecipient recp = {scriptPubKey, recipient.nAmount, false}; - recipient = recp; - CTxOut txout(recipient.nAmount, scriptPubKey); - size_t nSize = GetSerializeSize(txout, SER_DISK, 0) + 148u; - recipient.nAmount = 3 * minRelayTxFee.GetFee(nSize); -} - -void CreateFeeRecipient(CScript& scriptPubKey, const std::vector& data, CRecipient& recipient) -{ - // add hash to data output (must match hash in inputs check with the tx scriptpubkey hash) - uint256 hash = Hash(data.begin(), data.end()); - std::vector vchHashRand = vchFromValue(hash.GetHex()); - scriptPubKey << vchHashRand; - CRecipient recp = {scriptPubKey, 0, false}; - recipient = recp; -} void ToLowerCase(CharString& vchValue) { std::string strValue; @@ -609,24 +592,6 @@ bool ExtractOpTypeValue(const CScript& script, std::string& strOpType, std::vect return true; } -bool GetScriptOpTypeValue(const std::vector& vecSend, CScript& bdapOpScript, std::string& strOpType, std::vector& vchValue) -{ - LogPrint("bdap", "%s -- vecSend size = %u \n", __func__, vecSend.size()); - for (const CRecipient& rec : vecSend) { - CScript script = rec.scriptPubKey; - if (!script.IsUnspendable()) { - if (ExtractOpTypeValue(script, strOpType, vchValue)) { - bdapOpScript = script; - break; - } - } - } - if (strOpType.size() > 0) { - return true; - } - return false; -} - bool GetTransactionOpTypeValue(const CTransaction& tx, CScript& bdapOpScript, std::string& strOpType, std::vector& vchValue) { for (const CTxOut& out : tx.vout) diff --git a/src/bdap/utils.h b/src/bdap/utils.h index e00e9be72..a2f3d7b73 100644 --- a/src/bdap/utils.h +++ b/src/bdap/utils.h @@ -13,6 +13,7 @@ class CCoinsViewCache; class CDynamicAddress; +class CStealthAddress; struct CRecipient; class CScript; class CTxOut; diff --git a/src/bdap/vgpmessage.cpp b/src/bdap/vgpmessage.cpp index 5e0d39df8..313317701 100644 --- a/src/bdap/vgpmessage.cpp +++ b/src/bdap/vgpmessage.cpp @@ -6,6 +6,7 @@ #include "bdap/vgpmessage.h" +#include "arith_uint256.h" #include "base58.h" #include "bdap/linkmanager.h" #include "bdap/utils.h" @@ -19,79 +20,16 @@ #include "script/script.h" #include "streams.h" #include "timedata.h" +#include "uint256.h" #include "util.h" #include "wallet/wallet.h" #include -static std::map mapMyVGPMessages; -static CCriticalSection cs_mapMyVGPMessages; -static int nMyMessageCounter = 0; - static std::map mapRecentMessageLog; static CCriticalSection cs_mapRecentMessageLog; static int nMessageCounter = 0; -class CMessage -{ -public: - static const int CURRENT_VERSION = 1; - int nMessageVersion; - std::vector vchMessageType; - std::vector vchMessage; - std::vector vchSenderFQDN; - bool fKeepLast; - - CMessage() - { - SetNull(); - } - - CMessage(const int& version, const std::vector& type, const std::vector& message, const std::vector& sender, bool keeplast) - : nMessageVersion(version), vchMessageType(type), vchMessage(message), vchSenderFQDN(sender), fKeepLast(keeplast) {} - - CMessage(const std::vector& vchData) - { - UnserializeFromData(vchData); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(nMessageVersion); - READWRITE(vchMessageType); - READWRITE(vchMessage); - READWRITE(vchSenderFQDN); - READWRITE(fKeepLast); - } - - void SetNull() - { - nMessageVersion = -1; - vchMessageType.clear(); - vchMessage.clear(); - vchSenderFQDN.clear(); - fKeepLast = false; - } - - inline bool IsNull() const { return (nMessageVersion == -1); } - - inline CMessage operator=(const CMessage& b) - { - nMessageVersion = b.nMessageVersion; - vchMessageType = b.vchMessageType; - vchMessage = b.vchMessage; - vchSenderFQDN = b.vchSenderFQDN; - fKeepLast = b.fKeepLast; - return *this; - } - - void Serialize(std::vector& vchData); - bool UnserializeFromData(const std::vector& vchData); -}; - void CMessage::Serialize(std::vector& vchData) { CDataStream dsMessageData(SER_NETWORK, PROTOCOL_VERSION); @@ -529,49 +467,6 @@ bool ReceivedMessage(const uint256& messageHash) return false; } -void CleanupMyMessageMap() -{ - // map with message type, message sender and timestamp. Used to keep last message from a sender/type pair. - std::map, std::vector>, int64_t> mapMessageTypeFromTimestamp; - int64_t nCurrentTimeStamp = GetAdjustedTime(); - std::map::iterator itr = mapMyVGPMessages.begin(); - while (itr != mapMyVGPMessages.end()) - { - CVGPMessage message = (*itr).second; - CUnsignedVGPMessage unsignedMessage(message.vchMsg); - if (!unsignedMessage.fEncrypted && nCurrentTimeStamp > unsignedMessage.nTimeStamp + KEEP_MY_MESSAGE_ALIVE_SECONDS) - { - CMessage message(unsignedMessage.vchMessageData); - std::pair, std::vector> pairTypeFrom = std::make_pair(message.vchMessageType, message.vchSenderFQDN); - if (!message.fKeepLast) { - itr = mapMyVGPMessages.erase(itr); - } - else { - std::map, std::vector>, int64_t>::iterator itTypeFrom = mapMessageTypeFromTimestamp.find(pairTypeFrom); - if (itTypeFrom != mapMessageTypeFromTimestamp.end()) { - if (itTypeFrom->second > unsignedMessage.nTimeStamp) { - itr = mapMyVGPMessages.erase(itr); - } - else { - mapMessageTypeFromTimestamp[pairTypeFrom] = unsignedMessage.nTimeStamp; - ++itr; - } - } - else { - mapMessageTypeFromTimestamp[pairTypeFrom] = unsignedMessage.nTimeStamp; - ++itr; - } - } - } - else - { - ++itr; - } - } - LogPrintf("%s -- Size %d\n", __func__, mapMyVGPMessages.size()); -} - -#ifdef ENABLE_WALLET bool DecryptMessage(CUnsignedVGPMessage& unsignedMessage) { CLink link; @@ -608,103 +503,6 @@ bool DecryptMessage(CUnsignedVGPMessage& unsignedMessage) return false; } -void AddMyMessage(const CVGPMessage& message) -{ - bool fFound = false; - CUnsignedVGPMessage unsignedMessage(message.vchMsg); - LogPrint("bdap", "%s -- Message hash = %s, Link MessageID = %s\n", __func__, message.GetHash().ToString(), unsignedMessage.MessageID.ToString()); - CVGPMessage storeMessage; - if (pwalletMain && pLinkManager && !pwalletMain->IsLocked() && unsignedMessage.fEncrypted) - { - if (DecryptMessage(unsignedMessage)) - fFound = true; - } - if (fFound) - { - CVGPMessage newMessage(unsignedMessage); - storeMessage = newMessage; - } - else - { - storeMessage = message; - } - LOCK(cs_mapMyVGPMessages); - mapMyVGPMessages[storeMessage.GetHash()] = storeMessage; - nMyMessageCounter++; - if ((nMyMessageCounter % 10) == 0) - CleanupMyMessageMap(); -} - -void GetMyLinkMessages(const uint256& subjectID, std::vector& vMessages) -{ - LOCK(cs_mapMyVGPMessages); - std::map::iterator itr = mapMyVGPMessages.begin(); - while (itr != mapMyVGPMessages.end()) - { - CVGPMessage message = (*itr).second; - CUnsignedVGPMessage unsignedMessage(message.vchMsg); - if (unsignedMessage.SubjectID == subjectID) - { - if (unsignedMessage.fEncrypted) - { - if (pwalletMain && !pwalletMain->IsLocked() && DecryptMessage(unsignedMessage)) - { - vMessages.push_back(unsignedMessage); - } - } - else - { - vMessages.push_back(unsignedMessage); - } - } - itr++; - } -} - -void GetMyLinkMessagesByType(const std::vector& vchType, const std::vector& vchRecipientFQDN, std::vector& vMessages, bool& fKeepLast) -{ - LOCK(cs_mapMyVGPMessages); - std::map::iterator itr = mapMyVGPMessages.begin(); - while (itr != mapMyVGPMessages.end()) - { - CVGPMessage messageWrapper = (*itr).second; - CUnsignedVGPMessage unsignedMessage(messageWrapper.vchMsg); - if (unsignedMessage.fEncrypted && pwalletMain && !pwalletMain->IsLocked()) - { - DecryptMessage(unsignedMessage); - } - if (!unsignedMessage.fEncrypted && (vchType.size() == 0 || vchType == unsignedMessage.Type()) && unsignedMessage.SenderFQDN() != vchRecipientFQDN) - { - if (unsignedMessage.KeepLast()) - fKeepLast = true; - - vMessages.push_back(unsignedMessage); - } - itr++; - } -} - -void GetMyLinkMessagesBySubjectAndSender(const uint256& subjectID, const std::vector& vchSenderFQDN, - const std::vector& vchType, std::vector& vchMessages, bool& fKeepLast) -{ - LOCK(cs_mapMyVGPMessages); - std::map::iterator itr = mapMyVGPMessages.begin(); - while (itr != mapMyVGPMessages.end()) - { - CVGPMessage messageWrapper = (*itr).second; - CUnsignedVGPMessage unsignedMessage(messageWrapper.vchMsg); - if (unsignedMessage.SubjectID == subjectID && unsignedMessage.SenderFQDN() == vchSenderFQDN && (vchType.size() == 0 || vchType == unsignedMessage.Type())) - { - if (unsignedMessage.KeepLast()) - fKeepLast = true; - - vchMessages.push_back(messageWrapper); - } - itr++; - } -} -#endif // ENABLE_WALLET - void KeepLastTypeBySender(std::vector& vMessages) { std::map, std::vector>, std::pair > mapFromMessageTime; diff --git a/src/bdap/vgpmessage.h b/src/bdap/vgpmessage.h index d3c5905c7..80ef3d648 100644 --- a/src/bdap/vgpmessage.h +++ b/src/bdap/vgpmessage.h @@ -177,6 +177,66 @@ class CVGPMessage }; +class CMessage +{ +public: + static const int CURRENT_VERSION = 1; + int nMessageVersion; + std::vector vchMessageType; + std::vector vchMessage; + std::vector vchSenderFQDN; + bool fKeepLast; + + CMessage() + { + SetNull(); + } + + CMessage(const int& version, const std::vector& type, const std::vector& message, const std::vector& sender, bool keeplast) + : nMessageVersion(version), vchMessageType(type), vchMessage(message), vchSenderFQDN(sender), fKeepLast(keeplast) {} + + CMessage(const std::vector& vchData) + { + UnserializeFromData(vchData); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITE(nMessageVersion); + READWRITE(vchMessageType); + READWRITE(vchMessage); + READWRITE(vchSenderFQDN); + READWRITE(fKeepLast); + } + + void SetNull() + { + nMessageVersion = -1; + vchMessageType.clear(); + vchMessage.clear(); + vchSenderFQDN.clear(); + fKeepLast = false; + } + + inline bool IsNull() const { return (nMessageVersion == -1); } + + inline CMessage operator=(const CMessage& b) + { + nMessageVersion = b.nMessageVersion; + vchMessageType = b.vchMessageType; + vchMessage = b.vchMessage; + vchSenderFQDN = b.vchSenderFQDN; + fKeepLast = b.fKeepLast; + return *this; + } + + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData); +}; + bool GetSecretSharedKey(const std::string& strSenderFQDN, const std::string& strRecipientFQDN, CKeyEd25519& key, std::string& strErrorMessage); uint256 GetSubjectIDFromKey(const CKeyEd25519& key); diff --git a/src/bdap/wallet/keys.cpp b/src/bdap/wallet/keys.cpp new file mode 100644 index 000000000..658179de9 --- /dev/null +++ b/src/bdap/wallet/keys.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 2016-2019 Duality Blockchain Solutions +// Copyright (c) 2009-2019 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/wallet/keys.h" + +#include "arith_uint256.h" +#include "base58.h" +#include "key.h" +#include "pubkey.h" +#include "keystore.h" +#include "util.h" +#include "crypto/sha512.h" +#include "wallet/crypter.h" + +#include +#include +#include + +extern bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); +extern bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const std::vector& vchPubKey, CKeyEd25519& key); + +bool CBasicKeyStore::AddDHTKey(const CKeyEd25519& key, const std::vector& vchPubKey) +{ + LOCK(cs_KeyStore); + + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); +#ifdef ENABLE_SENSITIVE_DEBUG + LogPrint("dht", "CBasicKeyStore::AddDHTKey, \nkeyID = %s, \npubkey = %s, \nprivkey = %s, \nprivseed = %s\n", + keyID.ToString(), key.GetPubKeyString(), + key.GetPrivKeyString(), key.GetPrivSeedString()); +#endif // ENABLE_SENSITIVE_DEBUG + if (keyID != key.GetID()) { +#ifdef ENABLE_SENSITIVE_DEBUG + LogPrint("dht", "CBasicKeyStore::AddDHTKey GetID does't match \nvchPubKey.GetID() = %s, \nkey.GetID() = %s\n", + keyID.ToString(), key.GetID().ToString()); +#endif // ENABLE_SENSITIVE_DEBUG + return false; + } + mapDHTKeys[keyID] = key; + return true; +} + +bool CBasicKeyStore::GetDHTKey(const CKeyID& address, CKeyEd25519& keyOut) const +{ + { + LOCK(cs_KeyStore); + DHTKeyMap::const_iterator mi = mapDHTKeys.find(address); + if (mi != mapDHTKeys.end()) + { + keyOut = mi->second; + return true; + } + } + return false; +} + +bool CBasicKeyStore::GetDHTPubKeys(std::vector>& vvchDHTPubKeys) const +{ + for (const std::pair& key : mapDHTKeys) { + vvchDHTPubKeys.push_back(key.second.GetPubKey()); +#ifdef ENABLE_SENSITIVE_DEBUG + LogPrint("dht", "CBasicKeyStore::GetDHTPubKeys -- pubkey = %s\n", key.second.GetPubKeyString()); +#endif // ENABLE_SENSITIVE_DEBUG + } + return (vvchDHTPubKeys.size() > 0); +} + +bool CCryptoKeyStore::AddDHTKey(const CKeyEd25519& key, const std::vector& pubkey) +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) { + return CBasicKeyStore::AddDHTKey(key, pubkey); + } + + if (IsLocked(true)) + return false; + +#ifdef ENABLE_SENSITIVE_DEBUG + LogPrintf("dht: CCryptoKeyStore::AddDHTKey \npubkey = %s, \nprivkey = %s, \nprivseed = %s\n", + key.GetPubKeyString(), key.GetPrivKeyString(), key.GetPrivSeedString()); +#endif // ENABLE_SENSITIVE_DEBUG + + std::vector vchDHTPrivSeed = key.GetPrivSeed(); + std::vector vchCryptedSecret; + CKeyingMaterial vchSecret(vchDHTPrivSeed.begin(), vchDHTPrivSeed.end()); + if (!EncryptSecret(vMasterKey, vchSecret, key.GetHash(), vchCryptedSecret)) { + LogPrintf("dht: CCryptoKeyStore::AddDHTKey -- Error after EncryptSecret\n"); + return false; + } + + if (!AddCryptedDHTKey(key.GetPubKey(), vchCryptedSecret)) { + LogPrintf("dht: CCryptoKeyStore::AddDHTKey -- Error after AddCryptedDHTKey\n"); + return false; + } + } + return true; +} + +bool CCryptoKeyStore::AddCryptedDHTKey(const std::vector& vchPubKey, const std::vector& vchCryptedSecret) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return false; + + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); + mapCryptedDHTKeys[keyID] = make_pair(vchPubKey, vchCryptedSecret); + } + return true; +} + +bool CCryptoKeyStore::GetDHTKey(const CKeyID& address, CKeyEd25519& keyOut) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::GetDHTKey(address, keyOut); + + CryptedDHTKeyMap::const_iterator mi = mapCryptedDHTKeys.find(address); + if (mi != mapCryptedDHTKeys.end()) + { + const std::vector& vchPubKey = (*mi).second.first; + const std::vector& vchCryptedSecret = (*mi).second.second; + return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut); + } + } + return false; +} diff --git a/src/bdap/wallet/keys.h b/src/bdap/wallet/keys.h new file mode 100644 index 000000000..e18d72408 --- /dev/null +++ b/src/bdap/wallet/keys.h @@ -0,0 +1,9 @@ +// Copyright (c) 2016-2019 Duality Blockchain Solutions +// Copyright (c) 2009-2019 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_BDAP_KEYS_H +#define BITCOIN_BDAP_KEYS_H + +#endif // BITCOIN_BDAP_KEYS_H \ No newline at end of file diff --git a/src/bdap/wallet/linkmanager.cpp b/src/bdap/wallet/linkmanager.cpp new file mode 100644 index 000000000..14087a653 --- /dev/null +++ b/src/bdap/wallet/linkmanager.cpp @@ -0,0 +1,737 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/linkmanager.h" + +#include "base58.h" +#include "bdap/domainentry.h" +#include "bdap/domainentrydb.h" +#include "bdap/linking.h" +#include "bdap/utils.h" +#include "dht/ed25519.h" +#include "pubkey.h" +#include "bdap/stealth.h" +#include "wallet/wallet.h" + +#include "encryption.h" // for VGP DecryptBDAPData + +#ifdef ENABLE_WALLET +bool CLinkManager::IsLinkFromMe(const std::vector& vchLinkPubKey) +{ + if (!pwalletMain) + return false; + + CKeyID keyID(Hash160(vchLinkPubKey.begin(), vchLinkPubKey.end())); + CKeyEd25519 keyOut; + if (pwalletMain->GetDHTKey(keyID, keyOut)) + return true; + + return false; +} + +bool CLinkManager::IsLinkForMe(const std::vector& vchLinkPubKey, const std::vector& vchSharedPubKey) +{ + if (!pwalletMain) + return false; + + std::vector> vvchMyDHTPubKeys; + if (!pwalletMain->GetDHTPubKeys(vvchMyDHTPubKeys)) + return false; + + if (vvchMyDHTPubKeys.size() == 0) + return false; + + for (const std::vector& vchMyDHTPubKey : vvchMyDHTPubKeys) { + CKeyID keyID(Hash160(vchMyDHTPubKey.begin(), vchMyDHTPubKey.end())); + CKeyEd25519 dhtKey; + if (pwalletMain->GetDHTKey(keyID, dhtKey)) { + std::vector vchGetSharedPubKey = GetLinkSharedPubKey(dhtKey, vchLinkPubKey); + if (vchGetSharedPubKey == vchSharedPubKey) + return true; + } + } + + return false; +} + +bool CLinkManager::GetLinkPrivateKey(const std::vector& vchSenderPubKey, const std::vector& vchSharedPubKey, std::array& sharedSeed, std::string& strErrorMessage) +{ + if (!pwalletMain) + return false; + + std::vector> vvchDHTPubKeys; + if (!pwalletMain->GetDHTPubKeys(vvchDHTPubKeys)) { + strErrorMessage = "Failed to get DHT key vector."; + return false; + } + // loop through each account key to check if it matches the shared key + for (const std::vector& vchPubKey : vvchDHTPubKeys) { + CDomainEntry entry; + if (pDomainEntryDB->ReadDomainEntryPubKey(vchPubKey, entry)) { + CKeyEd25519 dhtKey; + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); + if (pwalletMain->GetDHTKey(keyID, dhtKey)) { + if (vchSharedPubKey == GetLinkSharedPubKey(dhtKey, vchSenderPubKey)) { + sharedSeed = GetLinkSharedPrivateKey(dhtKey, vchSenderPubKey); + return true; + } + } + else { + strErrorMessage = strErrorMessage + "Error getting DHT private key.\n"; + } + } + } + return false; +} + +void CLinkManager::ProcessQueue() +{ + if (!pwalletMain) + return; + + if (pwalletMain->IsLocked()) + return; + + // make sure we are not stuck in an infinite loop + size_t size = QueueSize(); + size_t counter = 0; + LogPrintf("CLinkManager::%s -- Start links in queue = %d\n", __func__, size); + while (!linkQueue.empty() && size > counter) + { + // TODO (BDAP): Do we need to lock the queue while processing? + CLinkStorage storage = linkQueue.front(); + ProcessLink(storage); + linkQueue.pop(); + counter++; + } + LogPrintf("CLinkManager::%s -- Finished links in queue = %d\n", __func__, QueueSize()); +} + +bool GetSharedPrivateSeed(const CLink& link, std::array& seed, std::string& strErrorMessage) +{ + if (!pwalletMain) + return false; + + if (link.nLinkState != 2) + return false; + + //LogPrintf("bdap: %s -- %s\n", __func__, link.ToString()); + std::array sharedSeed1; + std::array sharedSeed2; + CDomainEntry entry; + if (pDomainEntryDB->GetDomainEntryInfo(link.RecipientFullObjectPath, entry)) { + if (link.fRequestFromMe) // Requestor + { + // first key exchange: requestor link pubkey + recipient account pubkey + std::vector vchRecipientPubKey = entry.DHTPublicKey; + std::vector vchRequestorPubKey = link.RequestorPubKey; + CKeyEd25519 reqKey; + CKeyID reqKeyID(Hash160(vchRequestorPubKey.begin(), vchRequestorPubKey.end())); + if (pwalletMain->GetDHTKey(reqKeyID, reqKey)) { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(reqKey, vchRecipientPubKey); + if (link.SharedRequestPubKey == vchGetLinkSharedPubKey) + { + sharedSeed1 = GetLinkSharedPrivateKey(reqKey, vchRecipientPubKey); + } + else + { + strErrorMessage = strprintf("Requestor SharedRequestPubKey (%s) does not match derived shared request public key (%s).", + stringFromVch(link.SharedRequestPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get reqKey %s DHT private key.", stringFromVch(vchRequestorPubKey)); + return false; + } + // second key exchange: recipient link pubkey + requestor account pubkey + CDomainEntry entryRequestor; + if (pDomainEntryDB->GetDomainEntryInfo(link.RequestorFullObjectPath, entryRequestor)) + { + std::vector vchReqPubKey = entryRequestor.DHTPublicKey; + std::vector vchLinkPubKey = link.RecipientPubKey; + CKeyEd25519 linkKey; + CKeyID linkKeyID(Hash160(vchReqPubKey.begin(), vchReqPubKey.end())); + if (pwalletMain->GetDHTKey(linkKeyID, linkKey)) { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(linkKey, vchLinkPubKey); + if (link.SharedAcceptPubKey == vchGetLinkSharedPubKey) + { + sharedSeed2 = GetLinkSharedPrivateKey(linkKey, vchLinkPubKey); + } + else + { + strErrorMessage = strprintf("Requestor SharedAcceptPubKey (%s) does not match derived shared link public key (%s).", + stringFromVch(link.SharedAcceptPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get requestor link Key %s DHT private key.", stringFromVch(vchLinkPubKey)); + return false; + } + } + else + { + strErrorMessage = strprintf("Can not find %s link requestor record.", stringFromVch(link.RequestorFullObjectPath)); + return false; + } + } + else // Recipient + { + // first key exchange: requestor link pubkey + recipient account pubkey + std::vector vchRecipientPubKey = entry.DHTPublicKey; + std::vector vchRequestorPubKey = link.RequestorPubKey; + CKeyEd25519 recKey; + CKeyID recKeyID(Hash160(vchRecipientPubKey.begin(), vchRecipientPubKey.end())); + if (pwalletMain->GetDHTKey(recKeyID, recKey)) + { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(recKey, vchRequestorPubKey); + if (link.SharedRequestPubKey == vchGetLinkSharedPubKey) { + sharedSeed1 = GetLinkSharedPrivateKey(recKey, vchRequestorPubKey); + } + else + { + strErrorMessage = strprintf("Recipient SharedRequestPubKey (%s) does not match derived shared request public key (%s).", + stringFromVch(link.SharedRequestPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get recKey %s DHT private key.", stringFromVch(vchRecipientPubKey)); + return false; + } + // second key exchange: recipient link pubkey + requestor account pubkey + CDomainEntry entryRequestor; + if (pDomainEntryDB->GetDomainEntryInfo(link.RequestorFullObjectPath, entryRequestor)) + { + std::vector vchLinkPubKey = link.RecipientPubKey; + std::vector vchReqPubKey = entryRequestor.DHTPublicKey; + CKeyEd25519 linkKey; + CKeyID linkKeyID(Hash160(vchLinkPubKey.begin(), vchLinkPubKey.end())); + if (pwalletMain->GetDHTKey(linkKeyID, linkKey)) + { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(linkKey, vchReqPubKey); + if (link.SharedAcceptPubKey == vchGetLinkSharedPubKey) { + sharedSeed2 = GetLinkSharedPrivateKey(linkKey, vchReqPubKey); + } + else + { + strErrorMessage = strprintf("Recipient SharedAcceptPubKey (%s) does not match derived shared link public key (%s).", + stringFromVch(link.SharedAcceptPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get recipient linkKey %s DHT private key.", stringFromVch(vchLinkPubKey)); + return false; + } + } + else + { + strErrorMessage = strprintf("Can not find %s link requestor record.", stringFromVch(link.RequestorFullObjectPath)); + return false; + } + } + } + else + { + strErrorMessage = strprintf("Can not find %s link recipient record.", stringFromVch(link.RecipientFullObjectPath)); + return false; + } + CKeyEd25519 sharedKey1(sharedSeed1); + CKeyEd25519 sharedKey2(sharedSeed2); + // third key exchange: shared link request pubkey + shared link accept pubkey + // Only the link recipient and requestor can derive this secret key. + // the third shared public key is not on the blockchain and should only be known by the participants. + seed = GetLinkSharedPrivateKey(sharedKey1, sharedKey2.GetPubKey()); + return true; +} + +bool GetMessageInfo(CLink& link, std::string& strErrorMessage) +{ + std::array seed; + if (!GetSharedPrivateSeed(link, seed, strErrorMessage)) + { + return false; + } + CKeyEd25519 key(seed); + link.vchSecretPubKeyBytes = key.GetPubKeyBytes(); + link.SubjectID = Hash(link.vchSecretPubKeyBytes.begin(), link.vchSecretPubKeyBytes.end()); + return true; +} + +bool CLinkManager::ProcessLink(const CLinkStorage& storage, const bool fStoreInQueueOnly) +{ + if (!pwalletMain) { + linkQueue.push(storage); + return true; + } + + if (fStoreInQueueOnly || pwalletMain->IsLocked()) { + linkQueue.push(storage); + return true; + } + int nDataVersion = -1; + if (!storage.Encrypted()) + { + if (storage.nType == 1) // Clear text link request + { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + CLinkRequest link(vchData, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + link.nHeight = storage.nHeight; + link.txHash = storage.txHash; + link.nExpireTime = storage.nExpireTime; + CDomainEntry entry; + if (GetDomainEntry(link.RequestorFullObjectPath, entry)) { + if (SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { + bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); + LogPrint("bdap", "%s -- Link request from me found with a valid signature proof. Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fRequestFromMe = fIsLinkFromMe; + if (record.nHeightAccept > 0) { + record.nLinkState = 2; + } + else { + record.nLinkState = 1; + } + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RequestorPubKey = link.RequestorPubKey; + record.SharedRequestPubKey = link.SharedPubKey; + record.LinkMessage = link.LinkMessage; + record.nHeightRequest = link.nHeight; + record.nExpireTimeRequest = link.nExpireTime; + record.txHashRequest = link.txHash; + record.RequestorWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Clear text link request added to map id = %s\n", __func__, linkID.ToString()); + m_Links[linkID] = record; + + } + else + LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + } + else { + LogPrintf("%s -- Link request GetDomainEntry failed.\n", __func__); + return false; + } + } + else if (storage.nType == 2) // Clear text accept + { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + CLinkAccept link(vchData, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + link.nHeight = storage.nHeight; + link.txHash = storage.txHash; + link.nExpireTime = storage.nExpireTime; + CDomainEntry entry; + if (GetDomainEntry(link.RecipientFullObjectPath, entry)) { + if (SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { + bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); + //bool fIsLinkForMe = IsLinkForMe(storage.vchLinkPubKey, storage.vchSharedPubKey); + LogPrint("bdap", "%s -- Link accept from me found with a valid signature proof. Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fAcceptFromMe = fIsLinkFromMe; + record.nLinkState = 2; + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RecipientPubKey = link.RecipientPubKey; + record.SharedAcceptPubKey = link.SharedPubKey; + record.nHeightAccept = link.nHeight; + record.nExpireTimeAccept = link.nExpireTime; + record.txHashAccept = link.txHash; + record.RecipientWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link accept = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Clear text accept added to map id = %s, %s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else + LogPrintf("%s -- Warning! Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + } + else { + LogPrintf("%s -- Link accept GetDomainEntry failed.\n", __func__); + return false; + } + } + } + else if (storage.Encrypted() && !pwalletMain->IsLocked()) + { + bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); + bool fIsLinkForMe = IsLinkForMe(storage.vchLinkPubKey, storage.vchSharedPubKey); + if (!fIsLinkFromMe && !fIsLinkForMe) { + // This happens if you lose your DHT private key but have the BDAP account link wallet private key. + LogPrintf("%s -- ** Warning: Encrypted link received but can not process it: TxID = %s\n", __func__, storage.txHash.ToString()); + return false; + } + + if (storage.nType == 1 && fIsLinkFromMe) // Encrypted link request from me + { + //LogPrintf("%s -- Version 1 link request from me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 privDHTKey; + CKeyID keyID(Hash160(storage.vchLinkPubKey.begin(), storage.vchLinkPubKey.end())); + if (pwalletMain->GetDHTKey(keyID, privDHTKey)) { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(privDHTKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkRequest link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RequestorFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link requestor %s\n", __func__, stringFromVch(link.RequestorFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fRequestFromMe = fIsLinkFromMe; + record.fAcceptFromMe = (fIsLinkFromMe && fIsLinkForMe); + if (record.nHeightAccept > 0) { + record.nLinkState = 2; + } + else { + record.nLinkState = 1; + } + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RequestorPubKey = link.RequestorPubKey; + record.SharedRequestPubKey = link.SharedPubKey; + record.LinkMessage = link.LinkMessage; + record.nHeightRequest = link.nHeight; + record.nExpireTimeRequest = link.nExpireTime; + record.txHashRequest = link.txHash; + record.RequestorWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link request from me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link request GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request GetDHTKey failed.\n", __func__); + return false; + } + } + else if (storage.nType == 1 && !fIsLinkFromMe && fIsLinkForMe) // Encrypted link request for me + { + //LogPrintf("%s -- Version 1 link request for me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 sharedDHTKey; + std::array sharedSeed; + std::string strErrorMessage; + if (GetLinkPrivateKey(storage.vchLinkPubKey, storage.vchSharedPubKey, sharedSeed, strErrorMessage)) { + CKeyEd25519 sharedKey(sharedSeed); + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(sharedKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkRequest link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RequestorFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link requestor %s\n", __func__, stringFromVch(link.RequestorFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + + record.LinkID = linkID; + record.fRequestFromMe = fIsLinkFromMe; + if (record.nHeightAccept > 0) { + record.nLinkState = 2; + } + else { + record.nLinkState = 1; + } + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RequestorPubKey = link.RequestorPubKey; + record.SharedRequestPubKey = link.SharedPubKey; + record.LinkMessage = link.LinkMessage; + record.nHeightRequest = link.nHeight; + record.nExpireTimeRequest = link.nExpireTime; + record.txHashRequest = link.txHash; + record.RequestorWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link request for me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link request GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request GetLinkPrivateKey failed.\n", __func__); + return false; + } + } + else if (storage.nType == 2 && fIsLinkFromMe) // Link accept from me + { + //LogPrintf("%s -- Version 1 encrypted link accept from me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 privDHTKey; + CKeyID keyID(Hash160(storage.vchLinkPubKey.begin(), storage.vchLinkPubKey.end())); + if (pwalletMain->GetDHTKey(keyID, privDHTKey)) { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(privDHTKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkAccept link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RecipientFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link recipient %s\n", __func__, stringFromVch(link.RecipientFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fRequestFromMe = (fIsLinkFromMe && fIsLinkForMe); + record.fAcceptFromMe = fIsLinkFromMe; + record.nLinkState = 2; + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RecipientPubKey = link.RecipientPubKey; + record.SharedAcceptPubKey = link.SharedPubKey; + record.nHeightAccept = link.nHeight; + record.nExpireTimeAccept = link.nExpireTime; + record.txHashAccept = link.txHash; + record.RecipientWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- accept request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link accept from me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link accept GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept GetDHTKey failed.\n", __func__); + return false; + } + } + else if (storage.nType == 2 && !fIsLinkFromMe && fIsLinkForMe) // Link accept for me + { + //LogPrintf("%s -- Version 1 link accept for me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 sharedDHTKey; + std::array sharedSeed; + std::string strErrorMessage; + if (GetLinkPrivateKey(storage.vchLinkPubKey, storage.vchSharedPubKey, sharedSeed, strErrorMessage)) { + CKeyEd25519 sharedKey(sharedSeed); + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(sharedKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkAccept link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RecipientFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link recipient %s\n", __func__, stringFromVch(link.RecipientFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fAcceptFromMe = fIsLinkFromMe; + record.nLinkState = 2; + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RecipientPubKey = link.RecipientPubKey; + record.SharedAcceptPubKey = link.SharedPubKey; + record.nHeightAccept = link.nHeight; + record.nExpireTimeAccept = link.nExpireTime; + record.txHashAccept = link.txHash; + record.RecipientWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- accept request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link accept for me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link accept GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept GetLinkPrivateKey failed.\n", __func__); + return false; + } + } + else + { + linkQueue.push(storage); + } + } + return true; +} +#endif // ENABLE_WALLET diff --git a/src/bdap/wallet/utils.cpp b/src/bdap/wallet/utils.cpp new file mode 100644 index 000000000..3bb55e19e --- /dev/null +++ b/src/bdap/wallet/utils.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/utils.h" + +#include "base58.h" +#include "chainparams.h" +#include "coins.h" +#include "core_io.h" +#include "policy/policy.h" +#include "serialize.h" +#include "uint256.h" +#include "validation.h" +#include "wallet/wallet.h" +#include "utils.h" +#include "utiltime.h" +#include "script/script.h" + +#include + +#include +#include + +#include + +void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient) +{ + CRecipient recp = {scriptPubKey, recipient.nAmount, false}; + recipient = recp; + CTxOut txout(recipient.nAmount, scriptPubKey); + size_t nSize = GetSerializeSize(txout, SER_DISK, 0) + 148u; + recipient.nAmount = 3 * minRelayTxFee.GetFee(nSize); +} + +void CreateFeeRecipient(CScript& scriptPubKey, const std::vector& data, CRecipient& recipient) +{ + // add hash to data output (must match hash in inputs check with the tx scriptpubkey hash) + uint256 hash = Hash(data.begin(), data.end()); + std::vector vchHashRand = vchFromValue(hash.GetHex()); + scriptPubKey << vchHashRand; + CRecipient recp = {scriptPubKey, 0, false}; + recipient = recp; +} + +bool GetScriptOpTypeValue(const std::vector& vecSend, CScript& bdapOpScript, std::string& strOpType, std::vector& vchValue) +{ + LogPrint("bdap", "%s -- vecSend size = %u \n", __func__, vecSend.size()); + for (const CRecipient& rec : vecSend) { + CScript script = rec.scriptPubKey; + if (!script.IsUnspendable()) { + if (ExtractOpTypeValue(script, strOpType, vchValue)) { + bdapOpScript = script; + break; + } + } + } + if (strOpType.size() > 0) { + return true; + } + return false; +} diff --git a/src/bdap/wallet/vgp.cpp b/src/bdap/wallet/vgp.cpp new file mode 100644 index 000000000..64dc23454 --- /dev/null +++ b/src/bdap/wallet/vgp.cpp @@ -0,0 +1,172 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/vgpmessage.h" + +#include "arith_uint256.h" +#include "base58.h" +#include "bdap/linkmanager.h" +#include "bdap/utils.h" +#include "clientversion.h" +#include "dht/ed25519.h" +#include "hash.h" +#include "key.h" +#include "net.h" // for g_connman +#include "netmessagemaker.h" +#include "script/script.h" +#include "streams.h" +#include "timedata.h" +#include "util.h" +#include "wallet/wallet.h" + +#include "encryption.h" // for VGP DecryptBDAPData + +#include + +static std::map mapMyVGPMessages; +static CCriticalSection cs_mapMyVGPMessages; +static int nMyMessageCounter = 0; + +#ifdef ENABLE_WALLET +void AddMyMessage(const CVGPMessage& message) +{ + bool fFound = false; + CUnsignedVGPMessage unsignedMessage(message.vchMsg); + LogPrint("bdap", "%s -- Message hash = %s, Link MessageID = %s\n", __func__, message.GetHash().ToString(), unsignedMessage.MessageID.ToString()); + CVGPMessage storeMessage; + if (pwalletMain && pLinkManager && !pwalletMain->IsLocked() && unsignedMessage.fEncrypted) + { + if (DecryptMessage(unsignedMessage)) + fFound = true; + } + if (fFound) + { + CVGPMessage newMessage(unsignedMessage); + storeMessage = newMessage; + } + else + { + storeMessage = message; + } + LOCK(cs_mapMyVGPMessages); + mapMyVGPMessages[storeMessage.GetHash()] = storeMessage; + nMyMessageCounter++; + if ((nMyMessageCounter % 10) == 0) + CleanupMyMessageMap(); +} + +void GetMyLinkMessages(const uint256& subjectID, std::vector& vMessages) +{ + LOCK(cs_mapMyVGPMessages); + std::map::iterator itr = mapMyVGPMessages.begin(); + while (itr != mapMyVGPMessages.end()) + { + CVGPMessage message = (*itr).second; + CUnsignedVGPMessage unsignedMessage(message.vchMsg); + if (unsignedMessage.SubjectID == subjectID) + { + if (unsignedMessage.fEncrypted) + { + if (pwalletMain && !pwalletMain->IsLocked() && DecryptMessage(unsignedMessage)) + { + vMessages.push_back(unsignedMessage); + } + } + else + { + vMessages.push_back(unsignedMessage); + } + } + itr++; + } +} + +void GetMyLinkMessagesByType(const std::vector& vchType, const std::vector& vchRecipientFQDN, std::vector& vMessages, bool& fKeepLast) +{ + LOCK(cs_mapMyVGPMessages); + std::map::iterator itr = mapMyVGPMessages.begin(); + while (itr != mapMyVGPMessages.end()) + { + CVGPMessage messageWrapper = (*itr).second; + CUnsignedVGPMessage unsignedMessage(messageWrapper.vchMsg); + if (unsignedMessage.fEncrypted && pwalletMain && !pwalletMain->IsLocked()) + { + DecryptMessage(unsignedMessage); + } + if (!unsignedMessage.fEncrypted && (vchType.size() == 0 || vchType == unsignedMessage.Type()) && unsignedMessage.SenderFQDN() != vchRecipientFQDN) + { + if (unsignedMessage.KeepLast()) + fKeepLast = true; + + vMessages.push_back(unsignedMessage); + } + itr++; + } +} + +void GetMyLinkMessagesBySubjectAndSender(const uint256& subjectID, const std::vector& vchSenderFQDN, + const std::vector& vchType, std::vector& vchMessages, bool& fKeepLast) +{ + LOCK(cs_mapMyVGPMessages); + std::map::iterator itr = mapMyVGPMessages.begin(); + while (itr != mapMyVGPMessages.end()) + { + CVGPMessage messageWrapper = (*itr).second; + CUnsignedVGPMessage unsignedMessage(messageWrapper.vchMsg); + if (unsignedMessage.SubjectID == subjectID && unsignedMessage.SenderFQDN() == vchSenderFQDN && (vchType.size() == 0 || vchType == unsignedMessage.Type())) + { + if (unsignedMessage.KeepLast()) + fKeepLast = true; + + vchMessages.push_back(messageWrapper); + } + itr++; + } +} +#endif // ENABLE_WALLET + + +void CleanupMyMessageMap() +{ + // map with message type, message sender and timestamp. Used to keep last message from a sender/type pair. + std::map, std::vector>, int64_t> mapMessageTypeFromTimestamp; + int64_t nCurrentTimeStamp = GetAdjustedTime(); + std::map::iterator itr = mapMyVGPMessages.begin(); + while (itr != mapMyVGPMessages.end()) + { + CVGPMessage message = (*itr).second; + CUnsignedVGPMessage unsignedMessage(message.vchMsg); + if (!unsignedMessage.fEncrypted && nCurrentTimeStamp > unsignedMessage.nTimeStamp + KEEP_MY_MESSAGE_ALIVE_SECONDS) + { + CMessage message(unsignedMessage.vchMessageData); + std::pair, std::vector> pairTypeFrom = std::make_pair(message.vchMessageType, message.vchSenderFQDN); + if (!message.fKeepLast) { + itr = mapMyVGPMessages.erase(itr); + } + else { + std::map, std::vector>, int64_t>::iterator itTypeFrom = mapMessageTypeFromTimestamp.find(pairTypeFrom); + if (itTypeFrom != mapMessageTypeFromTimestamp.end()) { + if (itTypeFrom->second > unsignedMessage.nTimeStamp) { + itr = mapMyVGPMessages.erase(itr); + } + else { + mapMessageTypeFromTimestamp[pairTypeFrom] = unsignedMessage.nTimeStamp; + ++itr; + } + } + else { + mapMessageTypeFromTimestamp[pairTypeFrom] = unsignedMessage.nTimeStamp; + ++itr; + } + } + } + else + { + ++itr; + } + } + LogPrintf("%s -- Size %d\n", __func__, mapMyVGPMessages.size()); +} diff --git a/src/bdap/wallet/wallet.cpp b/src/bdap/wallet/wallet.cpp new file mode 100644 index 000000000..997c1a9a4 --- /dev/null +++ b/src/bdap/wallet/wallet.cpp @@ -0,0 +1,481 @@ +// Copyright (c) 2016-2019 Duality Blockchain Solutions +// Copyright (c) 2009-2019 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/wallet/wallet.h" + +#include "protocol.h" +#include "serialize.h" +#include "util.h" +#include "utiltime.h" +#include "validation.h" // For CheckTransaction +#include "wallet/db.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" + +#include "dht/ed25519.h" +#include "bdap/bdap.h" +#include "bdap/utils.h" +#include "bdap/linkstorage.h" + +#include +#include +#include + +extern std::atomic nWalletDBUpdateCounter; +/* extern */ unsigned int nWalletDBUpdated; + +bool CWallet::NewEdKeyPool() +{ + { + LOCK(cs_wallet); + CWalletDB walletdb(strWalletFile); + BOOST_FOREACH (int64_t nIndex, setInternalEdKeyPool) { + walletdb.EraseEdPool(nIndex); + } + setInternalEdKeyPool.clear(); + BOOST_FOREACH (int64_t nIndex, setExternalEdKeyPool) { + walletdb.EraseEdPool(nIndex); + } + setExternalEdKeyPool.clear(); + + if (!TopUpKeyPoolCombo()) //was topupedkeypool + return false; + + LogPrintf("CWallet::NewEdKeyPool rewrote edkeypool\n"); + } + return true; +} + +bool CWallet::SyncEdKeyPool() +{ + if (pwalletMain->IsLocked()) + return false; + + CWalletDB walletdb(strWalletFile); + + CKeyPool keypool; + CPubKey retrievedPubKey; + CKey retrievedKey; + + CKeyPool keypool2; + CPubKey retrievedPubKey2; + CKey retrievedKey2; + + for (int64_t nIndex : setInternalKeyPool) { + if (!walletdb.ReadPool(nIndex, keypool)) { + throw std::runtime_error(std::string(__func__) + ": read failed"); + } + retrievedPubKey = keypool.vchPubKey; + GetKey(retrievedPubKey.GetID(), retrievedKey); + + std::array edSeed = ConvertSecureVector32ToArray(retrievedKey.getKeyData()); + CKeyEd25519 childKey(edSeed); + CharString vchDHTPubKey = childKey.GetPubKey(); + + CKeyID vchDHTPubKeyID = GetIdFromCharVector(vchDHTPubKey); + + //only add if doesn't currently exist + if (!pwalletMain->HaveDHTKey(vchDHTPubKeyID)) { + if (!walletdb.WriteEdPool(nIndex, CEdKeyPool(GenerateNewEdKey(0, true, retrievedKey), true))) + throw std::runtime_error("SyncEdKeyPool(): writing generated key failed"); + else { + setInternalEdKeyPool.insert(nIndex); + } + } + } + + for (int64_t nIndex : setExternalKeyPool) { + if (!walletdb.ReadPool(nIndex, keypool2)) { + throw std::runtime_error(std::string(__func__) + ": read failed"); + } + retrievedPubKey2 = keypool2.vchPubKey; + GetKey(retrievedPubKey2.GetID(), retrievedKey2); + + std::array edSeed2 = ConvertSecureVector32ToArray(retrievedKey2.getKeyData()); + CKeyEd25519 childKey2(edSeed2); + CharString vchDHTPubKey2 = childKey2.GetPubKey(); + + CKeyID vchDHTPubKeyID2 = GetIdFromCharVector(vchDHTPubKey2); + + // only add if doesn't currently exist + if (!pwalletMain->HaveDHTKey(vchDHTPubKeyID2)) { + if (!walletdb.WriteEdPool(nIndex, CEdKeyPool(GenerateNewEdKey(0, false, retrievedKey2), false))) + throw std::runtime_error("SyncEdKeyPool(): writing generated key failed"); + else { + setExternalEdKeyPool.insert(nIndex); + } + } + } + + return true; +} + + + +bool CWallet::TopUpKeyPoolCombo(unsigned int kpSize, bool fIncreaseSize) +{ + { + LOCK(cs_wallet); + + if (IsLocked(true)) + return false; + + int64_t amountExternal = setExternalKeyPool.size(); + int64_t amountInternal = setInternalKeyPool.size(); + + // Top up key pool + unsigned int nTargetSize; + unsigned int defaultKeyPoolSize = std::max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0); + if (kpSize > 0) + nTargetSize = kpSize; + else { + if (defaultKeyPoolSize >= DynamicKeyPoolSize) { + DynamicKeyPoolSize = defaultKeyPoolSize; + } + + if (fIncreaseSize) { + DynamicKeyPoolSize = DynamicKeyPoolSize + 2; + } //if fIncreaseSize + + nTargetSize = DynamicKeyPoolSize; + } + + // count amount of available keys (internal, external) + // make sure the keypool of external and internal keys fits the user selected target (-keypool) + + int64_t missingExternal = std::max(std::max((int64_t)nTargetSize, (int64_t)1) - amountExternal, (int64_t)0); + int64_t missingInternal = std::max(std::max((int64_t)nTargetSize, (int64_t)1) - amountInternal, (int64_t)0); + + if (!IsHDEnabled()) { + // don't create extra internal keys + missingInternal = 0; + } else { + nTargetSize *= 2; + } + bool fInternal = false; + CWalletDB walletdb(strWalletFile); + for (int64_t i = missingInternal + missingExternal; i--;) { + int64_t nEnd = 1; + //int64_t nEdEnd = 1; + if (i < missingInternal) { + fInternal = true; + } + if (!setInternalKeyPool.empty()) { + nEnd = *(--setInternalKeyPool.end()) + 1; + } + if (!setExternalKeyPool.empty()) { + nEnd = std::max(nEnd, *(--setExternalKeyPool.end()) + 1); + } + // TODO: implement keypools for all accounts? + + //get seed for ed29915 keys + CPubKey retrievedPubKey; + CKey retrievedKey; + + retrievedPubKey = GenerateNewKey(0, fInternal); + GetKey(retrievedPubKey.GetID(), retrievedKey); + + if (!walletdb.WritePool(nEnd, CKeyPool(retrievedPubKey, fInternal))) + throw std::runtime_error("TopUpKeyPoolCombo(): writing generated key failed"); + + if (fInternal) { + setInternalKeyPool.insert(nEnd); + } else { + setExternalKeyPool.insert(nEnd); + } + + // TODO: implement keypools for all accounts? + if (!walletdb.WriteEdPool(nEnd, CEdKeyPool(GenerateNewEdKey(0, fInternal, retrievedKey), fInternal))) + throw std::runtime_error("TopUpKeyPoolCombo(): writing generated key failed"); + + if (fInternal) { + setInternalEdKeyPool.insert(nEnd); + } else { + setExternalEdKeyPool.insert(nEnd); + } + + double dProgress = 100.f * nEnd / (nTargetSize + 1); + std::string strMsg = ""; + if (dProgress <= 100) + strMsg = strprintf(_("Loading wallet... (%3.2f %%)"), dProgress); + else + strMsg = strprintf(_("Increasing keypool... (%d)"),amountExternal); + uiInterface.InitMessage(strMsg); + } + } + return true; +} + +void CWallet::ReserveEdKeyForTransactions(const std::vector& pubKeyToReserve) +{ + CWalletDB walletdb(strWalletFile); + CEdKeyPool edkeypool; + std::vector edPubKey; + std::vector keypoolIndexes; + bool EraseIndex = false; + int64_t IndexToErase = 0; + int64_t nIndex = 0; + std::set::iterator it = setInternalEdKeyPool.begin(); + + while ((it != setInternalEdKeyPool.end()) && (!EraseIndex)) { + nIndex = *it; + if (!walletdb.ReadEdPool(nIndex, edkeypool)) { + throw std::runtime_error(std::string(__func__) + ": read failed"); + } + edPubKey = edkeypool.edPubKey; + + if(pubKeyToReserve == edPubKey) { + KeepKey(nIndex); + fNeedToUpdateKeyPools = true; + EraseIndex = true; + IndexToErase = nIndex; + ReserveKeyCount++; + } + it++; + } + + if (EraseIndex) { + std::set::iterator eraseIndexEd = setInternalEdKeyPool.find(IndexToErase); + std::set::iterator eraseIndex = setInternalKeyPool.find(IndexToErase); + if (eraseIndexEd != setInternalEdKeyPool.end()) + setInternalEdKeyPool.erase(eraseIndexEd); + if (eraseIndex != setInternalKeyPool.end()) + setInternalKeyPool.erase(eraseIndex); + } +} + +size_t CWallet::EdKeypoolCountExternalKeys() +{ + AssertLockHeld(cs_wallet); // setExternalEdKeyPool + return setExternalEdKeyPool.size(); +} + +size_t CWallet::EdKeypoolCountInternalKeys() +{ + AssertLockHeld(cs_wallet); // setInternalEdKeyPool + return setInternalEdKeyPool.size(); +} + +std::array CWallet::ConvertSecureVector32ToArray(const std::vector >& vIn) +{ + std::array arrReturn; + for(unsigned int i = 0; i < 32; i++) { + arrReturn[i] = (char)vIn[i]; + } + return arrReturn; +} + + +std::vector CWallet::GenerateNewEdKey(uint32_t nAccountIndex, bool fInternal, const CKey& seedIn) +{ + bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets + CKey secretRet; + secretRet.MakeNewKey(fCompressed); + + // Create new metadata + int64_t nCreationTime = GetTime(); + CKeyMetadata metadata(nCreationTime); + + CKeyEd25519 secretEdRet; + + if (!seedIn.IsValid()){ + DeriveEd25519ChildKey(secretRet,secretEdRet); + } else { + DeriveEd25519ChildKey(seedIn,secretEdRet); + }; + + mapKeyMetadata[secretEdRet.GetID()] = metadata; + UpdateTimeFirstKey(nCreationTime); + + return secretEdRet.GetPubKey(); +} + +void CWallet::DeriveEd25519ChildKey(const CKey& seed, CKeyEd25519& secretEdRet) +{ + std::array edSeed = ConvertSecureVector32ToArray(seed.getKeyData()); + CKeyEd25519 childKey(edSeed); + AddDHTKey(childKey, childKey.GetPubKey()); //TODO + secretEdRet = childKey; + +} + +bool CWallet::AddDHTKey(const CKeyEd25519& key, const std::vector& pubkey) +{ + AssertLockHeld(cs_wallet); // mapKeyMetadata + if (!CCryptoKeyStore::AddDHTKey(key, pubkey)) { + return false; + } + + if (!fFileBacked) + return true; + + if (!IsCrypted()) { + CKeyID keyID(Hash160(pubkey.begin(), pubkey.end())); + return CWalletDB(strWalletFile).WriteDHTKey(key, pubkey, mapKeyMetadata[keyID]); + } + LogPrint("dht", "CWallet::AddDHTKey \npubkey = %s, \nprivkey = %s, \nprivseed = %s\n", + key.GetPubKeyString(), key.GetPrivKeyString(), key.GetPrivSeedString()); + return true; +} + +bool CWallet::AddCryptedDHTKey(const std::vector& vchPubKey, const std::vector& vchCryptedSecret) +{ + if (!CCryptoKeyStore::AddCryptedDHTKey(vchPubKey, vchCryptedSecret)) { + LogPrint("dht", "CWallet::AddCryptedDHTKey AddCryptedDHTKey failed.\n"); + return false; + } + if (!fFileBacked) + return true; + { + LOCK(cs_wallet); + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); + if (pwalletdbEncryption) { + return pwalletdbEncryption->WriteCryptedDHTKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[keyID]); + } + else { + return CWalletDB(strWalletFile).WriteCryptedDHTKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[keyID]); + } + } + return false; +} + +bool CWallet::GetDHTKey(const CKeyID& address, CKeyEd25519& keyOut) const +{ + LOCK(cs_wallet); + return CCryptoKeyStore::GetDHTKey(address, keyOut); +} + +bool CWallet::HaveDHTKey(const CKeyID &address) const +{ + LOCK(cs_wallet); + if (mapHdPubKeys.count(address) > 0) + return true; + return CCryptoKeyStore::HaveDHTKey(address); +} + +bool CWallet::GetDHTPubKeys(std::vector>& vvchDHTPubKeys) const +{ + if (IsCrypted()) + return CCryptoKeyStore::GetDHTPubKeys(vvchDHTPubKeys); + + return CBasicKeyStore::GetDHTPubKeys(vvchDHTPubKeys); +} + +bool CWallet::LoadCryptedDHTKey(const std::vector& vchPubKey, const std::vector& vchCryptedSecret) +{ + return CCryptoKeyStore::AddCryptedDHTKey(vchPubKey, vchCryptedSecret); +} + +bool CWallet::WriteLinkMessageInfo(const uint256& subjectID, const std::vector& vchPubKey) +{ + CWalletDB walletdb(strWalletFile); + return walletdb.WriteLinkMessageInfo(subjectID, vchPubKey); +} + +bool CWallet::EraseLinkMessageInfo(const uint256& subjectID) +{ + CWalletDB walletdb(strWalletFile); + return walletdb.EraseLinkMessageInfo(subjectID); +} + +bool CWalletDB::ReadEdPool(int64_t nPool, CEdKeyPool& edkeypool) +{ + return Read(std::make_pair(std::string("edpool"), nPool), edkeypool); +} + +bool CWalletDB::WriteEdPool(int64_t nPool, const CEdKeyPool& edkeypool) +{ + nWalletDBUpdateCounter++; + return Write(std::make_pair(std::string("edpool"), nPool), edkeypool); +} + +bool CWalletDB::EraseEdPool(int64_t nPool) +{ + nWalletDBUpdateCounter++; + return Erase(std::make_pair(std::string("edpool"), nPool)); +} + +bool CWalletDB::WriteDHTKey(const CKeyEd25519& key, const std::vector& vchPubKey, const CKeyMetadata& keyMeta) +{ + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); + if (!Write(std::make_pair(std::string("dhtkeymeta"), keyID), keyMeta, false)) + return false; + + nWalletDBUpdated++; + std::vector vchPrivKeySeed = key.GetPrivSeed(); + // hash pubkey/privkey to accelerate wallet load + std::vector vchKey; + vchKey.reserve(vchPubKey.size() + vchPrivKeySeed.size()); + vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); + vchKey.insert(vchKey.end(), vchPrivKeySeed.begin(), vchPrivKeySeed.end()); + + LogPrint("dht", "CWalletDB::WriteDHTKey \nvchKey = %s, \nkeyID = %s, \npubkey = %s, \nprivkey = %s, \nprivseed = %s\n", + stringFromVch(vchKey), keyID.ToString(), + key.GetPubKeyString(), key.GetPrivKeyString(), key.GetPrivSeedString()); + + return Write(std::make_pair(std::string("dhtkey"), vchPubKey), std::make_pair(vchPrivKeySeed, Hash(vchKey.begin(), vchKey.end())), false); +} + +bool CWalletDB::WriteCryptedDHTKey(const std::vector& vchPubKey, + const std::vector& vchCryptedSecret, + const CKeyMetadata& keyMeta) +{ + const bool fEraseUnencryptedKey = true; + nWalletDBUpdateCounter++; + + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); + if (!Write(std::make_pair(std::string("keymeta"), keyID), keyMeta)) { + LogPrint("dht", "CWalletDB::WriteCryptedDHTKey Write keymeta failed.\n"); + return false; + } + + // hash pubkey/privkey to accelerate wallet load + std::vector vchKey; + vchKey.reserve(vchPubKey.size() + vchCryptedSecret.size()); + vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); + vchKey.insert(vchKey.end(), vchCryptedSecret.begin(), vchCryptedSecret.end()); + + if (!Write(std::make_pair(std::string("cdhtkey"), vchPubKey), vchCryptedSecret, false)) { + LogPrint("dht", "CWalletDB::WriteCryptedDHTKey Write cdhtkey failed.\n"); + return false; + } + + if (fEraseUnencryptedKey) { + Erase(std::make_pair(std::string("dhtkey"), vchPubKey)); + } + return true; +} + +// Stores the raw link in the wallet database +bool CWalletDB::WriteLink(const CLinkStorage& link) +{ + ProcessLink(link); + std::vector vchPubKeys = link.vchLinkPubKey; + vchPubKeys.insert(vchPubKeys.end(), link.vchSharedPubKey.begin(), link.vchSharedPubKey.end()); + uint256 linkID = Hash(vchPubKeys.begin(), vchPubKeys.end()); + LogPrint("bdap", "%s -- linkID = %s\n", __func__, linkID.ToString()); + return Write(std::make_pair(std::string("link"), linkID), link); +} + +bool CWalletDB::EraseLink(const std::vector& vchPubKey, const std::vector& vchSharedKey) +{ + std::vector vchPubKeys = vchPubKey; + vchPubKeys.insert(vchPubKeys.end(), vchSharedKey.begin(), vchSharedKey.end()); + uint256 linkID = Hash(vchPubKeys.begin(), vchPubKeys.end()); + LogPrint("bdap", "%s -- linkID = %s\n", __func__, linkID.ToString()); + return Erase(std::make_pair(std::string("link"), linkID)); +} + +bool CWalletDB::WriteLinkMessageInfo(const uint256& subjectID, const std::vector& vchPubKey) +{ + LogPrint("bdap", "%s -- subjectID = %s\n", __func__, subjectID.ToString()); + return Write(std::make_pair(std::string("linkid"), subjectID), vchPubKey); +} + +bool CWalletDB::EraseLinkMessageInfo(const uint256& subjectID) +{ + LogPrint("bdap", "%s -- subjectID = %s\n", __func__, subjectID.ToString()); + return Erase(std::make_pair(std::string("linkid"), subjectID)); +} diff --git a/src/bdap/wallet/wallet.h b/src/bdap/wallet/wallet.h new file mode 100644 index 000000000..e4c4ac2e5 --- /dev/null +++ b/src/bdap/wallet/wallet.h @@ -0,0 +1,48 @@ +// Copyright (c) 2016-2019 Duality Blockchain Solutions +// Copyright (c) 2009-2019 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_BDAP_WALLET_H +#define BITCOIN_BDAP_WALLET_H + +#include "serialize.h" + +#include + +/** An Ed key pool entry */ +class CEdKeyPool +{ +public: + int64_t nTime; + std::vector edPubKey; + bool fInternal; // for change outputs + + CEdKeyPool(); + CEdKeyPool(const std::vector& edPubKeyIn, bool fInternalIn); + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(nTime); + READWRITE(edPubKey); + if (ser_action.ForRead()) { + try { + READWRITE(fInternal); + } catch (std::ios_base::failure&) { + /* flag as external address if we can't read the internal boolean + (this will be the case for any wallet before the HD chain split version) */ + fInternal = false; + } + } else { + READWRITE(fInternal); + } + } +}; + +#endif // BITCOIN_BDAP_WALLET_H \ No newline at end of file diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 6689b71d1..35d655c5c 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -128,7 +128,7 @@ bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingM } -static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial& vchPlaintext, const uint256& nIV, std::vector& vchCiphertext) +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial& vchPlaintext, const uint256& nIV, std::vector& vchCiphertext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_IV_SIZE);