1#![feature(maybe_uninit_as_bytes, maybe_uninit_fill, trusted_len)]
4#![no_std]
5
6use ab_contracts_common::metadata::decode::{
7 MetadataDecoder, MetadataDecodingError, MetadataItem, MethodMetadataItem,
8 MethodsMetadataDecoder,
9};
10use ab_io_type::trivial_type::TrivialType;
11use ab_riscv_primitives::instruction::GenericBaseInstruction;
12use ab_riscv_primitives::instruction::b_64_ext::BZbc64ExtInstruction;
13use ab_riscv_primitives::instruction::m_64_ext::M64ExtInstruction;
14use ab_riscv_primitives::instruction::rv64::Rv64Instruction;
15use ab_riscv_primitives::instruction::tuples::Tuple3Instruction;
16use ab_riscv_primitives::registers::EReg;
17use core::iter;
18use core::iter::TrustedLen;
19use core::mem::MaybeUninit;
20use replace_with::replace_with_or_abort;
21use tracing::{debug, trace};
22
23pub const CONTRACT_FILE_MAGIC: [u8; 4] = *b"ABC0";
25pub type Register = EReg<u64>;
27pub type Instruction = Tuple3Instruction<
29 M64ExtInstruction<Register>,
30 BZbc64ExtInstruction<Register>,
31 Rv64Instruction<Register>,
32>;
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, TrivialType)]
36#[repr(C)]
37pub struct ContractFileHeader {
38 pub magic: [u8; 4],
40 pub read_only_section_file_size: u32,
42 pub read_only_section_memory_size: u32,
46 pub metadata_offset: u32,
48 pub metadata_size: u16,
50 pub num_methods: u16,
52 pub host_call_fn_offset: u32,
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, TrivialType)]
60#[repr(C)]
61pub struct ContractFileMethodMetadata {
62 pub offset: u32,
64 pub size: u32,
66}
67
68#[derive(Debug, Copy, Clone)]
69pub struct ContractFileMethod<'a> {
70 pub address: u32,
72 pub method_metadata_item: MethodMetadataItem<'a>,
74 pub method_metadata_bytes: &'a [u8],
80}
81
82#[derive(Debug, thiserror::Error)]
84pub enum ContractFileParseError {
85 #[error("The file is too large, must fit into `u32`: {file_size} bytes")]
87 FileTooLarge {
88 file_size: usize,
90 },
91 #[error("The file does not have a header (not enough bytes)")]
93 NoHeader,
94 #[error("The magic bytes in the header are incorrect")]
96 WrongMagicBytes,
97 #[error(
99 "The metadata section is out of bounds of the file: offset {offset}, size {size}, file \
100 size {file_size}"
101 )]
102 MetadataOutOfRange {
103 offset: u32,
105 size: u16,
107 file_size: u32,
109 },
110 #[error("Failed to decode metadata item")]
112 MetadataDecoding,
113 #[error(
115 "The file is too small: num_methods {num_methods}, read_only_section_size \
116 {read_only_section_size}, file_size {file_size}"
117 )]
118 FileTooSmall {
119 num_methods: u16,
121 read_only_section_size: u32,
123 file_size: u32,
125 },
126 #[error(
128 "Method offset is out of bounds of the file: offset {offset}, code section \
129 offset {code_section_offset} file_size {file_size}"
130 )]
131 MethodOutOfRange {
132 offset: u32,
134 code_section_offset: u32,
136 file_size: u32,
138 },
139 #[error(
141 "The host call function offset is out of bounds of the file: offset {offset}, code section \
142 offset {code_section_offset} file_size {file_size}"
143 )]
144 HostCallFnOutOfRange {
145 offset: u32,
147 code_section_offset: u32,
149 file_size: u32,
151 },
152 #[error("The host call function doesn't have auipc + jalr tailcall pattern: {first} {second}")]
154 InvalidHostCallFnPattern {
155 first: Instruction,
157 second: Instruction,
159 },
160 #[error(
162 "The read-only section file size is larger than the memory size: file_size {file_size}, \
163 memory_size {memory_size}"
164 )]
165 InvalidReadOnlySizes {
166 file_size: u32,
168 memory_size: u32,
170 },
171 #[error(
174 "There are not enough methods in the header to match the number of methods in the actual \
175 metadata: header_num_methods {header_num_methods}, metadata_method_index \
176 {metadata_method_index}"
177 )]
178 InsufficientHeaderMethods {
179 header_num_methods: u16,
181 metadata_method_index: u16,
183 },
184 #[error(
187 "The number of methods in the header {header_num_methods} does not match the number of \
188 methods in the actual metadata {metadata_num_methods}"
189 )]
190 MetadataNumMethodsMismatch {
191 header_num_methods: u16,
193 metadata_num_methods: u16,
195 },
196 #[error("Unexpected instruction encountered while parsing the code section: {instruction}")]
198 UnexpectedInstruction {
199 instruction: Instruction,
201 },
202 #[error(
204 "Unexpected trailing code bytes encountered while parsing the code section: {num_bytes} \
205 trailing bytes"
206 )]
207 UnexpectedTrailingCodeBytes {
208 num_bytes: usize,
210 },
211}
212
213impl From<MetadataDecodingError<'_>> for ContractFileParseError {
214 fn from(error: MetadataDecodingError<'_>) -> Self {
215 debug!(?error, "Failed to decode metadata item");
216 Self::MetadataDecoding
217 }
218}
219
220#[derive(Debug)]
221pub struct ContractFile<'a> {
222 read_only_section_file_size: u32,
223 read_only_section_memory_size: u32,
224 num_methods: u16,
225 bytes: &'a [u8],
226}
227
228impl<'a> ContractFile<'a> {
229 pub fn parse<CM>(
238 file_bytes: &'a [u8],
239 mut contract_method: CM,
240 ) -> Result<Self, ContractFileParseError>
241 where
242 CM: FnMut(ContractFileMethod<'a>) -> Result<(), ContractFileParseError>,
243 {
244 let file_size = u32::try_from(file_bytes.len()).map_err(|_error| {
245 ContractFileParseError::FileTooLarge {
246 file_size: file_bytes.len(),
247 }
248 })?;
249 let (header_bytes, after_header_bytes) = file_bytes
250 .split_at_checked(size_of::<ContractFileHeader>())
251 .ok_or(ContractFileParseError::NoHeader)?;
252 let header = unsafe { ContractFileHeader::read_unaligned_unchecked(header_bytes) };
254
255 if header.magic != CONTRACT_FILE_MAGIC {
256 return Err(ContractFileParseError::WrongMagicBytes);
257 }
258
259 if header.read_only_section_file_size > header.read_only_section_memory_size {
260 return Err(ContractFileParseError::InvalidReadOnlySizes {
261 file_size: header.read_only_section_file_size,
262 memory_size: header.read_only_section_memory_size,
263 });
264 }
265
266 let metadata_bytes = file_bytes
267 .get(header.metadata_offset as usize..)
268 .ok_or(ContractFileParseError::MetadataOutOfRange {
269 offset: header.metadata_offset,
270 size: header.metadata_size,
271 file_size,
272 })?
273 .get(..header.metadata_size as usize)
274 .ok_or(ContractFileParseError::MetadataOutOfRange {
275 offset: header.metadata_offset,
276 size: header.metadata_size,
277 file_size,
278 })?;
279
280 let read_only_padding_size =
281 header.read_only_section_memory_size - header.read_only_section_file_size;
282 let read_only_section_offset = ContractFileHeader::SIZE
283 + u32::from(header.num_methods) * ContractFileMethodMetadata::SIZE;
284 let code_section_offset =
285 read_only_section_offset.saturating_add(header.read_only_section_file_size);
286
287 {
288 let mut contract_file_methods_metadata_iter = {
289 let mut file_contract_metadata_bytes = after_header_bytes;
290
291 (0..header.num_methods).map(move |_| {
292 let contract_file_method_metadata_bytes = file_contract_metadata_bytes
293 .split_off(..size_of::<ContractFileMethodMetadata>())
294 .ok_or(ContractFileParseError::FileTooSmall {
295 num_methods: header.num_methods,
296 read_only_section_size: header.read_only_section_file_size,
297 file_size,
298 })?;
299 let contract_file_method_metadata = unsafe {
301 ContractFileMethodMetadata::read_unaligned_unchecked(
302 contract_file_method_metadata_bytes,
303 )
304 };
305
306 if (contract_file_method_metadata.offset + contract_file_method_metadata.size)
307 > file_size
308 {
309 return Err(ContractFileParseError::FileTooSmall {
310 num_methods: header.num_methods,
311 read_only_section_size: header.read_only_section_file_size,
312 file_size,
313 });
314 }
315
316 if contract_file_method_metadata.offset < code_section_offset {
317 return Err(ContractFileParseError::MethodOutOfRange {
318 offset: contract_file_method_metadata.offset,
319 code_section_offset,
320 file_size,
321 });
322 }
323
324 Ok(contract_file_method_metadata)
325 })
326 };
327
328 let mut metadata_num_methods = 0;
329 let mut remaining_metadata_bytes = metadata_bytes;
330 let mut metadata_decoder = MetadataDecoder::new(metadata_bytes);
331
332 while let Some(maybe_metadata_item) = metadata_decoder.decode_next() {
333 let metadata_item = maybe_metadata_item?;
334 trace!(?metadata_item, "Decoded metadata item");
335
336 let mut methods_metadata_decoder = metadata_item.into_decoder();
337 loop {
338 let Some(method_metadata_decoder) = methods_metadata_decoder.decode_next()
342 else {
343 break;
344 };
345
346 let before_remaining_bytes = method_metadata_decoder.remaining_metadata_bytes();
347 let (_, method_metadata_item) = method_metadata_decoder.decode_next()?;
348
349 trace!(?method_metadata_item, "Decoded method metadata item");
350 metadata_num_methods += 1;
351
352 let method_metadata_bytes = remaining_metadata_bytes
353 .split_off(
354 ..before_remaining_bytes
355 - methods_metadata_decoder.remaining_metadata_bytes(),
356 )
357 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
358
359 let contract_file_method_metadata = contract_file_methods_metadata_iter
360 .next()
361 .ok_or(ContractFileParseError::InsufficientHeaderMethods {
362 header_num_methods: header.num_methods,
363 metadata_method_index: metadata_num_methods - 1,
364 })??;
365 contract_method(ContractFileMethod {
366 address: contract_file_method_metadata.offset - read_only_section_offset
367 + read_only_padding_size,
368 method_metadata_item,
369 method_metadata_bytes,
370 })?;
371 }
372 }
373
374 if metadata_num_methods != header.num_methods {
375 return Err(ContractFileParseError::MetadataNumMethodsMismatch {
376 header_num_methods: header.num_methods,
377 metadata_num_methods,
378 });
379 }
380 }
381
382 if code_section_offset >= file_size {
383 return Err(ContractFileParseError::FileTooSmall {
384 num_methods: header.num_methods,
385 read_only_section_size: header.read_only_section_file_size,
386 file_size,
387 });
388 }
389
390 if header.host_call_fn_offset != 0
391 && (header.host_call_fn_offset >= file_size
392 || header.host_call_fn_offset < code_section_offset)
393 {
394 return Err(ContractFileParseError::HostCallFnOutOfRange {
395 offset: header.host_call_fn_offset,
396 code_section_offset,
397 file_size,
398 });
399 }
400
401 if header.host_call_fn_offset != 0 {
402 let instructions_bytes = file_bytes
403 .get(header.host_call_fn_offset as usize..)
404 .ok_or(ContractFileParseError::HostCallFnOutOfRange {
405 offset: header.host_call_fn_offset,
406 code_section_offset,
407 file_size,
408 })?
409 .get(..size_of::<[u32; 2]>())
410 .ok_or(ContractFileParseError::HostCallFnOutOfRange {
411 offset: header.host_call_fn_offset,
412 code_section_offset,
413 file_size,
414 })?;
415
416 let first_instruction = u32::from_le_bytes([
417 instructions_bytes[0],
418 instructions_bytes[1],
419 instructions_bytes[2],
420 instructions_bytes[3],
421 ]);
422 let second_instruction = u32::from_le_bytes([
423 instructions_bytes[4],
424 instructions_bytes[5],
425 instructions_bytes[6],
426 instructions_bytes[7],
427 ]);
428
429 let first = Instruction::decode(first_instruction);
430 let second = Instruction::decode(second_instruction);
431
432 let matches_expected_pattern = if let (
438 Instruction::Base(Rv64Instruction::Auipc {
439 rd: auipc_rd,
440 imm: _,
441 }),
442 Instruction::Base(Rv64Instruction::Jalr {
443 rd: jalr_rd,
444 rs1: jalr_rs1,
445 imm: _,
446 }),
447 ) = (first, second)
448 {
449 auipc_rd == jalr_rs1 && jalr_rd == Register::Zero
450 } else {
451 false
452 };
453
454 if !matches_expected_pattern {
455 return Err(ContractFileParseError::InvalidHostCallFnPattern { first, second });
456 }
457 }
458
459 {
461 let mut remaining_code_file_bytes = &file_bytes[code_section_offset as usize..];
462 while let Some(instruction_bytes) =
463 remaining_code_file_bytes.split_off(..size_of::<u32>())
464 {
465 let instruction = u32::from_le_bytes([
466 instruction_bytes[0],
467 instruction_bytes[1],
468 instruction_bytes[2],
469 instruction_bytes[3],
470 ]);
471 let instruction = Instruction::decode(instruction);
472 match instruction {
473 Instruction::A(_)
474 | Instruction::B(_)
475 | Instruction::Base(
476 Rv64Instruction::Add { .. }
477 | Rv64Instruction::Sub { .. }
478 | Rv64Instruction::Sll { .. }
479 | Rv64Instruction::Slt { .. }
480 | Rv64Instruction::Sltu { .. }
481 | Rv64Instruction::Xor { .. }
482 | Rv64Instruction::Srl { .. }
483 | Rv64Instruction::Sra { .. }
484 | Rv64Instruction::Or { .. }
485 | Rv64Instruction::And { .. }
486 | Rv64Instruction::Addw { .. }
487 | Rv64Instruction::Subw { .. }
488 | Rv64Instruction::Sllw { .. }
489 | Rv64Instruction::Srlw { .. }
490 | Rv64Instruction::Sraw { .. }
491 | Rv64Instruction::Addi { .. }
492 | Rv64Instruction::Slti { .. }
493 | Rv64Instruction::Sltiu { .. }
494 | Rv64Instruction::Xori { .. }
495 | Rv64Instruction::Ori { .. }
496 | Rv64Instruction::Andi { .. }
497 | Rv64Instruction::Slli { .. }
498 | Rv64Instruction::Srli { .. }
499 | Rv64Instruction::Srai { .. }
500 | Rv64Instruction::Addiw { .. }
501 | Rv64Instruction::Slliw { .. }
502 | Rv64Instruction::Srliw { .. }
503 | Rv64Instruction::Sraiw { .. }
504 | Rv64Instruction::Lb { .. }
505 | Rv64Instruction::Lh { .. }
506 | Rv64Instruction::Lw { .. }
507 | Rv64Instruction::Ld { .. }
508 | Rv64Instruction::Lbu { .. }
509 | Rv64Instruction::Lhu { .. }
510 | Rv64Instruction::Lwu { .. }
511 | Rv64Instruction::Jalr { .. }
512 | Rv64Instruction::Sb { .. }
513 | Rv64Instruction::Sh { .. }
514 | Rv64Instruction::Sw { .. }
515 | Rv64Instruction::Sd { .. }
516 | Rv64Instruction::Beq { .. }
517 | Rv64Instruction::Bne { .. }
518 | Rv64Instruction::Blt { .. }
519 | Rv64Instruction::Bge { .. }
520 | Rv64Instruction::Bltu { .. }
521 | Rv64Instruction::Bgeu { .. }
522 | Rv64Instruction::Lui { .. }
523 | Rv64Instruction::Auipc { .. }
524 | Rv64Instruction::Jal { .. }
525 | Rv64Instruction::Ebreak
526 | Rv64Instruction::Unimp,
527 ) => {
528 }
530 Instruction::Base(
531 Rv64Instruction::Fence { .. }
532 | Rv64Instruction::Ecall
533 | Rv64Instruction::Invalid(_),
534 ) => {
535 return Err(ContractFileParseError::UnexpectedInstruction { instruction });
536 }
537 }
538 }
539
540 if !remaining_code_file_bytes.is_empty() {
541 return Err(ContractFileParseError::UnexpectedTrailingCodeBytes {
542 num_bytes: remaining_code_file_bytes.len(),
543 });
544 }
545 }
546
547 Ok(Self {
548 read_only_section_file_size: header.read_only_section_file_size,
549 read_only_section_memory_size: header.read_only_section_memory_size,
550 num_methods: header.num_methods,
551 bytes: file_bytes,
552 })
553 }
554
555 pub unsafe fn parse_unchecked(file_bytes: &'a [u8]) -> Self {
563 let header = unsafe { ContractFileHeader::read_unaligned_unchecked(file_bytes) };
565
566 Self {
567 read_only_section_file_size: header.read_only_section_file_size,
568 read_only_section_memory_size: header.read_only_section_memory_size,
569 num_methods: header.num_methods,
570 bytes: file_bytes,
571 }
572 }
573
574 #[inline(always)]
576 pub fn header(&self) -> ContractFileHeader {
577 unsafe { ContractFileHeader::read_unaligned_unchecked(self.bytes) }
579 }
580
581 #[inline]
583 pub fn metadata_bytes(&self) -> &[u8] {
584 let header = self.header();
585 unsafe {
587 self.bytes
588 .get_unchecked(header.metadata_offset as usize..)
589 .get_unchecked(..header.metadata_size as usize)
590 }
591 }
592
593 #[inline]
595 pub fn contract_memory_size(&self) -> u32 {
596 let read_only_section_offset = ContractFileHeader::SIZE
597 + u32::from(self.num_methods) * ContractFileMethodMetadata::SIZE;
598 let read_only_padding_size =
599 self.read_only_section_memory_size - self.read_only_section_file_size;
600 self.bytes.len() as u32 - read_only_section_offset + read_only_padding_size
601 }
602
603 #[must_use = "Must check that contract memory was large enough"]
607 pub fn initialize_contract_memory(&self, mut contract_memory: &mut [MaybeUninit<u8>]) -> bool {
608 let contract_memory_input_size = contract_memory.len();
609 let read_only_section_offset = ContractFileHeader::SIZE
610 + u32::from(self.num_methods) * ContractFileMethodMetadata::SIZE;
611 let read_only_padding_size =
612 self.read_only_section_memory_size - self.read_only_section_file_size;
613
614 let source_bytes = unsafe {
616 self.bytes
617 .get_unchecked(read_only_section_offset as usize..)
618 };
619
620 if contract_memory.len() == source_bytes.len() {
622 contract_memory.write_copy_of_slice(source_bytes);
623 return true;
624 }
625
626 let Some(read_only_file_target_bytes) =
627 contract_memory.split_off_mut(..self.read_only_section_file_size as usize)
628 else {
629 trace!(
630 %contract_memory_input_size,
631 contract_memory_size = %self.contract_memory_size(),
632 read_only_section_file_size = self.read_only_section_file_size,
633 "Not enough bytes to write read-only section from the file"
634 );
635
636 return false;
637 };
638
639 let (read_only_file_source_bytes, code_source_bytes) =
641 unsafe { source_bytes.split_at_unchecked(self.read_only_section_file_size as usize) };
642 read_only_file_target_bytes.write_copy_of_slice(read_only_file_source_bytes);
644
645 let Some(read_only_padding_bytes) =
646 contract_memory.split_off_mut(..read_only_padding_size as usize)
647 else {
648 trace!(
649 %contract_memory_input_size,
650 contract_memory_size = %self.contract_memory_size(),
651 read_only_section_file_size = self.read_only_section_file_size,
652 read_only_section_memory_size = self.read_only_section_memory_size,
653 %read_only_padding_size,
654 "Not enough bytes to write read-only padding section"
655 );
656
657 return false;
658 };
659
660 read_only_padding_bytes.write_filled(0);
662
663 if code_source_bytes.len() != contract_memory.len() {
664 trace!(
665 %contract_memory_input_size,
666 contract_memory_size = %self.contract_memory_size(),
667 read_only_section_file_size = self.read_only_section_file_size,
668 read_only_section_memory_size = self.read_only_section_memory_size,
669 %read_only_padding_size,
670 code_size = %code_source_bytes.len(),
671 "Not enough bytes to write code section from the file"
672 );
673
674 return false;
675 }
676
677 contract_memory.write_copy_of_slice(code_source_bytes);
678
679 true
680 }
681
682 pub fn get_code(&self) -> &[u8] {
684 let read_only_section_offset = ContractFileHeader::SIZE
685 + u32::from(self.num_methods) * ContractFileMethodMetadata::SIZE;
686
687 let source_bytes = unsafe {
689 self.bytes
690 .get_unchecked(read_only_section_offset as usize..)
691 };
692
693 let (_read_only_file_source_bytes, code_source_bytes) =
695 unsafe { source_bytes.split_at_unchecked(self.read_only_section_file_size as usize) };
696
697 code_source_bytes
698 }
699
700 pub fn iterate_methods(
702 &self,
703 ) -> impl ExactSizeIterator<Item = ContractFileMethod<'_>> + TrustedLen {
704 let metadata_bytes = self.metadata_bytes();
705
706 #[ouroboros::self_referencing]
707 struct MethodsMetadataIterState<'metadata> {
708 metadata_decoder: MetadataDecoder<'metadata>,
709 #[borrows(mut metadata_decoder)]
710 #[covariant]
711 methods_metadata_decoder: Option<MethodsMetadataDecoder<'this, 'metadata>>,
712 }
713
714 let metadata_decoder = MetadataDecoder::new(metadata_bytes);
715
716 let mut methods_metadata_state =
717 MethodsMetadataIterState::new(metadata_decoder, |metadata_decoder| {
718 metadata_decoder
719 .decode_next()
720 .and_then(Result::ok)
721 .map(MetadataItem::into_decoder)
722 });
723
724 let mut metadata_methods_iter = iter::from_fn(move || {
725 loop {
726 let maybe_next_item = methods_metadata_state.with_methods_metadata_decoder_mut(
727 |maybe_methods_metadata_decoder| {
728 let methods_metadata_decoder = maybe_methods_metadata_decoder.as_mut()?;
729 let method_metadata_decoder = methods_metadata_decoder.decode_next()?;
730
731 let before_remaining_bytes =
732 method_metadata_decoder.remaining_metadata_bytes();
733
734 let (_, method_metadata_item) = method_metadata_decoder
735 .decode_next()
736 .expect("Input is valid according to function contract; qed");
737
738 let method_metadata_bytes = unsafe {
740 metadata_bytes
741 .get_unchecked(metadata_bytes.len() - before_remaining_bytes..)
742 .get_unchecked(
743 ..before_remaining_bytes
744 - methods_metadata_decoder.remaining_metadata_bytes(),
745 )
746 };
747
748 Some((method_metadata_item, method_metadata_bytes))
749 },
750 );
751
752 if let Some(next_item) = maybe_next_item {
753 return Some(next_item);
754 }
755
756 replace_with_or_abort(&mut methods_metadata_state, |methods_metadata_state| {
758 let metadata_decoder = methods_metadata_state.into_heads().metadata_decoder;
759 MethodsMetadataIterState::new(metadata_decoder, |metadata_decoder| {
760 metadata_decoder
761 .decode_next()
762 .and_then(Result::ok)
763 .map(MetadataItem::into_decoder)
764 })
765 });
766
767 if methods_metadata_state
768 .borrow_methods_metadata_decoder()
769 .is_none()
770 {
771 return None;
772 }
773 }
774 });
775
776 let read_only_padding_size =
777 self.read_only_section_memory_size - self.read_only_section_file_size;
778 let contract_file_methods_metadata_bytes =
780 unsafe { self.bytes.get_unchecked(size_of::<ContractFileHeader>()..) };
781
782 (0..self.num_methods).map(move |method_index| {
783 let contract_file_method_metadata_bytes = unsafe {
785 contract_file_methods_metadata_bytes
786 .get_unchecked(
787 method_index as usize * size_of::<ContractFileMethodMetadata>()..,
788 )
789 .get_unchecked(..size_of::<ContractFileMethodMetadata>())
790 };
791 let contract_file_method_metadata = unsafe {
793 ContractFileMethodMetadata::read_unaligned_unchecked(
794 contract_file_method_metadata_bytes,
795 )
796 };
797
798 let (method_metadata_item, method_metadata_bytes) = metadata_methods_iter
799 .next()
800 .expect("Protected internal invariant checked in constructor; qed");
801
802 ContractFileMethod {
803 address: contract_file_method_metadata.offset + read_only_padding_size,
804 method_metadata_item,
805 method_metadata_bytes,
806 }
807 })
808 }
809}