Bitcoin Core  27.99.0
P2P Digital Currency
script.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2022 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/solver.h>
20 #include <streams.h>
22 #include <test/fuzz/fuzz.h>
23 #include <test/fuzz/util.h>
24 #include <univalue.h>
25 #include <util/chaintype.h>
26 
27 #include <algorithm>
28 #include <cassert>
29 #include <cstdint>
30 #include <optional>
31 #include <string>
32 #include <vector>
33 
35 {
37 }
38 
40 {
41  FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
42  const CScript script{ConsumeScript(fuzzed_data_provider)};
43 
44  CompressedScript compressed;
45  if (CompressScript(script, compressed)) {
46  const unsigned int size = compressed[0];
47  compressed.erase(compressed.begin());
48  assert(size <= 5);
49  CScript decompressed_script;
50  const bool ok = DecompressScript(decompressed_script, size, compressed);
51  assert(ok);
52  assert(script == decompressed_script);
53  }
54 
55  TxoutType which_type;
56  bool is_standard_ret = IsStandard(script, std::nullopt, which_type);
57  if (!is_standard_ret) {
58  assert(which_type == TxoutType::NONSTANDARD ||
59  which_type == TxoutType::NULL_DATA ||
60  which_type == TxoutType::MULTISIG);
61  }
62  if (which_type == TxoutType::NONSTANDARD) {
63  assert(!is_standard_ret);
64  }
65  if (which_type == TxoutType::NULL_DATA) {
66  assert(script.IsUnspendable());
67  }
68  if (script.IsUnspendable()) {
69  assert(which_type == TxoutType::NULL_DATA ||
70  which_type == TxoutType::NONSTANDARD);
71  }
72 
73  CTxDestination address;
74  bool extract_destination_ret = ExtractDestination(script, address);
75  if (!extract_destination_ret) {
76  assert(which_type == TxoutType::PUBKEY ||
77  which_type == TxoutType::NONSTANDARD ||
78  which_type == TxoutType::NULL_DATA ||
79  which_type == TxoutType::MULTISIG);
80  }
81  if (which_type == TxoutType::NONSTANDARD ||
82  which_type == TxoutType::NULL_DATA ||
83  which_type == TxoutType::MULTISIG) {
84  assert(!extract_destination_ret);
85  }
86 
87  const FlatSigningProvider signing_provider;
88  (void)InferDescriptor(script, signing_provider);
89  (void)IsSegWitOutput(signing_provider, script);
90 
91  (void)RecursiveDynamicUsage(script);
92 
93  std::vector<std::vector<unsigned char>> solutions;
94  (void)Solver(script, solutions);
95 
96  (void)script.HasValidOps();
97  (void)script.IsPayToScriptHash();
98  (void)script.IsPayToWitnessScriptHash();
99  (void)script.IsPushOnly();
100  (void)script.GetSigOpCount(/* fAccurate= */ false);
101 
102  {
103  const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
104  CompressedScript compressed_script;
105  compressed_script.assign(bytes.begin(), bytes.end());
106  // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
107  if (compressed_script.size() >= 32) {
108  CScript decompressed_script;
109  DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script);
110  }
111  }
112 
113  const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
114  if (other_script) {
115  {
116  CScript script_mut{script};
117  (void)FindAndDelete(script_mut, *other_script);
118  }
119  const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
120  const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
121  const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
122  {
123  CScriptWitness wit;
124  for (const auto& s : random_string_vector) {
125  wit.stack.emplace_back(s.begin(), s.end());
126  }
127  (void)CountWitnessSigOps(script, *other_script, &wit, flags);
128  wit.SetNull();
129  }
130  }
131 
132  (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider));
133  (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT)));
134 
135  {
136  const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
137  CScript append_script{bytes.begin(), bytes.end()};
138  append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
139  append_script << ConsumeOpcodeType(fuzzed_data_provider);
140  append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
141  append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
142  }
143 
144  {
145  const CTxDestination tx_destination_1{
146  fuzzed_data_provider.ConsumeBool() ?
147  DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) :
148  ConsumeTxDestination(fuzzed_data_provider)};
149  const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)};
150  const std::string encoded_dest{EncodeDestination(tx_destination_1)};
151  const UniValue json_dest{DescribeAddress(tx_destination_1)};
152  (void)GetKeyForDestination(/*store=*/{}, tx_destination_1);
153  const CScript dest{GetScriptForDestination(tx_destination_1)};
154  const bool valid{IsValidDestination(tx_destination_1)};
155 
156  if (!std::get_if<PubKeyDestination>(&tx_destination_1)) {
157  // Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding
158  Assert(dest.empty() != valid);
159  Assert(tx_destination_1 == DecodeDestination(encoded_dest));
160  Assert(valid == IsValidDestinationString(encoded_dest));
161  }
162 
163  (void)(tx_destination_1 < tx_destination_2);
164  if (tx_destination_1 == tx_destination_2) {
165  Assert(encoded_dest == EncodeDestination(tx_destination_2));
166  Assert(json_dest.write() == DescribeAddress(tx_destination_2).write());
167  Assert(dest == GetScriptForDestination(tx_destination_2));
168  }
169  }
170 }
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
Definition: addresstype.cpp:49
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:131
int flags
Definition: bitcoin-tx.cpp:530
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain type.
#define Assert(val)
Identity function.
Definition: check.h:77
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
std::string ConsumeRandomLengthString(size_t max_length)
T ConsumeIntegralInRange(T min, T max)
Implements a drop-in replacement for std::vector<T> which stores up to N elements directly (without h...
Definition: prevector.h:37
size_type size() const
Definition: prevector.h:296
iterator erase(iterator pos)
Definition: prevector.h:415
iterator begin()
Definition: prevector.h:304
void assign(size_type n, const T &val)
Definition: prevector.h:225
bool DecompressScript(CScript &script, unsigned int nSize, const CompressedScript &in)
Definition: compressor.cpp:95
bool CompressScript(const CScript &script, CompressedScript &out)
Definition: compressor.cpp:55
static size_t RecursiveDynamicUsage(const CScript &script)
Definition: core_memusage.h:12
unsigned int u32
int FindAndDelete(CScript &script, const CScript &b)
size_t CountWitnessSigOps(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, unsigned int flags)
@ SCRIPT_VERIFY_P2SH
Definition: interpreter.h:49
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: key_io.cpp:303
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition: key_io.cpp:292
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:287
bool IsStandard(const CScript &scriptPubKey, const std::optional< unsigned > &max_datacarrier_bytes, TxoutType &whichType)
Definition: policy.cpp:70
UniValue DescribeAddress(const CTxDestination &dest)
Definition: util.cpp:329
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
std::string GetOpName(opcodetype opcode)
Definition: script.cpp:18
std::string ScriptErrorString(const ScriptError serror)
enum ScriptError_t ScriptError
@ SCRIPT_ERR_ERROR_COUNT
Definition: script_error.h:85
bool IsSegWitOutput(const SigningProvider &provider, const CScript &script)
Check whether a scriptPubKey is known to be segwit.
Definition: sign.cpp:765
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: solver.cpp:140
TxoutType
Definition: solver.h:22
@ NULL_DATA
unspendable OP_RETURN script that carries data
std::vector< std::vector< unsigned char > > stack
Definition: script.h:569
void SetNull()
Definition: script.h:576
FUZZ_TARGET(script,.init=initialize_script)
Definition: script.cpp:39
void initialize_script()
Definition: script.cpp:34
CScript ConsumeScript(FuzzedDataProvider &fuzzed_data_provider, const bool maybe_p2wsh) noexcept
Definition: util.cpp:93
CTxDestination ConsumeTxDestination(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.cpp:184
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:78
std::vector< B > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:57
opcodetype ConsumeOpcodeType(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.h:138
assert(!tx.IsCoinBase())