| 341 | } |
| 342 | |
| 343 | CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const bool maybe_p2wsh) noexcept |
| 344 | { |
| 345 | CScript r_script{}; |
| 346 | { |
| 347 | // Keep a buffer of bytes to allow the fuzz engine to produce smaller |
| 348 | // inputs to generate CScripts with repeated data. |
| 349 | static constexpr unsigned MAX_BUFFER_SZ{128}; |
| 350 | std::vector<uint8_t> buffer(MAX_BUFFER_SZ, uint8_t{'a'}); |
| 351 | while (fuzzed_data_provider.ConsumeBool()) { |
| 352 | CallOneOf( |
| 353 | fuzzed_data_provider, |
| 354 | [&] { |
| 355 | // Insert byte vector directly to allow malformed or unparsable scripts |
| 356 | r_script.insert(r_script.end(), buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ)); |
| 357 | }, |
| 358 | [&] { |
| 359 | // Push a byte vector from the buffer |
| 360 | r_script << std::vector<uint8_t>{buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ)}; |
| 361 | }, |
| 362 | [&] { |
| 363 | // Push multisig |
| 364 | // There is a special case for this to aid the fuzz engine |
| 365 | // navigate the highly structured multisig format. |
| 366 | r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22); |
| 367 | int num_data{fuzzed_data_provider.ConsumeIntegralInRange(1, 22)}; |
| 368 | std::vector<uint8_t> pubkey_comp{buffer.begin(), buffer.begin() + CPubKey::COMPRESSED_SIZE}; |
| 369 | pubkey_comp.front() = fuzzed_data_provider.ConsumeIntegralInRange(2, 3); // Set first byte for GetLen() to pass |
| 370 | std::vector<uint8_t> pubkey_uncomp{buffer.begin(), buffer.begin() + CPubKey::SIZE}; |
| 371 | pubkey_uncomp.front() = fuzzed_data_provider.ConsumeIntegralInRange(4, 7); // Set first byte for GetLen() to pass |
| 372 | while (num_data--) { |
| 373 | auto& pubkey{fuzzed_data_provider.ConsumeBool() ? pubkey_uncomp : pubkey_comp}; |
| 374 | if (fuzzed_data_provider.ConsumeBool()) { |
| 375 | pubkey.back() = num_data; // Make each pubkey different |
| 376 | } |
| 377 | r_script << pubkey; |
| 378 | } |
| 379 | r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22); |
| 380 | }, |
| 381 | [&] { |
| 382 | // Mutate the buffer |
| 383 | const auto vec{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/MAX_BUFFER_SZ)}; |
| 384 | std::copy(vec.begin(), vec.end(), buffer.begin()); |
| 385 | }, |
| 386 | [&] { |
| 387 | // Push an integral |
| 388 | r_script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); |
| 389 | }, |
| 390 | [&] { |
| 391 | // Push an opcode |
| 392 | r_script << ConsumeOpcodeType(fuzzed_data_provider); |
| 393 | }, |
| 394 | [&] { |
| 395 | // Push a scriptnum |
| 396 | r_script << ConsumeScriptNum(fuzzed_data_provider); |
| 397 | }); |
| 398 | } |
| 399 | } |
| 400 | if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) { |
no test coverage detected