Changeset View
Changeset View
Standalone View
Standalone View
src/script/signingprovider.cpp
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | FlatSigningProvider Merge(const FlatSigningProvider &a, | ||||
ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end()); | ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end()); | ||||
ret.keys = a.keys; | ret.keys = a.keys; | ||||
ret.keys.insert(b.keys.begin(), b.keys.end()); | ret.keys.insert(b.keys.begin(), b.keys.end()); | ||||
ret.origins = a.origins; | ret.origins = a.origins; | ||||
ret.origins.insert(b.origins.begin(), b.origins.end()); | ret.origins.insert(b.origins.begin(), b.origins.end()); | ||||
return ret; | return ret; | ||||
} | } | ||||
void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts( | |||||
const CPubKey &pubkey) { | |||||
AssertLockHeld(cs_KeyStore); | |||||
CKeyID key_id = pubkey.GetID(); | |||||
// We must actually know about this key already. | |||||
assert(HaveKey(key_id) || mapWatchKeys.count(key_id)); | |||||
// This adds the redeemscripts necessary to detect alternative outputs using | |||||
// the same keys. Also note that having superfluous scripts in the keystore | |||||
// never hurts. They're only used to guide recursion in signing and IsMine | |||||
// logic - if a script is present but we can't do anything with it, it has | |||||
// no effect. "Implicitly" refers to fact that scripts are derived | |||||
// automatically from existing keys, and are present in memory, even without | |||||
// being explicitly loaded (e.g. from a file). | |||||
// Right now there are none so do nothing. | |||||
} | |||||
bool FillableSigningProvider::GetPubKey(const CKeyID &address, | bool FillableSigningProvider::GetPubKey(const CKeyID &address, | ||||
CPubKey &vchPubKeyOut) const { | CPubKey &vchPubKeyOut) const { | ||||
CKey key; | CKey key; | ||||
if (!GetKey(address, key)) { | if (!GetKey(address, key)) { | ||||
LOCK(cs_KeyStore); | |||||
WatchKeyMap::const_iterator it = mapWatchKeys.find(address); | |||||
if (it != mapWatchKeys.end()) { | |||||
vchPubKeyOut = it->second; | |||||
return true; | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
vchPubKeyOut = key.GetPubKey(); | vchPubKeyOut = key.GetPubKey(); | ||||
return true; | return true; | ||||
} | } | ||||
bool FillableSigningProvider::AddKeyPubKey(const CKey &key, | bool FillableSigningProvider::AddKeyPubKey(const CKey &key, | ||||
const CPubKey &pubkey) { | const CPubKey &pubkey) { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
mapKeys[pubkey.GetID()] = key; | mapKeys[pubkey.GetID()] = key; | ||||
ImplicitlyLearnRelatedKeyScripts(pubkey); | |||||
return true; | return true; | ||||
} | } | ||||
bool FillableSigningProvider::HaveKey(const CKeyID &address) const { | bool FillableSigningProvider::HaveKey(const CKeyID &address) const { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
return mapKeys.count(address) > 0; | return mapKeys.count(address) > 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | bool FillableSigningProvider::GetCScript(const CScriptID &hash, | ||||
ScriptMap::const_iterator mi = mapScripts.find(hash); | ScriptMap::const_iterator mi = mapScripts.find(hash); | ||||
if (mi != mapScripts.end()) { | if (mi != mapScripts.end()) { | ||||
redeemScriptOut = (*mi).second; | redeemScriptOut = (*mi).second; | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
static bool ExtractPubKey(const CScript &dest, CPubKey &pubKeyOut) { | |||||
// TODO: Use Solver to extract this? | |||||
CScript::const_iterator pc = dest.begin(); | |||||
opcodetype opcode; | |||||
std::vector<uint8_t> vch; | |||||
if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch)) { | |||||
return false; | |||||
} | |||||
pubKeyOut = CPubKey(vch); | |||||
if (!pubKeyOut.IsFullyValid()) { | |||||
return false; | |||||
} | |||||
if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || | |||||
dest.GetOp(pc, opcode, vch)) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool FillableSigningProvider::AddWatchOnly(const CScript &dest) { | |||||
LOCK(cs_KeyStore); | |||||
setWatchOnly.insert(dest); | |||||
CPubKey pubKey; | |||||
if (ExtractPubKey(dest, pubKey)) { | |||||
mapWatchKeys[pubKey.GetID()] = pubKey; | |||||
ImplicitlyLearnRelatedKeyScripts(pubKey); | |||||
} | |||||
return true; | |||||
} | |||||
bool FillableSigningProvider::RemoveWatchOnly(const CScript &dest) { | |||||
LOCK(cs_KeyStore); | |||||
setWatchOnly.erase(dest); | |||||
CPubKey pubKey; | |||||
if (ExtractPubKey(dest, pubKey)) { | |||||
mapWatchKeys.erase(pubKey.GetID()); | |||||
} | |||||
// Related CScripts are not removed; having superfluous scripts around is | |||||
// harmless (see comment in ImplicitlyLearnRelatedKeyScripts). | |||||
return true; | |||||
} | |||||
bool FillableSigningProvider::HaveWatchOnly(const CScript &dest) const { | |||||
LOCK(cs_KeyStore); | |||||
return setWatchOnly.count(dest) > 0; | |||||
} | |||||
bool FillableSigningProvider::HaveWatchOnly() const { | |||||
LOCK(cs_KeyStore); | |||||
return (!setWatchOnly.empty()); | |||||
} | |||||
CKeyID GetKeyForDestination(const SigningProvider &store, | CKeyID GetKeyForDestination(const SigningProvider &store, | ||||
const CTxDestination &dest) { | const CTxDestination &dest) { | ||||
// Only supports destinations which map to single public keys, i.e. P2PKH. | // Only supports destinations which map to single public keys, i.e. P2PKH. | ||||
if (auto id = boost::get<PKHash>(&dest)) { | if (auto id = boost::get<PKHash>(&dest)) { | ||||
return CKeyID(*id); | return CKeyID(*id); | ||||
} | } | ||||
return CKeyID(); | return CKeyID(); | ||||
} | } |