Bitcoin Core  0.18.99
P2P Digital Currency
ismine.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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.
5 
6 #include <wallet/ismine.h>
7 
8 #include <key.h>
9 #include <script/script.h>
10 #include <script/sign.h>
11 #include <script/signingprovider.h>
12 #include <wallet/wallet.h>
13 
14 typedef std::vector<unsigned char> valtype;
15 
16 namespace {
17 
24 enum class IsMineSigVersion
25 {
26  TOP = 0,
27  P2SH = 1,
28  WITNESS_V0 = 2,
29 };
30 
36 enum class IsMineResult
37 {
38  NO = 0,
39  WATCH_ONLY = 1,
40  SPENDABLE = 2,
41  INVALID = 3,
42 };
43 
44 bool PermitsUncompressed(IsMineSigVersion sigversion)
45 {
46  return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
47 }
48 
49 bool HaveKeys(const std::vector<valtype>& pubkeys, const CWallet& keystore)
50 {
51  for (const valtype& pubkey : pubkeys) {
52  CKeyID keyID = CPubKey(pubkey).GetID();
53  if (!keystore.HaveKey(keyID)) return false;
54  }
55  return true;
56 }
57 
58 IsMineResult IsMineInner(const CWallet& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
59 {
60  IsMineResult ret = IsMineResult::NO;
61 
62  std::vector<valtype> vSolutions;
63  txnouttype whichType = Solver(scriptPubKey, vSolutions);
64 
65  CKeyID keyID;
66  switch (whichType)
67  {
68  case TX_NONSTANDARD:
69  case TX_NULL_DATA:
70  case TX_WITNESS_UNKNOWN:
71  break;
72  case TX_PUBKEY:
73  keyID = CPubKey(vSolutions[0]).GetID();
74  if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
75  return IsMineResult::INVALID;
76  }
77  if (keystore.HaveKey(keyID)) {
78  ret = std::max(ret, IsMineResult::SPENDABLE);
79  }
80  break;
82  {
83  if (sigversion == IsMineSigVersion::WITNESS_V0) {
84  // P2WPKH inside P2WSH is invalid.
85  return IsMineResult::INVALID;
86  }
87  if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
88  // We do not support bare witness outputs unless the P2SH version of it would be
89  // acceptable as well. This protects against matching before segwit activates.
90  // This also applies to the P2WSH case.
91  break;
92  }
93  ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
94  break;
95  }
96  case TX_PUBKEYHASH:
97  keyID = CKeyID(uint160(vSolutions[0]));
98  if (!PermitsUncompressed(sigversion)) {
99  CPubKey pubkey;
100  if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
101  return IsMineResult::INVALID;
102  }
103  }
104  if (keystore.HaveKey(keyID)) {
105  ret = std::max(ret, IsMineResult::SPENDABLE);
106  }
107  break;
108  case TX_SCRIPTHASH:
109  {
110  if (sigversion != IsMineSigVersion::TOP) {
111  // P2SH inside P2WSH or P2SH is invalid.
112  return IsMineResult::INVALID;
113  }
114  CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
115  CScript subscript;
116  if (keystore.GetCScript(scriptID, subscript)) {
117  ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH));
118  }
119  break;
120  }
122  {
123  if (sigversion == IsMineSigVersion::WITNESS_V0) {
124  // P2WSH inside P2WSH is invalid.
125  return IsMineResult::INVALID;
126  }
127  if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
128  break;
129  }
130  uint160 hash;
131  CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
132  CScriptID scriptID = CScriptID(hash);
133  CScript subscript;
134  if (keystore.GetCScript(scriptID, subscript)) {
135  ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0));
136  }
137  break;
138  }
139 
140  case TX_MULTISIG:
141  {
142  // Never treat bare multisig outputs as ours (they can still be made watchonly-though)
143  if (sigversion == IsMineSigVersion::TOP) {
144  break;
145  }
146 
147  // Only consider transactions "mine" if we own ALL the
148  // keys involved. Multi-signature transactions that are
149  // partially owned (somebody else has a key that can spend
150  // them) enable spend-out-from-under-you attacks, especially
151  // in shared-wallet situations.
152  std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
153  if (!PermitsUncompressed(sigversion)) {
154  for (size_t i = 0; i < keys.size(); i++) {
155  if (keys[i].size() != 33) {
156  return IsMineResult::INVALID;
157  }
158  }
159  }
160  if (HaveKeys(keys, keystore)) {
161  ret = std::max(ret, IsMineResult::SPENDABLE);
162  }
163  break;
164  }
165  }
166 
167  if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
168  ret = std::max(ret, IsMineResult::WATCH_ONLY);
169  }
170  return ret;
171 }
172 
173 } // namespace
174 
175 isminetype IsMine(const CWallet& keystore, const CScript& scriptPubKey)
176 {
177  switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
178  case IsMineResult::INVALID:
179  case IsMineResult::NO:
180  return ISMINE_NO;
181  case IsMineResult::WATCH_ONLY:
182  return ISMINE_WATCH_ONLY;
183  case IsMineResult::SPENDABLE:
184  return ISMINE_SPENDABLE;
185  }
186  assert(false);
187 }
188 
189 isminetype IsMine(const CWallet& keystore, const CTxDestination& dest)
190 {
191  CScript script = GetScriptForDestination(dest);
192  return IsMine(keystore, script);
193 }
Top-level scriptPubKey.
unspendable OP_RETURN script that carries data
Definition: standard.h:64
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
IsMineSigVersion
This is an enum that tracks the execution context of a script, similar to SigVersion in script/interp...
Definition: ismine.cpp:24
std::vector< unsigned char > valtype
Definition: ismine.cpp:14
txnouttype Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:91
IsMineResult
This is an internal representation of isminetype + invalidity.
Definition: ismine.cpp:36
bool HaveWatchOnly(const CScript &dest) const
Returns whether the watch-only script is in the wallet.
Definition: wallet.cpp:603
unsigned char * begin()
Definition: uint256.h:55
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:155
Only for Witness versions not already defined above.
Definition: standard.h:67
An encapsulated public key.
Definition: pubkey.h:30
bool HaveKey(const CKeyID &address) const override
Definition: wallet.cpp:4823
isminetype
IsMine() return codes.
Definition: ismine.h:18
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:289
CRIPEMD160 & Write(const unsigned char *data, size_t len)
Definition: ripemd160.cpp:247
P2SH redeemScript.
isminetype IsMine(const CWallet &keystore, const CScript &scriptPubKey)
Definition: ismine.cpp:175
txnouttype
Definition: standard.h:56
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:390
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:20
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:729
160-bit opaque blob.
Definition: uint256.h:110
virtual bool HaveCScript(const CScriptID &hash) const override
std::vector< unsigned char > valtype
Definition: interpreter.cpp:15
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:22
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: wallet.cpp:4860
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: ripemd160.cpp:273
boost::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:139
Definition: script.h:57
A hasher class for RIPEMD-160.
Definition: ripemd160.h:12
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:180