Bitcoin Core  22.99.0
P2P Digital Currency
script.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2021 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <chainparams.h>
6 #include <compressor.h>
7 #include <core_io.h>
8 #include <core_memusage.h>
9 #include <key_io.h>
10 #include <policy/policy.h>
11 #include <pubkey.h>
12 #include <rpc/util.h>
13 #include <script/descriptor.h>
14 #include <script/interpreter.h>
15 #include <script/script.h>
16 #include <script/script_error.h>
17 #include <script/sign.h>
18 #include <script/signingprovider.h>
19 #include <script/standard.h>
20 #include <streams.h>
22 #include <test/fuzz/fuzz.h>
23 #include <test/fuzz/util.h>
24 #include <univalue.h>
25 
26 #include <algorithm>
27 #include <cassert>
28 #include <cstdint>
29 #include <optional>
30 #include <string>
31 #include <vector>
32 
34 {
35  // Fuzzers using pubkey must hold an ECCVerifyHandle.
36  static const ECCVerifyHandle verify_handle;
37 
39 }
40 
42 {
43  FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
44  const std::optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider);
45  if (!script_opt) return;
46  const CScript script{*script_opt};
47 
48  CompressedScript compressed;
49  if (CompressScript(script, compressed)) {
50  const unsigned int size = compressed[0];
51  compressed.erase(compressed.begin());
52  assert(size <= 5);
53  CScript decompressed_script;
54  const bool ok = DecompressScript(decompressed_script, size, compressed);
55  assert(ok);
56  assert(script == decompressed_script);
57  }
58 
59  CTxDestination address;
60  TxoutType type_ret;
61  std::vector<CTxDestination> addresses;
62  int required_ret;
63  bool extract_destinations_ret = ExtractDestinations(script, type_ret, addresses, required_ret);
64  bool extract_destination_ret = ExtractDestination(script, address);
65  if (!extract_destinations_ret) {
66  assert(!extract_destination_ret);
67  if (type_ret == TxoutType::MULTISIG) {
68  assert(addresses.empty() && required_ret == 0);
69  } else {
70  assert(type_ret == TxoutType::PUBKEY ||
71  type_ret == TxoutType::NONSTANDARD ||
72  type_ret == TxoutType::NULL_DATA);
73  }
74  } else {
75  assert(required_ret >= 1 && required_ret <= 16);
76  assert((unsigned long)required_ret == addresses.size());
77  assert(type_ret == TxoutType::MULTISIG || required_ret == 1);
78  }
79  if (type_ret == TxoutType::NONSTANDARD || type_ret == TxoutType::NULL_DATA) {
80  assert(!extract_destinations_ret);
81  }
82  if (!extract_destination_ret) {
83  assert(type_ret == TxoutType::PUBKEY ||
84  type_ret == TxoutType::NONSTANDARD ||
85  type_ret == TxoutType::NULL_DATA ||
86  type_ret == TxoutType::MULTISIG);
87  } else {
88  assert(address == addresses[0]);
89  }
90  if (type_ret == TxoutType::NONSTANDARD ||
91  type_ret == TxoutType::NULL_DATA ||
92  type_ret == TxoutType::MULTISIG) {
93  assert(!extract_destination_ret);
94  }
95 
96  TxoutType which_type;
97  bool is_standard_ret = IsStandard(script, which_type);
98  assert(type_ret == which_type);
99  if (!is_standard_ret) {
100  assert(which_type == TxoutType::NONSTANDARD ||
101  which_type == TxoutType::NULL_DATA ||
102  which_type == TxoutType::MULTISIG);
103  }
104  if (which_type == TxoutType::NONSTANDARD) {
105  assert(!is_standard_ret);
106  }
107  if (which_type == TxoutType::NULL_DATA) {
108  assert(script.IsUnspendable());
109  }
110  if (script.IsUnspendable()) {
111  assert(which_type == TxoutType::NULL_DATA ||
112  which_type == TxoutType::NONSTANDARD);
113  }
114 
115  const FlatSigningProvider signing_provider;
116  (void)InferDescriptor(script, signing_provider);
117  (void)IsSegWitOutput(signing_provider, script);
118  (void)IsSolvable(signing_provider, script);
119 
120  (void)RecursiveDynamicUsage(script);
121 
122  std::vector<std::vector<unsigned char>> solutions;
123  (void)Solver(script, solutions);
124 
125  (void)script.HasValidOps();
126  (void)script.IsPayToScriptHash();
127  (void)script.IsPayToWitnessScriptHash();
128  (void)script.IsPushOnly();
129  (void)script.GetSigOpCount(/* fAccurate= */ false);
130 
131  (void)FormatScript(script);
132  (void)ScriptToAsmStr(script, false);
133  (void)ScriptToAsmStr(script, true);
134 
136  ScriptPubKeyToUniv(script, o1, true, true);
137  ScriptPubKeyToUniv(script, o1, true, false);
139  ScriptPubKeyToUniv(script, o2, false, true);
140  ScriptPubKeyToUniv(script, o2, false, false);
142  ScriptToUniv(script, o3, true);
144  ScriptToUniv(script, o4, false);
145 
146  {
147  const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
148  CompressedScript compressed_script;
149  compressed_script.assign(bytes.begin(), bytes.end());
150  // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
151  if (compressed_script.size() >= 32) {
152  CScript decompressed_script;
153  DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script);
154  }
155  }
156 
157  const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
158  if (other_script) {
159  {
160  CScript script_mut{script};
161  (void)FindAndDelete(script_mut, *other_script);
162  }
163  const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
164  const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
165  const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
166  {
167  CScriptWitness wit;
168  for (const auto& s : random_string_vector) {
169  wit.stack.emplace_back(s.begin(), s.end());
170  }
171  (void)CountWitnessSigOps(script, *other_script, &wit, flags);
172  wit.SetNull();
173  }
174  }
175 
176  (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider));
177  (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT)));
178 
179  {
180  const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
181  CScript append_script{bytes.begin(), bytes.end()};
182  append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
183  append_script << ConsumeOpcodeType(fuzzed_data_provider);
184  append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
185  append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
186  }
187 
188  {
189  const CTxDestination tx_destination_1{
190  fuzzed_data_provider.ConsumeBool() ?
191  DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) :
192  ConsumeTxDestination(fuzzed_data_provider)};
193  const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)};
194  const std::string encoded_dest{EncodeDestination(tx_destination_1)};
195  const UniValue json_dest{DescribeAddress(tx_destination_1)};
196  Assert(tx_destination_1 == DecodeDestination(encoded_dest));
197  (void)GetKeyForDestination(/* store */ {}, tx_destination_1);
198  const CScript dest{GetScriptForDestination(tx_destination_1)};
199  const bool valid{IsValidDestination(tx_destination_1)};
200  Assert(dest.empty() != valid);
201 
202  Assert(valid == IsValidDestinationString(encoded_dest));
203 
204  (void)(tx_destination_1 < tx_destination_2);
205  if (tx_destination_1 == tx_destination_2) {
206  Assert(encoded_dest == EncodeDestination(tx_destination_2));
207  Assert(json_dest.write() == DescribeAddress(tx_destination_2).write());
208  Assert(dest == GetScriptForDestination(tx_destination_2));
209  }
210  }
211 }
ScriptErrorString
std::string ScriptErrorString(const ScriptError serror)
Definition: script_error.cpp:10
ConsumeRandomLengthStringVector
std::vector< std::string > ConsumeRandomLengthStringVector(FuzzedDataProvider &fuzzed_data_provider, const size_t max_vector_size=16, const size_t max_string_length=16) noexcept
Definition: util.h:79
ScriptToUniv
void ScriptToUniv(const CScript &script, UniValue &out, bool include_address)
Definition: core_write.cpp:144
CountWitnessSigOps
size_t CountWitnessSigOps(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, unsigned int flags)
Definition: interpreter.cpp:2106
policy.h
FindAndDelete
int FindAndDelete(CScript &script, const CScript &b)
Definition: interpreter.cpp:253
UniValue::VOBJ
@ VOBJ
Definition: univalue.h:21
assert
assert(!tx.IsCoinBase())
Solver
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:144
IsStandard
bool IsStandard(const CScript &scriptPubKey, TxoutType &whichType)
Definition: policy.cpp:53
TxoutType
TxoutType
Definition: standard.h:59
flags
int flags
Definition: bitcoin-tx.cpp:513
key_io.h
streams.h
TxoutType::NONSTANDARD
@ NONSTANDARD
prevector::erase
iterator erase(iterator pos)
Definition: prevector.h:401
GetScriptForDestination
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:351
GetOpName
std::string GetOpName(opcodetype opcode)
Definition: script.cpp:12
util.h
FuzzedDataProvider::ConsumeRandomLengthString
std::string ConsumeRandomLengthString(size_t max_length)
Definition: FuzzedDataProvider.h:152
interpreter.h
FormatScript
std::string FormatScript(const CScript &script)
Definition: core_write.cpp:33
pubkey.h
chainparams.h
core_io.h
ConsumeOpcodeType
opcodetype ConsumeOpcodeType(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.h:122
Assert
#define Assert(val)
Identity function.
Definition: check.h:57
ConsumeTxDestination
CTxDestination ConsumeTxDestination(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.cpp:309
UniValue
Definition: univalue.h:19
ScriptError
enum ScriptError_t ScriptError
compressor.h
CScriptWitness
Definition: script.h:557
CScriptNum
Definition: script.h:219
signingprovider.h
initialize_script
void initialize_script()
Definition: script.cpp:33
RecursiveDynamicUsage
static size_t RecursiveDynamicUsage(const CScript &script)
Definition: core_memusage.h:12
TxoutType::PUBKEY
@ PUBKEY
CTxDestination
std::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:157
IsValidDestination
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:373
CompressScript
bool CompressScript(const CScript &script, CompressedScript &out)
Definition: compressor.cpp:55
IsSegWitOutput
bool IsSegWitOutput(const SigningProvider &provider, const CScript &script)
Check whether a scriptPubKey is known to be segwit.
Definition: sign.cpp:599
univalue.h
CBaseChainParams::REGTEST
static const std::string REGTEST
Definition: chainparamsbase.h:25
FuzzedDataProvider.h
sign.h
DescribeAddress
UniValue DescribeAddress(const CTxDestination &dest)
Definition: util.cpp:324
ConsumeRandomLengthByteVector
std::vector< uint8_t > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:61
standard.h
GetKeyForDestination
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
Definition: signingprovider.cpp:191
SelectParams
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given chain name.
Definition: chainparams.cpp:555
DecodeDestination
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg)
Definition: key_io.cpp:261
CScript
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:405
script.h
ExtractDestination
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:213
TxoutType::NULL_DATA
@ NULL_DATA
unspendable OP_RETURN script that carries data
prevector
Implements a drop-in replacement for std::vector<T> which stores up to N elements directly (without h...
Definition: prevector.h:37
prevector::assign
void assign(size_type n, const T &val)
Definition: prevector.h:218
core_memusage.h
ECCVerifyHandle
Users of this module must hold an ECCVerifyHandle.
Definition: pubkey.h:315
CScriptWitness::SetNull
void SetNull()
Definition: script.h:568
IsSolvable
bool IsSolvable(const SigningProvider &provider, const CScript &script)
Definition: sign.cpp:580
fuzz.h
script_error.h
FuzzedDataProvider
Definition: FuzzedDataProvider.h:31
FuzzedDataProvider::ConsumeIntegral
T ConsumeIntegral()
Definition: FuzzedDataProvider.h:194
SCRIPT_VERIFY_P2SH
@ SCRIPT_VERIFY_P2SH
Definition: interpreter.h:46
prevector::size
size_type size() const
Definition: prevector.h:282
prevector::begin
iterator begin()
Definition: prevector.h:290
TxoutType::MULTISIG
@ MULTISIG
ScriptPubKeyToUniv
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex, bool include_addresses)
Definition: core_write.cpp:161
IsValidDestinationString
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: key_io.cpp:272
FUZZ_TARGET_INIT
FUZZ_TARGET_INIT(script, initialize_script)
Definition: script.cpp:41
util.h
FuzzedDataProvider::ConsumeBool
bool ConsumeBool()
Definition: FuzzedDataProvider.h:288
InferDescriptor
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
Definition: descriptor.cpp:1412
ExtractDestinations
bool ExtractDestinations(const CScript &scriptPubKey, TxoutType &typeRet, std::vector< CTxDestination > &addressRet, int &nRequiredRet)
Parse a standard scriptPubKey with one or more destination addresses.
Definition: standard.cpp:270
DecompressScript
bool DecompressScript(CScript &script, unsigned int nSize, const CompressedScript &in)
Definition: compressor.cpp:95
FuzzedDataProvider::ConsumeIntegralInRange
T ConsumeIntegralInRange(T min, T max)
Definition: FuzzedDataProvider.h:204
EncodeDestination
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:256
ScriptToAsmStr
std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode=false)
Create the assembly string representation of a CScript object.
Definition: core_write.cpp:92
CScriptWitness::stack
std::vector< std::vector< unsigned char > > stack
Definition: script.h:561
FlatSigningProvider
Definition: signingprovider.h:73
descriptor.h
SCRIPT_ERR_ERROR_COUNT
@ SCRIPT_ERR_ERROR_COUNT
Definition: script_error.h:85