* Consume a Miniscript node from the fuzzer's output. * * This is similar to ConsumeNodeStable, but uses a precomputed table with permitted * fragments/subnode type for each required type. It is intended to more quickly explore * interesting miniscripts, at the cost of higher implementation complexity (which could * cause it miss things if incorrect), and with less regard for stability of the
| 769 | * everything). |
| 770 | */ |
| 771 | std::optional<NodeInfo> ConsumeNodeSmart(MsCtx script_ctx, FuzzedDataProvider& provider, Type type_needed) { |
| 772 | /** Table entry for the requested type. */ |
| 773 | const auto& table{IsTapscript(script_ctx) ? SMARTINFO.tap_table : SMARTINFO.wsh_table}; |
| 774 | auto recipes_it = table.find(type_needed); |
| 775 | assert(recipes_it != table.end()); |
| 776 | /** Pick one recipe from the available ones for that type. */ |
| 777 | const auto& [frag, subt] = PickValue(provider, recipes_it->second); |
| 778 | |
| 779 | // Based on the fragment the recipe uses, fill in other data (k, keys, data). |
| 780 | switch (frag) { |
| 781 | case Fragment::PK_K: |
| 782 | case Fragment::PK_H: |
| 783 | return {{frag, ConsumePubKey(provider)}}; |
| 784 | case Fragment::MULTI: { |
| 785 | const auto n_keys = provider.ConsumeIntegralInRange<uint8_t>(1, 20); |
| 786 | const auto k = provider.ConsumeIntegralInRange<uint8_t>(1, n_keys); |
| 787 | std::vector<CPubKey> keys{n_keys}; |
| 788 | for (auto& key: keys) key = ConsumePubKey(provider); |
| 789 | return {{frag, k, std::move(keys)}}; |
| 790 | } |
| 791 | case Fragment::MULTI_A: { |
| 792 | const auto n_keys = provider.ConsumeIntegralInRange<uint16_t>(1, 999); |
| 793 | const auto k = provider.ConsumeIntegralInRange<uint16_t>(1, n_keys); |
| 794 | std::vector<CPubKey> keys{n_keys}; |
| 795 | for (auto& key: keys) key = ConsumePubKey(provider); |
| 796 | return {{frag, k, std::move(keys)}}; |
| 797 | } |
| 798 | case Fragment::OLDER: |
| 799 | case Fragment::AFTER: |
| 800 | return {{frag, provider.ConsumeIntegralInRange<uint32_t>(1, 0x7FFFFFF)}}; |
| 801 | case Fragment::SHA256: |
| 802 | return {{frag, PickValue(provider, TEST_DATA.sha256)}}; |
| 803 | case Fragment::HASH256: |
| 804 | return {{frag, PickValue(provider, TEST_DATA.hash256)}}; |
| 805 | case Fragment::RIPEMD160: |
| 806 | return {{frag, PickValue(provider, TEST_DATA.ripemd160)}}; |
| 807 | case Fragment::HASH160: |
| 808 | return {{frag, PickValue(provider, TEST_DATA.hash160)}}; |
| 809 | case Fragment::JUST_0: |
| 810 | case Fragment::JUST_1: |
| 811 | case Fragment::WRAP_A: |
| 812 | case Fragment::WRAP_S: |
| 813 | case Fragment::WRAP_C: |
| 814 | case Fragment::WRAP_D: |
| 815 | case Fragment::WRAP_V: |
| 816 | case Fragment::WRAP_J: |
| 817 | case Fragment::WRAP_N: |
| 818 | case Fragment::AND_V: |
| 819 | case Fragment::AND_B: |
| 820 | case Fragment::OR_B: |
| 821 | case Fragment::OR_C: |
| 822 | case Fragment::OR_D: |
| 823 | case Fragment::OR_I: |
| 824 | case Fragment::ANDOR: |
| 825 | return {{subt, frag}}; |
| 826 | case Fragment::THRESH: { |
| 827 | uint32_t children; |
| 828 | if (subt.size() < 2) { |
no test coverage detected