private static EOFLayout parseEOF(final EOFParseStep step, final Queue<EOFParseStep> queue) {
    final ByteArrayInputStream inputStream =
        new ByteArrayInputStream(step.container.toArrayUnsafe());

    if (inputStream.available() < 3) {
      return invalidLayout(step.container, -1, "invalid_magic EOF Container too small");
    }
    if (inputStream.read() != 0xEF) {
      return invalidLayout(step.container, -1, "invalid_magic EOF header byte 0 incorrect");
    }
    if (inputStream.read() != 0x0) {
      return invalidLayout(step.container, -1, "invalid_magic EOF header byte 1 incorrect");
    }

    final int version = inputStream.read();
    if (version > MAX_SUPPORTED_VERSION || version < 1) {
      return invalidLayout(step.container, version, "invalid_version " + version);
    }

    String error = readKind(inputStream, SECTION_TYPES);
    if (error != null) {
      return invalidLayout(step.container, version, error);
    }
    int typesLength = readUnsignedShort(inputStream);
    if (typesLength % 4 != 0) {
      return invalidLayout(
          step.container,
          version,
          "invalid_type_section_size Invalid Types section size (mod 4 != 0)");
    }

    error = readKind(inputStream, SECTION_CODE);
    if (error != null) {
      return invalidLayout(step.container, version, error);
    }
    int codeSectionCount = readUnsignedShort(inputStream);
    if (codeSectionCount <= 0) {
      return invalidLayout(
          step.container, version, "incomplete_section_number Too few code sections");
    }
    if (codeSectionCount > 1024) {
      return invalidLayout(
          step.container,
          version,
          "too_many_code_sections - 0x" + Integer.toHexString(codeSectionCount));
    }
    if (codeSectionCount * 4 != typesLength) {
      return invalidLayout(
          step.container,
          version,
          "invalid_section_bodies_size Type section - 0x"
              + Integer.toHexString(codeSectionCount)
              + " * 4 != 0x"
              + Integer.toHexString(typesLength));
    }
    int[] codeSectionSizes = new int[codeSectionCount];
    for (int i = 0; i < codeSectionCount; i++) {
      int size = readUnsignedShort(inputStream);
      if (size <= 0) {
        return invalidLayout(step.container, version, "zero_section_size code " + i);
      }
      codeSectionSizes[i] = size;
    }

    int containerSectionCount;
    int[] containerSectionSizes;
    if (peekKind(inputStream) == SECTION_CONTAINER) {
      error = readKind(inputStream, SECTION_CONTAINER);
      if (error != null) {
        return invalidLayout(step.container, version, error);
      }
      containerSectionCount = readUnsignedShort(inputStream);
      if (containerSectionCount <= 0) {
        return invalidLayout(step.container, version, "Invalid container section count");
      }
      if (containerSectionCount > 256) {
        return invalidLayout(
            step.container,
            version,
            "too_many_containers sections - 0x" + Integer.toHexString(containerSectionCount));
      }
      containerSectionSizes = new int[containerSectionCount];
      for (int i = 0; i < containerSectionCount; i++) {
        int size = readUnsignedShort(inputStream);
        if (size <= 0) {
          return invalidLayout(
              step.container, version, "Invalid container section size for section " + i);
        }
        containerSectionSizes[i] = size;
      }
    } else {
      containerSectionCount = 0;
      containerSectionSizes = new int[0];
    }

    error = readKind(inputStream, SECTION_DATA);
    if (error != null) {
      return invalidLayout(step.container, version, error);
    }
    int dataSize = readUnsignedShort(inputStream);
    if (dataSize < 0) {
      return invalidLayout(step.container, version, "incomplete_data_header");
    }

    error = readKind(inputStream, SECTION_TERMINATOR);
    if (error != null) {
      return invalidLayout(step.container, version, error);
    }
    int[][] typeData = new int[codeSectionCount][3];
    for (int i = 0; i < codeSectionCount; i++) {
      // input stream keeps spitting out -1 if we run out of data, so no exceptions
      typeData[i][0] = inputStream.read();
      typeData[i][1] = inputStream.read();
      typeData[i][2] = readUnsignedShort(inputStream);
    }
    if (typeData[codeSectionCount - 1][2] == -1) {
      return invalidLayout(
          step.container, version, "invalid_section_bodies_size Incomplete type section");
    }
    if (typeData[0][0] != 0 || (typeData[0][1] & 0x7f) != 0) {
      return invalidLayout(
          step.container, version, "invalid_first_section_type must be zero input non-returning");
    }
    CodeSection[] codeSections = new CodeSection[codeSectionCount];
    int pos = // calculate pos in stream...
        3 // header and version
            + 3 // type header
            + 3
            + (codeSectionCount * 2) // code section size
            + 3 // data section header
            + 1 // padding
            + (codeSectionCount * 4); // type data
    if (containerSectionCount > 0) {
      pos +=
          3 // subcontainer header
              + (containerSectionCount * 2); // subcontainer sizes
    }

    for (int i = 0; i < codeSectionCount; i++) {
      int codeSectionSize = codeSectionSizes[i];
      if (inputStream.skip(codeSectionSize) != codeSectionSize) {
        return invalidLayout(
            step.container, version, "invalid_section_bodies_size code section " + i);
      }
      if (typeData[i][0] > 0x7f) {
        return invalidLayout(
            step.container,
            version,
            "inputs_outputs_num_above_limit Type data input stack too large - 0x"
                + Integer.toHexString(typeData[i][0]));
      }
      if (typeData[i][1] > 0x80) {
        return invalidLayout(
            step.container,
            version,
            "inputs_outputs_num_above_limit - 0x" + Integer.toHexString(typeData[i][1]));
      }
      if (typeData[i][2] > 0x3ff) {
        return invalidLayout(
            step.container,
            version,
            "max_stack_height_above_limit Type data max stack too large - 0x"
                + Integer.toHexString(typeData[i][2]));
      }
      codeSections[i] =
          new CodeSection(codeSectionSize, typeData[i][0], typeData[i][1], typeData[i][2], pos);
      if (i == 0 && typeData[0][1] != 0x80) {
        return invalidLayout(
            step.container,
            version,
            "invalid_first_section_type want 0x80 (non-returning flag) has " + typeData[0][1]);
      }
      pos += codeSectionSize;
    }

    EOFLayout[] subContainers = new EOFLayout[containerSectionCount];
    for (int i = 0; i < containerSectionCount; i++) {
      int subcontainerSize = containerSectionSizes[i];
      if (subcontainerSize != inputStream.skip(subcontainerSize)) {
        return invalidLayout(step.container, version, "invalid_section_bodies_size");
      }
      Bytes subcontainer = step.container.slice(pos, subcontainerSize);
      pos += subcontainerSize;
      queue.add(new EOFParseStep(subcontainer, false, i, step, subContainers));
    }

    long loadedDataCount = inputStream.skip(dataSize);
    Bytes data = step.container.slice(pos, (int) loadedDataCount);

    Bytes completeContainer;
    if (inputStream.read() != -1) {
      if (step.strictSize) {
        return invalidLayout(
            step.container, version, "invalid_section_bodies_size data after end of all sections");
      } else {
        completeContainer = step.container.slice(0, pos + dataSize);
      }
    } else {
      completeContainer = step.container;
    }
    if (step.strictSize && dataSize != data.size()) {
      return invalidLayout(
          step.container,
          version,
          "toplevel_container_truncated Truncated data section when a complete section was required");
    }

    return new EOFLayout(completeContainer, version, codeSections, subContainers, dataSize, data);
  }
Parse EOF.

@param container the container
@param strictSize Require the container to fill all bytes, a validation error will result if
    strict and excess data is in the container
@return the eof layout
evm/src/main/java/org/hyperledger/besu/evm/code/EOFLayout.java