@@ -28,6 +28,19 @@ enum class IsMineSigVersion
28
28
WITNESS_V0 = 2 // ! P2WSH witness script execution
29
29
};
30
30
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
+
31
44
bool PermitsUncompressed (IsMineSigVersion sigversion)
32
45
{
33
46
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
@@ -42,16 +55,9 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
42
55
return true ;
43
56
}
44
57
45
- void Update (isminetype& val, isminetype update )
58
+ IsMineResult IsMineInner ( const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion )
46
59
{
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;
55
61
56
62
std::vector<valtype> vSolutions;
57
63
txnouttype whichType;
@@ -67,62 +73,57 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
67
73
case TX_PUBKEY:
68
74
keyID = CPubKey (vSolutions[0 ]).GetID ();
69
75
if (!PermitsUncompressed (sigversion) && vSolutions[0 ].size () != 33 ) {
70
- isInvalid = true ;
71
- return ISMINE_NO;
76
+ return IsMineResult::INVALID;
72
77
}
73
78
if (keystore.HaveKey (keyID)) {
74
- Update (ret, ISMINE_SPENDABLE );
79
+ ret = std::max (ret, IsMineResult::SPENDABLE );
75
80
}
76
81
break ;
77
82
case TX_WITNESS_V0_KEYHASH:
78
83
{
79
84
if (sigversion == IsMineSigVersion::WITNESS_V0) {
80
85
// P2WPKH inside P2WSH is invalid.
81
- isInvalid = true ;
82
- return ISMINE_NO;
86
+ return IsMineResult::INVALID;
83
87
}
84
88
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript (CScriptID (CScript () << OP_0 << vSolutions[0 ]))) {
85
89
// We do not support bare witness outputs unless the P2SH version of it would be
86
90
// acceptable as well. This protects against matching before segwit activates.
87
91
// This also applies to the P2WSH case.
88
92
break ;
89
93
}
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));
91
95
break ;
92
96
}
93
97
case TX_PUBKEYHASH:
94
98
keyID = CKeyID (uint160 (vSolutions[0 ]));
95
99
if (!PermitsUncompressed (sigversion)) {
96
100
CPubKey pubkey;
97
101
if (keystore.GetPubKey (keyID, pubkey) && !pubkey.IsCompressed ()) {
98
- isInvalid = true ;
99
- return ISMINE_NO;
102
+ return IsMineResult::INVALID;
100
103
}
101
104
}
102
105
if (keystore.HaveKey (keyID)) {
103
- Update (ret, ISMINE_SPENDABLE );
106
+ ret = std::max (ret, IsMineResult::SPENDABLE );
104
107
}
105
108
break ;
106
109
case TX_SCRIPTHASH:
107
110
{
108
111
if (sigversion != IsMineSigVersion::TOP) {
109
112
// P2SH inside P2WSH or P2SH is invalid.
110
- isInvalid = true ;
111
- return ISMINE_NO;
113
+ return IsMineResult::INVALID;
112
114
}
113
115
CScriptID scriptID = CScriptID (uint160 (vSolutions[0 ]));
114
116
CScript subscript;
115
117
if (keystore.GetCScript (scriptID, subscript)) {
116
- Update (ret, IsMineInner (keystore, subscript, isInvalid , IsMineSigVersion::P2SH));
118
+ ret = std::max (ret, IsMineInner (keystore, subscript, IsMineSigVersion::P2SH));
117
119
}
118
120
break ;
119
121
}
120
122
case TX_WITNESS_V0_SCRIPTHASH:
121
123
{
122
124
if (sigversion == IsMineSigVersion::WITNESS_V0) {
123
125
// P2WSH inside P2WSH is invalid.
124
- isInvalid = true ;
125
- return ISMINE_NO;
126
+ return IsMineResult::INVALID;
126
127
}
127
128
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript (CScriptID (CScript () << OP_0 << vSolutions[0 ]))) {
128
129
break ;
@@ -132,7 +133,7 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
132
133
CScriptID scriptID = CScriptID (hash);
133
134
CScript subscript;
134
135
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));
136
137
}
137
138
break ;
138
139
}
@@ -153,20 +154,19 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
153
154
if (!PermitsUncompressed (sigversion)) {
154
155
for (size_t i = 0 ; i < keys.size (); i++) {
155
156
if (keys[i].size () != 33 ) {
156
- isInvalid = true ;
157
- return ISMINE_NO;
157
+ return IsMineResult::INVALID;
158
158
}
159
159
}
160
160
}
161
161
if (HaveKeys (keys, keystore)) {
162
- Update (ret, ISMINE_SPENDABLE );
162
+ ret = std::max (ret, IsMineResult::SPENDABLE );
163
163
}
164
164
break ;
165
165
}
166
166
}
167
167
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) ;
170
170
}
171
171
return ret;
172
172
}
@@ -175,11 +175,18 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
175
175
176
176
isminetype IsMine (const CKeyStore& keystore, const CScript& scriptPubKey, bool & isInvalid)
177
177
{
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;
181
188
}
182
- return ret ;
189
+ assert ( false ) ;
183
190
}
184
191
185
192
isminetype IsMine (const CKeyStore& keystore, const CScript& scriptPubKey)
0 commit comments