diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 92d659569..0ef4a59f1 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -13,12 +13,24 @@ typedef std::vector valtype; +/** + * This is an enum that tracks the execution context of a script, similar to + * SigVersion in script/interpreter. It is separate however because we want to + * distinguish between top-level scriptPubKey execution and P2SH redeemScript + * execution (a distinction that has no impact on consensus rules). + */ enum class IsMineSigVersion { - BASE = 0, - WITNESS_V0 = 1 + TOP = 0, //! scriptPubKey execution + P2SH = 1, //! P2SH redeemScript + WITNESS_V0 = 2 //! P2WSH witness script execution }; +static bool PermitsUncompressed(IsMineSigVersion sigversion) +{ + return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH; +} + static bool HaveKeys(const std::vector& pubkeys, const CKeyStore& keystore) { for (const valtype& pubkey : pubkeys) { @@ -49,7 +61,7 @@ static isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPu break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - if (sigversion != IsMineSigVersion::BASE && vSolutions[0].size() != 33) { + if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) { isInvalid = true; return ISMINE_NO; } @@ -71,7 +83,7 @@ static isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPu } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (sigversion != IsMineSigVersion::BASE) { + if (!PermitsUncompressed(sigversion)) { CPubKey pubkey; if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { isInvalid = true; @@ -86,7 +98,7 @@ static isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPu CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { - isminetype ret = IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::BASE); + isminetype ret = IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::P2SH); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; } @@ -117,7 +129,7 @@ static isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPu // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. std::vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - if (sigversion != IsMineSigVersion::BASE) { + if (!PermitsUncompressed(sigversion)) { for (size_t i = 0; i < keys.size(); i++) { if (keys[i].size() != 33) { isInvalid = true; @@ -141,7 +153,7 @@ static isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPu isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid) { - return IsMineInner(keystore, scriptPubKey, isInvalid, IsMineSigVersion::BASE); + return IsMineInner(keystore, scriptPubKey, isInvalid, IsMineSigVersion::TOP); } isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)