@@ -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+
3144bool 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
176176isminetype 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
185192isminetype IsMine (const CKeyStore& keystore, const CScript& scriptPubKey)
0 commit comments