Bitcoin ABC 0.34.2
P2P Digital Currency
solver.cpp
Go to the documentation of this file.
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.
5
6#include <script/solver.h>
7
8#include <script/script.h>
9
10#include <string>
11
12typedef std::vector<uint8_t> valtype;
13
15 switch (t) {
17 return "nonstandard";
19 return "pubkey";
21 return "pubkeyhash";
23 return "scripthash";
25 return "multisig";
27 return "nulldata";
28 } // no default case, so the compiler can warn about missing cases
29 assert(false);
30}
31
32static bool MatchPayToPubkey(const CScript &script, valtype &pubkey) {
33 if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE &&
34 script.back() == OP_CHECKSIG) {
35 pubkey =
36 valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1);
37 return CPubKey::ValidSize(pubkey);
38 }
39 if (script.size() == CPubKey::COMPRESSED_SIZE + 2 &&
41 pubkey = valtype(script.begin() + 1,
42 script.begin() + CPubKey::COMPRESSED_SIZE + 1);
43 return CPubKey::ValidSize(pubkey);
44 }
45 return false;
46}
47
48static bool MatchPayToPubkeyHash(const CScript &script, valtype &pubkeyhash) {
49 if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 &&
50 script[2] == 20 && script[23] == OP_EQUALVERIFY &&
51 script[24] == OP_CHECKSIG) {
52 pubkeyhash = valtype(script.begin() + 3, script.begin() + 23);
53 return true;
54 }
55 return false;
56}
57
59static constexpr bool IsSmallInteger(opcodetype opcode) {
60 return opcode >= OP_1 && opcode <= OP_16;
61}
62
63static bool MatchMultisig(const CScript &script, unsigned int &required,
64 std::vector<valtype> &pubkeys) {
65 opcodetype opcode;
66 valtype data;
68 if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) {
69 return false;
70 }
71
72 if (!script.GetOp(it, opcode, data) || !IsSmallInteger(opcode)) {
73 return false;
74 }
75 required = CScript::DecodeOP_N(opcode);
76 while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
77 if (opcode < 0 || opcode > OP_PUSHDATA4 ||
78 !CheckMinimalPush(data, opcode)) {
79 return false;
80 }
81 pubkeys.emplace_back(std::move(data));
82 }
83 if (!IsSmallInteger(opcode)) {
84 return false;
85 }
86 unsigned int keys = CScript::DecodeOP_N(opcode);
87 if (pubkeys.size() != keys || keys < required) {
88 return false;
89 }
90 return (it + 1 == script.end());
91}
92
93TxoutType Solver(const CScript &scriptPubKey,
94 std::vector<std::vector<uint8_t>> &vSolutionsRet) {
95 vSolutionsRet.clear();
96
97 // Shortcut for pay-to-script-hash, which are more constrained than the
98 // other types:
99 // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
100 if (scriptPubKey.IsPayToScriptHash()) {
101 std::vector<uint8_t> hashBytes(scriptPubKey.begin() + 2,
102 scriptPubKey.begin() + 22);
103 vSolutionsRet.push_back(hashBytes);
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 &&
113 scriptPubKey.IsPushOnly(scriptPubKey.begin() + 1)) {
115 }
116
117 std::vector<uint8_t> data;
118 if (MatchPayToPubkey(scriptPubKey, data)) {
119 vSolutionsRet.push_back(std::move(data));
120 return TxoutType::PUBKEY;
121 }
122
123 if (MatchPayToPubkeyHash(scriptPubKey, data)) {
124 vSolutionsRet.push_back(std::move(data));
126 }
127
128 unsigned int required;
129 std::vector<std::vector<uint8_t>> keys;
130 if (MatchMultisig(scriptPubKey, required, keys)) {
131 // safe as required is in range 1..16
132 vSolutionsRet.push_back({static_cast<uint8_t>(required)});
133 vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
134 // safe as size is in range 1..16
135 vSolutionsRet.push_back({static_cast<uint8_t>(keys.size())});
136 return TxoutType::MULTISIG;
137 }
138
139 vSolutionsRet.clear();
141}
142
144 return CScript() << std::vector<uint8_t>(pubKey.begin(), pubKey.end())
145 << OP_CHECKSIG;
146}
147
148CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey> &keys) {
150
151 script << CScript::EncodeOP_N(nRequired);
152 for (const CPubKey &key : keys) {
153 script << ToByteVector(key);
154 }
156 return script;
157}
std::vector< uint8_t > valtype
Definition: addresstype.cpp:16
An encapsulated public key.
Definition: pubkey.h:31
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:37
const uint8_t * end() const
Definition: pubkey.h:101
static constexpr unsigned int SIZE
secp256k1:
Definition: pubkey.h:36
static bool ValidSize(const std::vector< uint8_t > &vch)
Definition: pubkey.h:70
const uint8_t * begin() const
Definition: pubkey.h:100
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:434
bool IsPushOnly(const_iterator pc) const
Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
Definition: script.cpp:407
bool IsPayToScriptHash() const
Definition: script.cpp:376
static int DecodeOP_N(opcodetype opcode)
Encode/decode small integers:
Definition: script.h:515
static opcodetype EncodeOP_N(int n)
Definition: script.h:523
size_type size() const
Definition: prevector.h:398
iterator begin()
Definition: prevector.h:402
bool CheckMinimalPush(const std::vector< uint8_t > &data, opcodetype opcode)
Check whether the given stack element data would be minimally pushed using the given opcode.
Definition: script.cpp:271
opcodetype
Script opcodes.
Definition: script.h:53
@ OP_PUSHDATA4
Definition: script.h:59
@ OP_CHECKMULTISIG
Definition: script.h:171
@ OP_CHECKSIG
Definition: script.h:169
@ OP_16
Definition: script.h:78
@ OP_DUP
Definition: script.h:104
@ OP_HASH160
Definition: script.h:166
@ OP_1
Definition: script.h:62
@ OP_RETURN
Definition: script.h:90
@ OP_EQUALVERIFY
Definition: script.h:126
std::vector< uint8_t > ToByteVector(const T &in)
Definition: script.h:48
std::vector< uint8_t > valtype
Definition: solver.cpp:12
static bool MatchPayToPubkeyHash(const CScript &script, valtype &pubkeyhash)
Definition: solver.cpp:48
static constexpr bool IsSmallInteger(opcodetype opcode)
Test for "small positive integer" script opcodes - OP_1 through OP_16.
Definition: solver.cpp:59
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: solver.cpp:148
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< uint8_t > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: solver.cpp:93
std::string GetTxnOutputType(TxoutType t)
Get the name of a TxoutType as a string.
Definition: solver.cpp:14
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: solver.cpp:143
static bool MatchPayToPubkey(const CScript &script, valtype &pubkey)
Definition: solver.cpp:32
static bool MatchMultisig(const CScript &script, unsigned int &required, std::vector< valtype > &pubkeys)
Definition: solver.cpp:63
TxoutType
Definition: solver.h:15
assert(!tx.IsCoinBase())