@@ -767,6 +767,8 @@ NodeRef GenNode(F ConsumeNode, Type root_type, bool strict_valid = false) {
767767 std::vector<NodeRef> stack;
768768 /* * The queue of instructions. */
769769 std::vector<std::pair<Type, std::optional<NodeInfo>>> todo{{root_type, {}}};
770+ /* * Predict the number of (static) script ops. */
771+ uint32_t ops{0 };
770772
771773 while (!todo.empty ()) {
772774 // The expected type we have to construct.
@@ -775,6 +777,72 @@ NodeRef GenNode(F ConsumeNode, Type root_type, bool strict_valid = false) {
775777 // Fragment/children have not been decided yet. Decide them.
776778 auto node_info = ConsumeNode (type_needed);
777779 if (!node_info) return {};
780+ // Update predicted resource limits.
781+ switch (node_info->fragment ) {
782+ case Fragment::JUST_0:
783+ case Fragment::JUST_1:
784+ break ;
785+ case Fragment::PK_K:
786+ break ;
787+ case Fragment::PK_H:
788+ ops += 3 ;
789+ break ;
790+ case Fragment::OLDER:
791+ case Fragment::AFTER:
792+ ops += 1 ;
793+ break ;
794+ case Fragment::RIPEMD160:
795+ case Fragment::SHA256:
796+ case Fragment::HASH160:
797+ case Fragment::HASH256:
798+ ops += 4 ;
799+ break ;
800+ case Fragment::ANDOR:
801+ ops += 3 ;
802+ break ;
803+ case Fragment::AND_V:
804+ break ;
805+ case Fragment::AND_B:
806+ case Fragment::OR_B:
807+ ops += 1 ;
808+ break ;
809+ case Fragment::OR_C:
810+ ops += 2 ;
811+ break ;
812+ case Fragment::OR_D:
813+ ops += 3 ;
814+ break ;
815+ case Fragment::OR_I:
816+ ops += 3 ;
817+ break ;
818+ case Fragment::THRESH:
819+ ops += node_info->subtypes .size ();
820+ break ;
821+ case Fragment::MULTI:
822+ ops += 1 ;
823+ break ;
824+ case Fragment::WRAP_A:
825+ ops += 2 ;
826+ break ;
827+ case Fragment::WRAP_S:
828+ ops += 1 ;
829+ break ;
830+ case Fragment::WRAP_C:
831+ ops += 1 ;
832+ break ;
833+ case Fragment::WRAP_D:
834+ ops += 3 ;
835+ break ;
836+ case Fragment::WRAP_V:
837+ break ;
838+ case Fragment::WRAP_J:
839+ ops += 4 ;
840+ break ;
841+ case Fragment::WRAP_N:
842+ ops += 1 ;
843+ break ;
844+ }
845+ if (ops > MAX_OPS_PER_SCRIPT) return {};
778846 auto subtypes = node_info->subtypes ;
779847 todo.back ().second = std::move (node_info);
780848 todo.reserve (todo.size () + subtypes.size ());
@@ -814,12 +882,18 @@ NodeRef GenNode(F ConsumeNode, Type root_type, bool strict_valid = false) {
814882 assert (node->GetType () << type_needed);
815883 }
816884 if (!node->IsValid ()) return {};
885+ // Update resource predictions.
886+ if (node->fragment == Fragment::WRAP_V && node->subs [0 ]->GetType () << " x" _mst) {
887+ ops += 1 ;
888+ }
889+ if (ops > MAX_OPS_PER_SCRIPT) return {};
817890 // Move it to the stack.
818891 stack.push_back (std::move (node));
819892 todo.pop_back ();
820893 }
821894 }
822895 assert (stack.size () == 1 );
896+ assert (stack[0 ]->GetStaticOps () == ops);
823897 stack[0 ]->DuplicateKeyCheck (KEY_COMP);
824898 return std::move (stack[0 ]);
825899}
0 commit comments