1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or https://www.opensource.org/licenses/mit-license.php .
10 #include "pbaas/identity.h"
11 #include "cc/CCinclude.h"
12 #include "boost/algorithm/string.hpp"
14 #include <boost/foreach.hpp>
16 bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
19 if (!GetKey(address, key))
21 vchPubKeyOut = key.GetPubKey();
25 bool CKeyStore::AddKey(const CKey &key) {
26 return AddKeyPubKey(key, key.GetPubKey());
29 bool CBasicKeyStore::SetHDSeed(const HDSeed& seed)
31 LOCK(cs_SpendingKeyStore);
32 if (!hdSeed.IsNull()) {
33 // Don't allow an existing seed to be changed. We can maybe relax this
34 // restriction later once we have worked out the UX implications.
41 bool CBasicKeyStore::HaveHDSeed() const
43 LOCK(cs_SpendingKeyStore);
44 return !hdSeed.IsNull();
47 bool CBasicKeyStore::GetHDSeed(HDSeed& seedOut) const
49 LOCK(cs_SpendingKeyStore);
50 if (hdSeed.IsNull()) {
58 CScriptID ScriptOrIdentityID(const CScript& scr)
62 if (scr.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode == EVAL_IDENTITY_PRIMARY && p.vData.size() && (identity = CIdentity(p.vData[0])).IsValid())
64 return CScriptID(identity.GetID());
68 return CScriptID(scr);
72 bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
75 mapKeys[pubkey.GetID()] = key;
79 bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
81 if (redeemScript.size() > CScript::MAX_SCRIPT_ELEMENT_SIZE)
82 return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid", CScript::MAX_SCRIPT_ELEMENT_SIZE);
85 mapScripts[ScriptOrIdentityID(redeemScript)] = redeemScript;
89 bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
92 return mapScripts.count(hash) > 0;
95 bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
98 ScriptMap::const_iterator mi = mapScripts.find(hash);
99 if (mi != mapScripts.end())
101 redeemScriptOut = (*mi).second;
107 bool CBasicKeyStore::HaveIdentity(const CIdentityID &idID) const
109 return mapIdentities.count(CIdentityMapKey(idID).MapKey()) != 0;
112 bool CBasicKeyStore::AddIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
114 if (mapIdentities.count(mapKey.MapKey()) || !mapKey.IsValid())
118 mapIdentities.insert(make_pair(mapKey.MapKey(), identity));
122 bool CBasicKeyStore::UpdateIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
124 if (!mapIdentities.count(mapKey.MapKey()) || !mapKey.IsValid())
128 // erase and insert to replace
129 mapIdentities.erase(mapKey.MapKey());
130 mapIdentities.insert(make_pair(mapKey.MapKey(), identity));
134 bool CBasicKeyStore::AddUpdateIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
136 arith_uint256 arithKey = mapKey.MapKey();
137 return CBasicKeyStore::AddIdentity(mapKey, identity) || CBasicKeyStore::UpdateIdentity(mapKey, identity);
140 bool CBasicKeyStore::RemoveIdentity(const CIdentityMapKey &mapKey, const uint256 &txid)
142 auto localKey = mapKey;
143 if (localKey.idID.IsNull())
147 auto startIt = mapIdentities.lower_bound(localKey.MapKey());
148 if (localKey.blockHeight == 0)
150 localKey.blockHeight = 0x7fffffff;
153 if (startIt != mapIdentities.end())
157 mapIdentities.erase(startIt, mapIdentities.upper_bound(localKey.MapKey()));
161 auto endIt = mapIdentities.upper_bound(localKey.MapKey());
162 for (; startIt != endIt; startIt++)
164 if (startIt->second.txid == txid)
166 mapIdentities.erase(startIt);
177 // return an identity if it is in the store
178 bool CBasicKeyStore::GetIdentity(const CIdentityID &idID, std::pair<CIdentityMapKey, CIdentityMapValue> &keyAndIdentity, uint32_t lteHeight) const
180 // debug test - comment normally
181 // printf("lower_bound: %s\n", CIdentityMapKey(idID).ToString().c_str());
182 // printf("upper_bound: %s\n", CIdentityMapKey(idID, lteHeight >= INT32_MAX ? INT32_MAX : lteHeight + 1).ToString().c_str());
183 // printf("first: %s\n", mapIdentities.size() ? CIdentityMapKey(mapIdentities.begin()->first).ToString().c_str() : "");
186 auto itStart = mapIdentities.lower_bound(CIdentityMapKey(idID).MapKey());
187 if (itStart == mapIdentities.end())
192 auto itEnd = mapIdentities.upper_bound(CIdentityMapKey(idID, lteHeight >= INT32_MAX ? INT32_MAX : lteHeight + 1).MapKey());
193 if (itEnd == mapIdentities.begin())
199 CIdentityMapKey foundKey(itEnd->first);
200 if (foundKey.idID != idID)
204 keyAndIdentity = make_pair(foundKey, itEnd->second);
208 // return all identities between two map keys, inclusive
209 bool CBasicKeyStore::GetIdentity(const CIdentityMapKey &keyStart, const CIdentityMapKey &keyEnd, std::vector<std::pair<CIdentityMapKey, CIdentityMapValue>> &keysAndIdentityUpdates) const
211 auto itStart = mapIdentities.lower_bound(keyStart.MapKey());
212 if (itStart == mapIdentities.end())
216 auto itEnd = mapIdentities.upper_bound(keyEnd.MapKey());
217 for (; itStart != mapIdentities.end() && itStart != itEnd; itStart++)
219 keysAndIdentityUpdates.push_back(make_pair(CIdentityMapKey(itStart->first), itStart->second));
224 bool CBasicKeyStore::GetIdentity(const CIdentityMapKey &mapKey, const uint256 &txid, std::pair<CIdentityMapKey, CIdentityMapValue> &keyAndIdentity)
226 CIdentityMapKey localKey = mapKey;
227 std::vector<std::pair<CIdentityMapKey, CIdentityMapValue>> toCheck;
230 if (localKey.blockHeight == 0)
232 localKey.blockHeight = 0x7fffffff;
234 if (!GetIdentity(mapKey, localKey, toCheck))
239 for (auto id : toCheck)
241 if (id.second.txid == txid)
250 // return the first identity not less than a specific key
251 bool CBasicKeyStore::GetFirstIdentity(const CIdentityID &idID, std::pair<CIdentityMapKey, CIdentityMapValue> &keyAndIdentity, uint32_t gteHeight) const
253 auto it = mapIdentities.lower_bound(CIdentityMapKey(idID, gteHeight).MapKey());
254 if (it == mapIdentities.end())
258 keyAndIdentity = make_pair(CIdentityMapKey(it->first), it->second);
262 bool CBasicKeyStore::GetIdentities(std::vector<std::pair<CIdentityMapKey, CIdentityMapValue *>> &mine,
263 std::vector<std::pair<CIdentityMapKey, CIdentityMapValue *>> &imsigner,
264 std::vector<std::pair<CIdentityMapKey, CIdentityMapValue *>> ¬mine)
266 for (auto &identity : mapIdentities)
268 CIdentityMapKey idKey(identity.first);
269 if (idKey.flags & idKey.CAN_SPEND)
271 mine.push_back(make_pair(idKey, &identity.second));
273 else if (idKey.flags & idKey.CAN_SIGN)
275 imsigner.push_back(make_pair(idKey, &identity.second));
279 notmine.push_back(make_pair(idKey, &identity.second));
282 return (mine.size() || imsigner.size() || notmine.size());
285 bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
288 setWatchOnly.insert(dest);
292 bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
295 setWatchOnly.erase(dest);
299 bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
302 return setWatchOnly.count(dest) > 0;
305 bool CBasicKeyStore::HaveWatchOnly() const
308 return (!setWatchOnly.empty());
311 bool CBasicKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk)
313 LOCK(cs_SpendingKeyStore);
314 auto address = sk.address();
315 mapSproutSpendingKeys[address] = sk;
316 mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key())));
321 bool CBasicKeyStore::AddSaplingSpendingKey(
322 const libzcash::SaplingExtendedSpendingKey &sk,
323 const libzcash::SaplingPaymentAddress &defaultAddr)
325 LOCK(cs_SpendingKeyStore);
326 auto fvk = sk.expsk.full_viewing_key();
328 // if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
329 if (!AddSaplingFullViewingKey(fvk, defaultAddr)) {
333 mapSaplingSpendingKeys[fvk] = sk;
338 bool CBasicKeyStore::AddSproutViewingKey(const libzcash::SproutViewingKey &vk)
340 LOCK(cs_SpendingKeyStore);
341 auto address = vk.address();
342 mapSproutViewingKeys[address] = vk;
343 mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk.sk_enc)));
347 bool CBasicKeyStore::AddSaplingFullViewingKey(
348 const libzcash::SaplingFullViewingKey &fvk,
349 const libzcash::SaplingPaymentAddress &defaultAddr)
351 LOCK(cs_SpendingKeyStore);
352 auto ivk = fvk.in_viewing_key();
353 mapSaplingFullViewingKeys[ivk] = fvk;
355 return CBasicKeyStore::AddSaplingIncomingViewingKey(ivk, defaultAddr);
358 // This function updates the wallet's internal address->ivk map.
359 // If we add an address that is already in the map, the map will
360 // remain unchanged as each address only has one ivk.
361 bool CBasicKeyStore::AddSaplingIncomingViewingKey(
362 const libzcash::SaplingIncomingViewingKey &ivk,
363 const libzcash::SaplingPaymentAddress &addr)
365 LOCK(cs_SpendingKeyStore);
367 // Add addr -> SaplingIncomingViewing to SaplingIncomingViewingKeyMap
368 mapSaplingIncomingViewingKeys[addr] = ivk;
373 bool CBasicKeyStore::RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk)
375 LOCK(cs_SpendingKeyStore);
376 mapSproutViewingKeys.erase(vk.address());
380 bool CBasicKeyStore::HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const
382 LOCK(cs_SpendingKeyStore);
383 return mapSproutViewingKeys.count(address) > 0;
386 bool CBasicKeyStore::HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const
388 LOCK(cs_SpendingKeyStore);
389 return mapSaplingFullViewingKeys.count(ivk) > 0;
392 bool CBasicKeyStore::HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const
394 LOCK(cs_SpendingKeyStore);
395 return mapSaplingIncomingViewingKeys.count(addr) > 0;
398 bool CBasicKeyStore::GetSproutViewingKey(
399 const libzcash::SproutPaymentAddress &address,
400 libzcash::SproutViewingKey &vkOut) const
402 LOCK(cs_SpendingKeyStore);
403 SproutViewingKeyMap::const_iterator mi = mapSproutViewingKeys.find(address);
404 if (mi != mapSproutViewingKeys.end()) {
411 bool CBasicKeyStore::GetSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk,
412 libzcash::SaplingFullViewingKey &fvkOut) const
414 LOCK(cs_SpendingKeyStore);
415 SaplingFullViewingKeyMap::const_iterator mi = mapSaplingFullViewingKeys.find(ivk);
416 if (mi != mapSaplingFullViewingKeys.end()) {
423 bool CBasicKeyStore::GetSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr,
424 libzcash::SaplingIncomingViewingKey &ivkOut) const
426 LOCK(cs_SpendingKeyStore);
427 SaplingIncomingViewingKeyMap::const_iterator mi = mapSaplingIncomingViewingKeys.find(addr);
428 if (mi != mapSaplingIncomingViewingKeys.end()) {
435 bool CBasicKeyStore::GetSaplingExtendedSpendingKey(const libzcash::SaplingPaymentAddress &addr,
436 libzcash::SaplingExtendedSpendingKey &extskOut) const {
437 libzcash::SaplingIncomingViewingKey ivk;
438 libzcash::SaplingFullViewingKey fvk;
440 return GetSaplingIncomingViewingKey(addr, ivk) &&
441 GetSaplingFullViewingKey(ivk, fvk) &&
442 GetSaplingSpendingKey(fvk, extskOut);