Skip to content

Commit c004ffc

Browse files
committed
Make handling of invalid in IsMine more uniform
1 parent a53f0fe commit c004ffc

File tree

1 file changed

+40
-33
lines changed

1 file changed

+40
-33
lines changed

src/script/ismine.cpp

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ enum class IsMineSigVersion
2828
WITNESS_V0 = 2 //! P2WSH witness script execution
2929
};
3030

31+
/**
32+
* This is an internal representation of isminetype + invalidity.
33+
* Its order is significant, as we return the max of all explored
34+
* possibilities.
35+
*/
36+
enum class IsMineResult
37+
{
38+
NO = 0, //! Not ours
39+
WATCH_ONLY = 1, //! Included in watch-only balance
40+
SPENDABLE = 2, //! Included in all balances
41+
INVALID = 3, //! Not spendable by anyone
42+
};
43+
3144
bool PermitsUncompressed(IsMineSigVersion sigversion)
3245
{
3346
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
@@ -42,16 +55,9 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
4255
return true;
4356
}
4457

45-
void Update(isminetype& val, isminetype update)
58+
IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
4659
{
47-
if (val == ISMINE_NO) val = update;
48-
if (val == ISMINE_WATCH_ONLY && update == ISMINE_SPENDABLE) val = update;
49-
}
50-
51-
isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, IsMineSigVersion sigversion)
52-
{
53-
isminetype ret = ISMINE_NO;
54-
isInvalid = false;
60+
IsMineResult ret = IsMineResult::NO;
5561

5662
std::vector<valtype> vSolutions;
5763
txnouttype whichType;
@@ -67,62 +73,57 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
6773
case TX_PUBKEY:
6874
keyID = CPubKey(vSolutions[0]).GetID();
6975
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
70-
isInvalid = true;
71-
return ISMINE_NO;
76+
return IsMineResult::INVALID;
7277
}
7378
if (keystore.HaveKey(keyID)) {
74-
Update(ret, ISMINE_SPENDABLE);
79+
ret = std::max(ret, IsMineResult::SPENDABLE);
7580
}
7681
break;
7782
case TX_WITNESS_V0_KEYHASH:
7883
{
7984
if (sigversion == IsMineSigVersion::WITNESS_V0) {
8085
// P2WPKH inside P2WSH is invalid.
81-
isInvalid = true;
82-
return ISMINE_NO;
86+
return IsMineResult::INVALID;
8387
}
8488
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
8589
// We do not support bare witness outputs unless the P2SH version of it would be
8690
// acceptable as well. This protects against matching before segwit activates.
8791
// This also applies to the P2WSH case.
8892
break;
8993
}
90-
Update(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, IsMineSigVersion::WITNESS_V0));
94+
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
9195
break;
9296
}
9397
case TX_PUBKEYHASH:
9498
keyID = CKeyID(uint160(vSolutions[0]));
9599
if (!PermitsUncompressed(sigversion)) {
96100
CPubKey pubkey;
97101
if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
98-
isInvalid = true;
99-
return ISMINE_NO;
102+
return IsMineResult::INVALID;
100103
}
101104
}
102105
if (keystore.HaveKey(keyID)) {
103-
Update(ret, ISMINE_SPENDABLE);
106+
ret = std::max(ret, IsMineResult::SPENDABLE);
104107
}
105108
break;
106109
case TX_SCRIPTHASH:
107110
{
108111
if (sigversion != IsMineSigVersion::TOP) {
109112
// P2SH inside P2WSH or P2SH is invalid.
110-
isInvalid = true;
111-
return ISMINE_NO;
113+
return IsMineResult::INVALID;
112114
}
113115
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
114116
CScript subscript;
115117
if (keystore.GetCScript(scriptID, subscript)) {
116-
Update(ret, IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::P2SH));
118+
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH));
117119
}
118120
break;
119121
}
120122
case TX_WITNESS_V0_SCRIPTHASH:
121123
{
122124
if (sigversion == IsMineSigVersion::WITNESS_V0) {
123125
// P2WSH inside P2WSH is invalid.
124-
isInvalid = true;
125-
return ISMINE_NO;
126+
return IsMineResult::INVALID;
126127
}
127128
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
128129
break;
@@ -132,7 +133,7 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
132133
CScriptID scriptID = CScriptID(hash);
133134
CScript subscript;
134135
if (keystore.GetCScript(scriptID, subscript)) {
135-
Update(ret, IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::WITNESS_V0));
136+
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0));
136137
}
137138
break;
138139
}
@@ -153,20 +154,19 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
153154
if (!PermitsUncompressed(sigversion)) {
154155
for (size_t i = 0; i < keys.size(); i++) {
155156
if (keys[i].size() != 33) {
156-
isInvalid = true;
157-
return ISMINE_NO;
157+
return IsMineResult::INVALID;
158158
}
159159
}
160160
}
161161
if (HaveKeys(keys, keystore)) {
162-
Update(ret, ISMINE_SPENDABLE);
162+
ret = std::max(ret, IsMineResult::SPENDABLE);
163163
}
164164
break;
165165
}
166166
}
167167

168-
if (ret == ISMINE_NO && keystore.HaveWatchOnly(scriptPubKey)) {
169-
return ISMINE_WATCH_ONLY;
168+
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
169+
ret = std::max(ret, IsMineResult::WATCH_ONLY);
170170
}
171171
return ret;
172172
}
@@ -175,11 +175,18 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
175175

176176
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid)
177177
{
178-
isminetype ret = IsMineInner(keystore, scriptPubKey, isInvalid, IsMineSigVersion::TOP);
179-
if (isInvalid) {
180-
ret = ISMINE_NO;
178+
isInvalid = false;
179+
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
180+
case IsMineResult::INVALID:
181+
isInvalid = true;
182+
case IsMineResult::NO:
183+
return ISMINE_NO;
184+
case IsMineResult::WATCH_ONLY:
185+
return ISMINE_WATCH_ONLY;
186+
case IsMineResult::SPENDABLE:
187+
return ISMINE_SPENDABLE;
181188
}
182-
return ret;
189+
assert(false);
183190
}
184191

185192
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)

0 commit comments

Comments
 (0)