PIVX Core  5.6.99
P2P Digital Currency
standard.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Copyright (c) 2017-2021 The PIVX Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or https://www.opensource.org/licenses/mit-license.php.
6 
7 #include "script/standard.h"
8 
9 #include "pubkey.h"
10 #include "script/script.h"
11 
12 typedef std::vector<unsigned char> valtype;
13 
14 unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
15 
16 CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
17 
19 {
20  switch (t)
21  {
22  case TX_NONSTANDARD: return "nonstandard";
23  case TX_PUBKEY: return "pubkey";
24  case TX_PUBKEYHASH: return "pubkeyhash";
25  case TX_EXCHANGEADDR: return "exchangeaddress";
26  case TX_SCRIPTHASH: return "scripthash";
27  case TX_MULTISIG: return "multisig";
28  case TX_COLDSTAKE: return "coldstake";
29  case TX_NULL_DATA: return "nulldata";
30  }
31  return nullptr;
32 }
33 
34 static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
35 {
36  if (script.size() == CPubKey::PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) {
37  pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::PUBLIC_KEY_SIZE + 1);
38  return CPubKey::ValidSize(pubkey);
39  }
40  if (script.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) {
41  pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1);
42  return CPubKey::ValidSize(pubkey);
43  }
44  return false;
45 }
46 
47 static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
48 {
49  if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
50  pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
51  return true;
52  }
53  return false;
54 }
55 
56 static bool MatchPayToColdStaking(const CScript& script, valtype& stakerPubKeyHash, valtype& ownerPubKeyHash)
57 {
58  if (script.IsPayToColdStaking()) {
59  stakerPubKeyHash = valtype(script.begin () + 6, script.begin() + 26);
60  ownerPubKeyHash = valtype(script.begin () + 28, script.begin() + 48);
61  return true;
62  }
63  return false;
64 }
65 
67 static constexpr bool IsSmallInteger(opcodetype opcode)
68 {
69  return opcode >= OP_1 && opcode <= OP_16;
70 }
71 
72 static bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<valtype>& pubkeys)
73 {
74  opcodetype opcode;
75  valtype data;
76  CScript::const_iterator it = script.begin();
77  if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
78 
79  if (!script.GetOp(it, opcode, data) || !IsSmallInteger(opcode)) return false;
80  required = CScript::DecodeOP_N(opcode);
81  while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
82  pubkeys.emplace_back(std::move(data));
83  }
84  if (!IsSmallInteger(opcode)) return false;
85  unsigned int keys = CScript::DecodeOP_N(opcode);
86  if (pubkeys.size() != keys || keys < required) return false;
87  return (it + 1 == script.end());
88 }
89 
90 bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
91 {
92  if (scriptPubKey.empty())
93  return false;
94 
95  vSolutionsRet.clear();
96 
97  // Shortcut for pay-to-script-hash, which are more constrained than the other types:
98  // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
99  if (scriptPubKey.IsPayToScriptHash())
100  {
101  typeRet = TX_SCRIPTHASH;
102  std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
103  vSolutionsRet.push_back(hashBytes);
104  return true;
105  }
106 
107  // Provably prunable, data-carrying output
108  //
109  // So long as script passes the IsUnspendable() test and all but the first
110  // byte passes the IsPushOnly() test we don't care what exactly is in the
111  // script.
112  if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
113  typeRet = TX_NULL_DATA;
114  return true;
115  }
116 
117  std::vector<unsigned char> data;
118  if (MatchPayToPubkey(scriptPubKey, data)) {
119  typeRet = TX_PUBKEY;
120  vSolutionsRet.push_back(std::move(data));
121  return true;
122  }
123 
124  if (MatchPayToPubkeyHash(scriptPubKey, data)) {
125  typeRet = TX_PUBKEYHASH;
126  vSolutionsRet.push_back(std::move(data));
127  return true;
128  }
129 
130  if (scriptPubKey.IsPayToExchangeAddress())
131  {
132  typeRet = TX_EXCHANGEADDR;
133  std::vector<unsigned char> hashBytes(scriptPubKey.begin()+4, scriptPubKey.begin()+24);
134  vSolutionsRet.push_back(hashBytes);
135  return true;
136  }
137 
138 
139  std::vector<unsigned char> data1;
140  if (MatchPayToColdStaking(scriptPubKey, data, data1)) {
141  typeRet = TX_COLDSTAKE;
142  vSolutionsRet.push_back(std::move(data));
143  vSolutionsRet.push_back(std::move(data1));
144  return true;
145  }
146 
147  unsigned int required;
148  std::vector<std::vector<unsigned char>> keys;
149  if (MatchMultisig(scriptPubKey, required, keys)) {
150  typeRet = TX_MULTISIG;
151  vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
152  vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
153  vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
154  return true;
155  }
156 
157  vSolutionsRet.clear();
158  typeRet = TX_NONSTANDARD;
159  return false;
160 }
161 
162 bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet, bool fColdStake)
163 {
164  std::vector<valtype> vSolutions;
165  txnouttype whichType;
166  if (!Solver(scriptPubKey, whichType, vSolutions))
167  return false;
168 
169  if (whichType == TX_PUBKEY) {
170  CPubKey pubKey(vSolutions[0]);
171  if (!pubKey.IsValid())
172  return false;
173 
174  addressRet = pubKey.GetID();
175  return true;
176 
177  } else if (whichType == TX_PUBKEYHASH) {
178  addressRet = CKeyID(uint160(vSolutions[0]));
179  return true;
180 
181  } else if (whichType == TX_SCRIPTHASH) {
182  addressRet = CScriptID(uint160(vSolutions[0]));
183  return true;
184  } else if (whichType == TX_EXCHANGEADDR) {
185  addressRet = CExchangeKeyID(uint160(vSolutions[0]));
186  return true;
187  } else if (whichType == TX_COLDSTAKE) {
188  addressRet = CKeyID(uint160(vSolutions[!fColdStake]));
189  return true;
190  }
191  // Multisig txns have more than one address...
192  return false;
193 }
194 
195 bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
196 {
197  addressRet.clear();
198  typeRet = TX_NONSTANDARD;
199  std::vector<valtype> vSolutions;
200  if (!Solver(scriptPubKey, typeRet, vSolutions))
201  return false;
202  if (typeRet == TX_NULL_DATA){
203  // This is data, not addresses
204  return false;
205  }
206 
207  if (typeRet == TX_MULTISIG)
208  {
209  nRequiredRet = vSolutions.front()[0];
210  for (unsigned int i = 1; i < vSolutions.size()-1; i++)
211  {
212  CPubKey pubKey(vSolutions[i]);
213  if (!pubKey.IsValid())
214  continue;
215 
216  CTxDestination address = pubKey.GetID();
217  addressRet.push_back(address);
218  }
219 
220  if (addressRet.empty())
221  return false;
222 
223  } else if (typeRet == TX_COLDSTAKE)
224  {
225  if (vSolutions.size() < 2)
226  return false;
227  nRequiredRet = 2;
228  addressRet.push_back(CKeyID(uint160(vSolutions[0])));
229  addressRet.push_back(CKeyID(uint160(vSolutions[1])));
230  return true;
231 
232  } else
233  {
234  nRequiredRet = 1;
235  CTxDestination address;
236  if (!ExtractDestination(scriptPubKey, address))
237  return false;
238  addressRet.push_back(address);
239  }
240 
241  return true;
242 }
243 
244 namespace
245 {
246 class CScriptVisitor : public boost::static_visitor<bool>
247 {
248 private:
249  CScript *script;
250 public:
251  explicit CScriptVisitor(CScript *scriptin) { script = scriptin; }
252 
253  bool operator()(const CNoDestination &dest) const {
254  script->clear();
255  return false;
256  }
257 
258  bool operator()(const CKeyID &keyID) const {
259  script->clear();
260  *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
261  return true;
262  }
263 
264  bool operator()(const CExchangeKeyID &keyID) const {
265  script->clear();
266  *script << OP_EXCHANGEADDR << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
267  return true;
268  }
269 
270  bool operator()(const CScriptID &scriptID) const {
271  script->clear();
272  *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
273  return true;
274  }
275 };
276 }
277 
279 {
280  CScript script;
281 
282  boost::apply_visitor(CScriptVisitor(&script), dest);
283  return script;
284 }
285 
287 {
288  return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
289 }
290 
291 CScript GetScriptForStakeDelegation(const CKeyID& stakingKey, const CKeyID& spendingKey)
292 {
293  CScript script;
294  script << OP_DUP << OP_HASH160 << OP_ROT <<
295  OP_IF << OP_CHECKCOLDSTAKEVERIFY << ToByteVector(stakingKey) <<
296  OP_ELSE << ToByteVector(spendingKey) << OP_ENDIF <<
298  return script;
299 }
300 
301 CScript GetScriptForStakeDelegationLOF(const CKeyID& stakingKey, const CKeyID& spendingKey)
302 {
303  CScript script;
304  script << OP_DUP << OP_HASH160 << OP_ROT <<
305  OP_IF << OP_CHECKCOLDSTAKEVERIFY_LOF << ToByteVector(stakingKey) <<
306  OP_ELSE << ToByteVector(spendingKey) << OP_ENDIF <<
308  return script;
309 }
310 
311 CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
312 {
313  CScript script;
314 
315  script << CScript::EncodeOP_N(nRequired);
316  for (const CPubKey& key : keys)
317  script << ToByteVector(key);
318  script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
319  return script;
320 }
321 
323 {
324  CScript script;
325  script << OP_RETURN << ToByteVector(message);
326  return script;
327 }
328 
330  return dest.which() != 0;
331 }
332 
A reference to a CKey: the Hash160 of its serialized public key, special case for exchange key.
Definition: pubkey.h:30
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:21
An encapsulated public key.
Definition: pubkey.h:44
const unsigned char * end() const
Definition: pubkey.h:124
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
bool IsValid() const
Definition: pubkey.h:183
static bool ValidSize(const std::vector< unsigned char > &vch)
Definition: pubkey.h:86
const unsigned char * begin() const
Definition: pubkey.h:123
static constexpr unsigned int PUBLIC_KEY_SIZE
secp256k1:
Definition: pubkey.h:49
static constexpr unsigned int COMPRESSED_PUBLIC_KEY_SIZE
Definition: pubkey.h:50
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
bool IsPushOnly(const_iterator pc) const
Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
Definition: script.cpp:285
bool IsPayToScriptHash() const
Definition: script.cpp:223
void clear()
Definition: script.h:659
static int DecodeOP_N(opcodetype opcode)
Encode/decode small integers:
Definition: script.h:568
bool GetOp(iterator &pc, opcodetype &opcodeRet, std::vector< unsigned char > &vchRet)
Definition: script.h:488
bool IsPayToColdStaking() const
Definition: script.cpp:233
bool IsPayToExchangeAddress() const
Definition: script.cpp:254
static opcodetype EncodeOP_N(int n)
Definition: script.h:575
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:24
CScriptID()
Definition: standard.h:26
bool empty() const
Definition: prevector.h:281
size_type size() const
Definition: prevector.h:277
T & back()
Definition: prevector.h:451
iterator begin()
Definition: prevector.h:285
iterator end()
Definition: prevector.h:287
160-bit opaque blob.
Definition: uint256.h:127
256-bit opaque blob.
Definition: uint256.h:138
uint160 Hash160(const T1 pbegin, const T1 pend)
Compute the 160-bit hash an object.
Definition: hash.h:193
std::vector< unsigned char > valtype
Definition: interpreter.cpp:17
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:43
opcodetype
Script opcodes.
Definition: script.h:50
@ OP_CHECKMULTISIG
Definition: script.h:168
@ OP_IF
Definition: script.h:80
@ OP_ROT
Definition: script.h:106
@ OP_CHECKSIG
Definition: script.h:166
@ OP_16
Definition: script.h:75
@ OP_EQUAL
Definition: script.h:122
@ OP_ENDIF
Definition: script.h:85
@ OP_DUP
Definition: script.h:101
@ OP_CHECKCOLDSTAKEVERIFY
Definition: script.h:191
@ OP_HASH160
Definition: script.h:163
@ OP_1
Definition: script.h:59
@ OP_CHECKCOLDSTAKEVERIFY_LOF
Definition: script.h:190
@ OP_ELSE
Definition: script.h:84
@ OP_RETURN
Definition: script.h:87
@ OP_EXCHANGEADDR
Definition: script.h:194
@ OP_EQUALVERIFY
Definition: script.h:123
CScript GetScriptForOpReturn(const uint256 &message)
Generate an OP_RETURN output script with the given data.
Definition: standard.cpp:322
bool ExtractDestinations(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< CTxDestination > &addressRet, int &nRequiredRet)
Parse a standard scriptPubKey with one or more destination addresses.
Definition: standard.cpp:195
CScript GetScriptForStakeDelegation(const CKeyID &stakingKey, const CKeyID &spendingKey)
Generate a P2CS script for the given staker and owner keys.
Definition: standard.cpp:291
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: standard.cpp:311
CScript GetScriptForStakeDelegationLOF(const CKeyID &stakingKey, const CKeyID &spendingKey)
Definition: standard.cpp:301
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:90
std::vector< unsigned char > valtype
Definition: standard.cpp:12
const char * GetTxnOutputType(txnouttype t)
Definition: standard.cpp:18
unsigned nMaxDatacarrierBytes
Definition: standard.cpp:14
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: standard.cpp:286
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:329
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:162
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
txnouttype
Definition: standard.h:46
@ TX_PUBKEYHASH
Definition: standard.h:50
@ TX_PUBKEY
Definition: standard.h:49
@ TX_NULL_DATA
Definition: standard.h:53
@ TX_COLDSTAKE
Definition: standard.h:54
@ TX_SCRIPTHASH
Definition: standard.h:51
@ TX_NONSTANDARD
Definition: standard.h:47
@ TX_MULTISIG
Definition: standard.h:52
@ TX_EXCHANGEADDR
Definition: standard.h:55