1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 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.
10 #include "script/script.h"
11 #include "script/standard.h"
12 #include "script/sign.h"
14 #include <boost/foreach.hpp>
16 typedef std::vector
<unsigned char> valtype
;
18 unsigned int HaveKeys(const std::vector
<valtype
>& pubkeys
, const CKeyStore
& keystore
)
20 unsigned int nResult
= 0;
21 for (const valtype
& pubkey
: pubkeys
)
23 CKeyID keyID
= CPubKey(pubkey
).GetID();
24 if (keystore
.HaveKey(keyID
))
30 isminetype
IsMine(const CKeyStore
& keystore
, const CScript
& scriptPubKey
, SigVersion sigversion
)
32 bool isInvalid
= false;
33 return IsMine(keystore
, scriptPubKey
, isInvalid
, sigversion
);
36 isminetype
IsMine(const CKeyStore
& keystore
, const CTxDestination
& dest
, SigVersion sigversion
)
38 bool isInvalid
= false;
39 return IsMine(keystore
, dest
, isInvalid
, sigversion
);
42 isminetype
IsMine(const CKeyStore
&keystore
, const CTxDestination
& dest
, bool& isInvalid
, SigVersion sigversion
)
44 CScript script
= GetScriptForDestination(dest
);
45 return IsMine(keystore
, script
, isInvalid
, sigversion
);
48 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
;
65 keyID
= CPubKey(vSolutions
[0]).GetID();
66 if (sigversion
!= SIGVERSION_BASE
&& vSolutions
[0].size() != 33) {
70 if (keystore
.HaveKey(keyID
))
71 return ISMINE_SPENDABLE
;
73 case TX_WITNESS_V0_KEYHASH
:
75 if (!keystore
.HaveCScript(CScriptID(CScript() << OP_0
<< vSolutions
[0]))) {
76 // We do not support bare witness outputs unless the P2SH version of it would be
77 // acceptable as well. This protects against matching before segwit activates.
78 // This also applies to the P2WSH case.
81 isminetype ret
= ::IsMine(keystore
, GetScriptForDestination(CKeyID(uint160(vSolutions
[0]))), isInvalid
, SIGVERSION_WITNESS_V0
);
82 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
87 keyID
= CKeyID(uint160(vSolutions
[0]));
88 if (sigversion
!= SIGVERSION_BASE
) {
90 if (keystore
.GetPubKey(keyID
, pubkey
) && !pubkey
.IsCompressed()) {
95 if (keystore
.HaveKey(keyID
))
96 return ISMINE_SPENDABLE
;
100 CScriptID scriptID
= CScriptID(uint160(vSolutions
[0]));
102 if (keystore
.GetCScript(scriptID
, subscript
)) {
103 isminetype ret
= IsMine(keystore
, subscript
, isInvalid
);
104 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
109 case TX_WITNESS_V0_SCRIPTHASH
:
111 if (!keystore
.HaveCScript(CScriptID(CScript() << OP_0
<< vSolutions
[0]))) {
115 CRIPEMD160().Write(&vSolutions
[0][0], vSolutions
[0].size()).Finalize(hash
.begin());
116 CScriptID scriptID
= CScriptID(hash
);
118 if (keystore
.GetCScript(scriptID
, subscript
)) {
119 isminetype ret
= IsMine(keystore
, subscript
, isInvalid
, SIGVERSION_WITNESS_V0
);
120 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
128 // Only consider transactions "mine" if we own ALL the
129 // keys involved. Multi-signature transactions that are
130 // partially owned (somebody else has a key that can spend
131 // them) enable spend-out-from-under-you attacks, especially
132 // in shared-wallet situations.
133 std::vector
<valtype
> keys(vSolutions
.begin()+1, vSolutions
.begin()+vSolutions
.size()-1);
134 if (sigversion
!= SIGVERSION_BASE
) {
135 for (size_t i
= 0; i
< keys
.size(); i
++) {
136 if (keys
[i
].size() != 33) {
142 if (HaveKeys(keys
, keystore
) == keys
.size())
143 return ISMINE_SPENDABLE
;
148 if (keystore
.HaveWatchOnly(scriptPubKey
)) {
149 // TODO: This could be optimized some by doing some work after the above solver
151 return ProduceSignature(DummySignatureCreator(&keystore
), scriptPubKey
, sigs
) ? ISMINE_WATCH_SOLVABLE
: ISMINE_WATCH_UNSOLVABLE
;