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"
15 typedef std::vector
<unsigned char> valtype
;
17 unsigned int HaveKeys(const std::vector
<valtype
>& pubkeys
, const CKeyStore
& keystore
)
19 unsigned int nResult
= 0;
20 for (const valtype
& pubkey
: pubkeys
)
22 CKeyID keyID
= CPubKey(pubkey
).GetID();
23 if (keystore
.HaveKey(keyID
))
29 isminetype
IsMine(const CKeyStore
& keystore
, const CScript
& scriptPubKey
, SigVersion sigversion
)
31 bool isInvalid
= false;
32 return IsMine(keystore
, scriptPubKey
, isInvalid
, sigversion
);
35 isminetype
IsMine(const CKeyStore
& keystore
, const CTxDestination
& dest
, SigVersion sigversion
)
37 bool isInvalid
= false;
38 return IsMine(keystore
, dest
, isInvalid
, sigversion
);
41 isminetype
IsMine(const CKeyStore
&keystore
, const CTxDestination
& dest
, bool& isInvalid
, SigVersion sigversion
)
43 CScript script
= GetScriptForDestination(dest
);
44 return IsMine(keystore
, script
, isInvalid
, sigversion
);
47 isminetype
IsMine(const CKeyStore
&keystore
, const CScript
& scriptPubKey
, bool& isInvalid
, SigVersion sigversion
)
49 std::vector
<valtype
> vSolutions
;
51 if (!Solver(scriptPubKey
, whichType
, vSolutions
)) {
52 if (keystore
.HaveWatchOnly(scriptPubKey
))
53 return ISMINE_WATCH_UNSOLVABLE
;
64 keyID
= CPubKey(vSolutions
[0]).GetID();
65 if (sigversion
!= SIGVERSION_BASE
&& vSolutions
[0].size() != 33) {
69 if (keystore
.HaveKey(keyID
))
70 return ISMINE_SPENDABLE
;
72 case TX_WITNESS_V0_KEYHASH
:
74 if (!keystore
.HaveCScript(CScriptID(CScript() << OP_0
<< vSolutions
[0]))) {
75 // We do not support bare witness outputs unless the P2SH version of it would be
76 // acceptable as well. This protects against matching before segwit activates.
77 // This also applies to the P2WSH case.
80 isminetype ret
= ::IsMine(keystore
, GetScriptForDestination(CKeyID(uint160(vSolutions
[0]))), isInvalid
, SIGVERSION_WITNESS_V0
);
81 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
86 keyID
= CKeyID(uint160(vSolutions
[0]));
87 if (sigversion
!= SIGVERSION_BASE
) {
89 if (keystore
.GetPubKey(keyID
, pubkey
) && !pubkey
.IsCompressed()) {
94 if (keystore
.HaveKey(keyID
))
95 return ISMINE_SPENDABLE
;
99 CScriptID scriptID
= CScriptID(uint160(vSolutions
[0]));
101 if (keystore
.GetCScript(scriptID
, subscript
)) {
102 isminetype ret
= IsMine(keystore
, subscript
, isInvalid
);
103 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
108 case TX_WITNESS_V0_SCRIPTHASH
:
110 if (!keystore
.HaveCScript(CScriptID(CScript() << OP_0
<< vSolutions
[0]))) {
114 CRIPEMD160().Write(&vSolutions
[0][0], vSolutions
[0].size()).Finalize(hash
.begin());
115 CScriptID scriptID
= CScriptID(hash
);
117 if (keystore
.GetCScript(scriptID
, subscript
)) {
118 isminetype ret
= IsMine(keystore
, subscript
, isInvalid
, SIGVERSION_WITNESS_V0
);
119 if (ret
== ISMINE_SPENDABLE
|| ret
== ISMINE_WATCH_SOLVABLE
|| (ret
== ISMINE_NO
&& isInvalid
))
127 // Only consider transactions "mine" if we own ALL the
128 // keys involved. Multi-signature transactions that are
129 // partially owned (somebody else has a key that can spend
130 // them) enable spend-out-from-under-you attacks, especially
131 // in shared-wallet situations.
132 std::vector
<valtype
> keys(vSolutions
.begin()+1, vSolutions
.begin()+vSolutions
.size()-1);
133 if (sigversion
!= SIGVERSION_BASE
) {
134 for (size_t i
= 0; i
< keys
.size(); i
++) {
135 if (keys
[i
].size() != 33) {
141 if (HaveKeys(keys
, keystore
) == keys
.size())
142 return ISMINE_SPENDABLE
;
147 if (keystore
.HaveWatchOnly(scriptPubKey
)) {
148 // TODO: This could be optimized some by doing some work after the above solver
150 return ProduceSignature(DummySignatureCreator(&keystore
), scriptPubKey
, sigs
) ? ISMINE_WATCH_SOLVABLE
: ISMINE_WATCH_UNSOLVABLE
;