1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2017 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #include <script/ismine.h>
10 #include <script/script.h>
11 #include <script/sign.h>
14 typedef std::vector
<unsigned char> valtype
;
16 unsigned int HaveKeys(const std::vector
<valtype
>& pubkeys
, const CKeyStore
& keystore
)
18 unsigned int nResult
= 0;
19 for (const valtype
& pubkey
: pubkeys
)
21 CKeyID keyID
= CPubKey(pubkey
).GetID();
22 if (keystore
.HaveKey(keyID
))
28 isminetype
IsMine(const CKeyStore
& keystore
, const CScript
& scriptPubKey
, SigVersion sigversion
)
30 bool isInvalid
= false;
31 return IsMine(keystore
, scriptPubKey
, isInvalid
, sigversion
);
34 isminetype
IsMine(const CKeyStore
& keystore
, const CTxDestination
& dest
, SigVersion sigversion
)
36 bool isInvalid
= false;
37 return IsMine(keystore
, dest
, isInvalid
, sigversion
);
40 isminetype
IsMine(const CKeyStore
&keystore
, const CTxDestination
& dest
, bool& isInvalid
, SigVersion sigversion
)
42 CScript script
= GetScriptForDestination(dest
);
43 return IsMine(keystore
, script
, isInvalid
, sigversion
);
46 isminetype
IsMine(const CKeyStore
&keystore
, const CScript
& scriptPubKey
, bool& isInvalid
, SigVersion sigversion
)
50 std::vector
<valtype
> vSolutions
;
52 if (!Solver(scriptPubKey
, whichType
, vSolutions
)) {
53 if (keystore
.HaveWatchOnly(scriptPubKey
))
54 return ISMINE_WATCH_UNSOLVABLE
;
63 case TX_WITNESS_UNKNOWN
:
66 keyID
= CPubKey(vSolutions
[0]).GetID();
67 if (sigversion
!= SIGVERSION_BASE
&& vSolutions
[0].size() != 33) {
71 if (keystore
.HaveKey(keyID
))
72 return ISMINE_SPENDABLE
;
74 case TX_WITNESS_V0_KEYHASH
:
76 if (!keystore
.HaveCScript(CScriptID(CScript() << OP_0
<< vSolutions
[0]))) {
77 // We do not support bare witness outputs unless the P2SH version of it would be
78 // acceptable as well. This protects against matching before segwit activates.
79 // This also applies to the P2WSH case.
82 isminetype ret
= ::IsMine(keystore
, GetScriptForDestination(CKeyID(uint160(vSolutions
[0]))), isInvalid
, SIGVERSION_WITNESS_V0
);
83 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
88 keyID
= CKeyID(uint160(vSolutions
[0]));
89 if (sigversion
!= SIGVERSION_BASE
) {
91 if (keystore
.GetPubKey(keyID
, pubkey
) && !pubkey
.IsCompressed()) {
96 if (keystore
.HaveKey(keyID
))
97 return ISMINE_SPENDABLE
;
101 CScriptID scriptID
= CScriptID(uint160(vSolutions
[0]));
103 if (keystore
.GetCScript(scriptID
, subscript
)) {
104 isminetype ret
= IsMine(keystore
, subscript
, isInvalid
);
105 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
110 case TX_WITNESS_V0_SCRIPTHASH
:
112 if (!keystore
.HaveCScript(CScriptID(CScript() << OP_0
<< vSolutions
[0]))) {
116 CRIPEMD160().Write(&vSolutions
[0][0], vSolutions
[0].size()).Finalize(hash
.begin());
117 CScriptID scriptID
= CScriptID(hash
);
119 if (keystore
.GetCScript(scriptID
, subscript
)) {
120 isminetype ret
= IsMine(keystore
, subscript
, isInvalid
, SIGVERSION_WITNESS_V0
);
121 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
129 // Only consider transactions "mine" if we own ALL the
130 // keys involved. Multi-signature transactions that are
131 // partially owned (somebody else has a key that can spend
132 // them) enable spend-out-from-under-you attacks, especially
133 // in shared-wallet situations.
134 std::vector
<valtype
> keys(vSolutions
.begin()+1, vSolutions
.begin()+vSolutions
.size()-1);
135 if (sigversion
!= SIGVERSION_BASE
) {
136 for (size_t i
= 0; i
< keys
.size(); i
++) {
137 if (keys
[i
].size() != 33) {
143 if (HaveKeys(keys
, keystore
) == keys
.size())
144 return ISMINE_SPENDABLE
;
149 if (keystore
.HaveWatchOnly(scriptPubKey
)) {
150 // TODO: This could be optimized some by doing some work after the above solver
152 return ProduceSignature(DummySignatureCreator(&keystore
), scriptPubKey
, sigs
) ? ISMINE_WATCH_SOLVABLE
: ISMINE_WATCH_UNSOLVABLE
;