1#![allow(clippy::indexing_slicing, clippy::arithmetic_side_effects)]
13
14use scale_info::{form::PortableForm, Field, TypeDef, TypeDefPrimitive, Variant};
15
16use crate::codec::value::Value;
17use crate::error::CoreError;
18use crate::keys::ss58_from_public;
19use crate::runtime::type_string::{Primitive, TypeSpec};
20use crate::runtime::Runtime;
21
22const MAX_DECODE_DEPTH: usize = 256;
28
29const MIN_ELEMENT_BUDGET: u64 = 1 << 20;
34
35const ELEMENT_BUDGET_PER_BYTE: u64 = 256;
39
40pub struct Cursor<'a> {
41 pub data: &'a [u8],
42 pub offset: usize,
43 depth: usize,
44 elements_remaining: u64,
49 pub strict: bool,
52}
53
54impl<'a> Cursor<'a> {
55 pub fn new(data: &'a [u8]) -> Self {
56 let budget = (data.len() as u64)
57 .saturating_mul(ELEMENT_BUDGET_PER_BYTE)
58 .max(MIN_ELEMENT_BUDGET);
59 Self {
60 data,
61 offset: 0,
62 depth: 0,
63 elements_remaining: budget,
64 strict: false,
65 }
66 }
67
68 fn sequence_bytes(&mut self, len: usize) -> Result<Value, CoreError> {
69 Ok(bytes_value(self.take(len)?))
70 }
71
72 fn descend(&mut self) -> Result<(), CoreError> {
73 self.depth += 1;
74 if self.depth > MAX_DECODE_DEPTH {
75 return Err(CoreError::Codec(format!(
76 "decode recursion exceeds {MAX_DECODE_DEPTH} levels (malformed or malicious type definition)"
77 )));
78 }
79 Ok(())
80 }
81
82 fn ascend(&mut self) {
83 self.depth = self.depth.saturating_sub(1);
84 }
85
86 fn charge_element(&mut self) -> Result<(), CoreError> {
88 self.elements_remaining = self.elements_remaining.checked_sub(1).ok_or_else(|| {
89 CoreError::Codec(
90 "decode exceeds its element budget (malformed or malicious collection length)"
91 .into(),
92 )
93 })?;
94 Ok(())
95 }
96
97 pub fn take(&mut self, n: usize) -> Result<&'a [u8], CoreError> {
98 let end = self.offset.checked_add(n).ok_or_else(overrun)?;
99 let slice = self.data.get(self.offset..end).ok_or_else(overrun)?;
100 self.offset = end;
101 Ok(slice)
102 }
103
104 pub fn byte(&mut self) -> Result<u8, CoreError> {
105 Ok(self.take(1)?[0])
106 }
107
108 pub fn remaining(&self) -> usize {
109 self.data.len().saturating_sub(self.offset)
110 }
111}
112
113fn overrun() -> CoreError {
114 CoreError::Codec("unexpected end of SCALE data".into())
115}
116
117pub fn compact_u128(cursor: &mut Cursor) -> Result<u128, CoreError> {
122 let strict = cursor.strict;
123 let non_canonical = || CoreError::Codec("non-canonical compact encoding".into());
124 let first = cursor.byte()?;
125 match first & 0b11 {
126 0 => Ok(u128::from(first >> 2)),
127 1 => {
128 let second = cursor.byte()?;
129 let value = u128::from(u16::from_le_bytes([first, second])) >> 2;
130 if strict && value < 0b100_0000 {
131 return Err(non_canonical());
132 }
133 Ok(value)
134 }
135 2 => {
136 let rest = cursor.take(3)?;
137 let word = u32::from_le_bytes([first, rest[0], rest[1], rest[2]]);
138 let value = u128::from(word >> 2);
139 if strict && value < 0b100_0000_0000_0000 {
140 return Err(non_canonical());
141 }
142 Ok(value)
143 }
144 _ => {
145 let len = usize::from(first >> 2) + 4;
146 if len > 16 {
147 return Err(CoreError::Codec("compact value wider than u128".into()));
148 }
149 let bytes = cursor.take(len)?;
150 if strict && bytes.last() == Some(&0) {
153 return Err(non_canonical());
154 }
155 let mut buf = [0u8; 16];
156 buf[..len].copy_from_slice(bytes);
157 let value = u128::from_le_bytes(buf);
158 if strict && value < 0b100_0000_0000_0000_0000_0000_0000_0000 {
159 return Err(non_canonical());
160 }
161 Ok(value)
162 }
163 }
164}
165
166pub fn compact_len(cursor: &mut Cursor) -> Result<usize, CoreError> {
167 usize::try_from(compact_u128(cursor)?)
168 .map_err(|_| CoreError::Codec("length does not fit usize".into()))
169}
170
171impl Runtime {
172 pub fn decode_spec(
175 &self,
176 spec: &TypeSpec,
177 data: &[u8],
178 strict: bool,
179 ) -> Result<Value, CoreError> {
180 let mut cursor = Cursor::new(data);
181 cursor.strict = strict;
182 if let TypeSpec::Id(id) = spec {
185 if let Ok(ty) = self.resolve(*id) {
186 if matches!(&ty.type_def, TypeDef::Composite(c) if c.fields.is_empty()) {
187 if strict && !data.is_empty() {
190 return Err(CoreError::Codec(format!(
191 "{} undecoded bytes remain",
192 data.len()
193 )));
194 }
195 return Ok(Value::Tuple(Vec::new()));
196 }
197 }
198 }
199 let value = self.decode_value(spec, &mut cursor)?;
200 if strict && cursor.remaining() != 0 {
201 return Err(CoreError::Codec(format!(
202 "{} undecoded bytes remain",
203 cursor.remaining()
204 )));
205 }
206 Ok(value)
207 }
208
209 pub fn decode_value(&self, spec: &TypeSpec, cursor: &mut Cursor) -> Result<Value, CoreError> {
210 cursor.descend()?;
211 let value = self.decode_value_inner(spec, cursor);
212 cursor.ascend();
213 value
214 }
215
216 fn decode_value_inner(&self, spec: &TypeSpec, cursor: &mut Cursor) -> Result<Value, CoreError> {
217 match spec {
218 TypeSpec::Id(id) => self.decode_id(*id, cursor),
219 TypeSpec::Primitive(p) => self.decode_primitive_spec(*p, cursor),
220 TypeSpec::Sequence(inner) => {
221 let len = compact_len(cursor)?;
222 if matches!(**inner, TypeSpec::Primitive(Primitive::U8)) {
223 return cursor.sequence_bytes(len);
224 }
225 let mut items = Vec::with_capacity(len.min(1024));
226 for _ in 0..len {
227 cursor.charge_element()?;
228 items.push(self.decode_value(inner, cursor)?);
229 }
230 Ok(Value::List(items))
231 }
232 TypeSpec::Option(inner) => match cursor.byte()? {
233 0 => Ok(Value::Null),
234 1 => self.decode_value(inner, cursor),
235 other => Err(CoreError::Codec(format!("bad Option byte {other:#x}"))),
236 },
237 TypeSpec::Array(inner, len) => {
238 let len = *len as usize;
239 if len > 0 && matches!(**inner, TypeSpec::Primitive(Primitive::U8)) {
241 return Ok(Value::hex(cursor.take(len)?));
242 }
243 let mut items = Vec::with_capacity(len.min(1024));
244 for _ in 0..len {
245 cursor.charge_element()?;
246 items.push(self.decode_value(inner, cursor)?);
247 }
248 Ok(Value::List(items))
249 }
250 TypeSpec::Tuple(parts) => {
251 let mut items = Vec::with_capacity(parts.len());
252 for part in parts {
253 items.push(self.decode_value(part, cursor)?);
254 }
255 Ok(Value::Tuple(items))
256 }
257 TypeSpec::Compact(_) => Ok(uint_value(compact_u128(cursor)?)),
258 TypeSpec::Bytes => {
259 let len = compact_len(cursor)?;
260 cursor.sequence_bytes(len)
261 }
262 TypeSpec::AccountId => {
263 let raw: [u8; 32] = cursor
264 .take(32)?
265 .try_into()
266 .map_err(|_| CoreError::Codec("bad AccountId length".into()))?;
267 Ok(Value::str(ss58_from_public(raw, self.ss58_format)))
268 }
269 TypeSpec::Era => self.decode_era(cursor),
270 TypeSpec::Call => self.decode_call_value(cursor),
271 TypeSpec::Extrinsic => Err(CoreError::Codec(
272 "extrinsics are decoded by the transport layer".into(),
273 )),
274 }
275 }
276
277 fn decode_primitive_spec(&self, p: Primitive, cursor: &mut Cursor) -> Result<Value, CoreError> {
278 let def = match p {
279 Primitive::Bool => TypeDefPrimitive::Bool,
280 Primitive::Char => TypeDefPrimitive::Char,
281 Primitive::Str => TypeDefPrimitive::Str,
282 Primitive::U8 => TypeDefPrimitive::U8,
283 Primitive::U16 => TypeDefPrimitive::U16,
284 Primitive::U32 => TypeDefPrimitive::U32,
285 Primitive::U64 => TypeDefPrimitive::U64,
286 Primitive::U128 => TypeDefPrimitive::U128,
287 Primitive::U256 => TypeDefPrimitive::U256,
288 Primitive::I8 => TypeDefPrimitive::I8,
289 Primitive::I16 => TypeDefPrimitive::I16,
290 Primitive::I32 => TypeDefPrimitive::I32,
291 Primitive::I64 => TypeDefPrimitive::I64,
292 Primitive::I128 => TypeDefPrimitive::I128,
293 Primitive::I256 => TypeDefPrimitive::I256,
294 };
295 decode_primitive(&def, cursor)
296 }
297
298 pub fn decode_id(&self, id: u32, cursor: &mut Cursor) -> Result<Value, CoreError> {
301 cursor.descend()?;
302 let value = self.decode_id_inner(id, cursor);
303 cursor.ascend();
304 value
305 }
306
307 fn decode_id_inner(&self, id: u32, cursor: &mut Cursor) -> Result<Value, CoreError> {
308 if self.outer_event_type == Some(id) {
309 return Ok(self.decode_outer_event(cursor)?.into_value());
310 }
311 if self.extrinsic.call_type == Some(id) {
312 return self.decode_call_value(cursor);
313 }
314 let ty = self.resolve(id)?;
315 let segments = &ty.path.segments;
316 let last = segments.last().map(String::as_str);
317 if last == Some("EventRecord")
318 && segments.first().map(String::as_str) == Some("frame_system")
319 {
320 return self.decode_event_record(ty, cursor);
321 }
322
323 match last {
324 Some("AccountId32") if is_path(segments, &["sp_core", "crypto", "AccountId32"]) => {
325 let raw: [u8; 32] = cursor
326 .take(32)?
327 .try_into()
328 .map_err(|_| CoreError::Codec("bad AccountId32".into()))?;
329 return Ok(Value::str(ss58_from_public(raw, self.ss58_format)));
330 }
331 Some("Era") if segments.first().map(String::as_str) == Some("sp_runtime") => {
332 return self.decode_era(cursor);
333 }
334 Some("MultiAddress") => {
335 return self.decode_multiaddress(ty, cursor);
336 }
337 Some("U256") if is_path(segments, &["primitive_types", "U256"]) => {
339 return Ok(Value::U256(fixed(cursor.take(32)?)?));
340 }
341 Some("BTreeMap") => {
342 return self.decode_btreemap(ty, cursor);
343 }
344 _ => {}
345 }
346
347 match &ty.type_def {
348 TypeDef::Primitive(p) => decode_primitive(p, cursor),
349 TypeDef::Compact(c) => {
350 let _ = c;
356 Ok(uint_value(compact_u128(cursor)?))
357 }
358 TypeDef::Composite(composite) => self.decode_fields_owner(&composite.fields, cursor),
359 TypeDef::Variant(variant) => {
360 let is_option = last == Some("Option") && segments.len() == 1;
361 let index = cursor.byte()?;
362 let chosen = variant
363 .variants
364 .iter()
365 .find(|v| v.index == index)
366 .ok_or_else(|| {
367 CoreError::Codec(format!("no variant with index {index} in type {id}"))
368 })?;
369 if is_option {
370 return match chosen.name.as_str() {
371 "None" => Ok(Value::Null),
372 _ => self.decode_fields_payload(&chosen.fields, cursor),
373 };
374 }
375 self.decode_variant(chosen, cursor)
376 }
377 TypeDef::Sequence(s) => {
378 let len = compact_len(cursor)?;
379 if self.is_u8(s.type_param.id) {
380 return cursor.sequence_bytes(len);
381 }
382 let mut items = Vec::with_capacity(len.min(4096));
383 for _ in 0..len {
384 cursor.charge_element()?;
385 items.push(self.decode_id(s.type_param.id, cursor)?);
386 }
387 Ok(Value::List(items))
388 }
389 TypeDef::Array(a) => {
390 let len = a.len as usize;
391 if len > 0 && self.is_u8(a.type_param.id) {
392 return Ok(Value::hex(cursor.take(len)?));
393 }
394 let mut items = Vec::with_capacity(len.min(4096));
395 for _ in 0..len {
396 cursor.charge_element()?;
397 items.push(self.decode_id(a.type_param.id, cursor)?);
398 }
399 Ok(Value::List(items))
400 }
401 TypeDef::Tuple(t) => {
402 let mut items = Vec::with_capacity(t.fields.len());
403 for field in &t.fields {
404 items.push(self.decode_id(field.id, cursor)?);
405 }
406 Ok(Value::Tuple(items))
407 }
408 TypeDef::BitSequence(_) => Err(CoreError::Codec(
409 "bit sequences are not used by this chain".into(),
410 )),
411 }
412 }
413
414 fn is_u8(&self, id: u32) -> bool {
415 matches!(
416 self.types.resolve(id).map(|t| &t.type_def),
417 Some(TypeDef::Primitive(TypeDefPrimitive::U8))
418 )
419 }
420
421 fn decode_fields_owner(
425 &self,
426 fields: &[Field<PortableForm>],
427 cursor: &mut Cursor,
428 ) -> Result<Value, CoreError> {
429 if fields.is_empty() {
430 return Ok(Value::Dict(Vec::new()));
431 }
432 let named = fields.iter().all(|f| f.name.is_some());
433 if named {
434 let mut entries = Vec::with_capacity(fields.len());
435 for field in fields {
436 let name = field.name.clone().unwrap_or_default();
437 entries.push((Value::Str(name), self.decode_id(field.ty.id, cursor)?));
438 }
439 return Ok(Value::Dict(entries));
440 }
441 if fields.len() == 1 {
442 return self.decode_id(fields[0].ty.id, cursor);
443 }
444 let mut items = Vec::with_capacity(fields.len());
445 for field in fields {
446 items.push(self.decode_id(field.ty.id, cursor)?);
447 }
448 Ok(Value::Tuple(items))
449 }
450
451 fn decode_fields_payload(
453 &self,
454 fields: &[Field<PortableForm>],
455 cursor: &mut Cursor,
456 ) -> Result<Value, CoreError> {
457 self.decode_fields_owner(fields, cursor)
458 }
459
460 fn decode_variant(
461 &self,
462 chosen: &Variant<PortableForm>,
463 cursor: &mut Cursor,
464 ) -> Result<Value, CoreError> {
465 if chosen.fields.is_empty() {
466 return Ok(Value::Str(chosen.name.clone()));
467 }
468 let payload = self.decode_fields_payload(&chosen.fields, cursor)?;
469 Ok(Value::Dict(vec![(
470 Value::Str(chosen.name.clone()),
471 payload,
472 )]))
473 }
474
475 fn decode_multiaddress(
479 &self,
480 ty: &scale_info::Type<PortableForm>,
481 cursor: &mut Cursor,
482 ) -> Result<Value, CoreError> {
483 let TypeDef::Variant(variant) = &ty.type_def else {
484 return Err(CoreError::Codec("MultiAddress is not an enum".into()));
485 };
486 let index = cursor.byte()?;
487 let chosen = variant
488 .variants
489 .iter()
490 .find(|v| v.index == index)
491 .ok_or_else(|| CoreError::Codec(format!("bad MultiAddress variant {index}")))?;
492 match chosen.name.as_str() {
493 "Id" | "Index" => self.decode_fields_payload(&chosen.fields, cursor),
494 _ => self.decode_variant(chosen, cursor),
495 }
496 }
497
498 fn decode_btreemap(
501 &self,
502 ty: &scale_info::Type<PortableForm>,
503 cursor: &mut Cursor,
504 ) -> Result<Value, CoreError> {
505 let TypeDef::Composite(composite) = &ty.type_def else {
507 return Err(CoreError::Codec("BTreeMap is not a composite".into()));
508 };
509 let inner = composite
510 .fields
511 .first()
512 .map(|f| f.ty.id)
513 .ok_or_else(|| CoreError::Codec("BTreeMap has no inner field".into()))?;
514 let TypeDef::Sequence(seq) = &self.resolve(inner)?.type_def else {
515 return Err(CoreError::Codec("BTreeMap inner is not a sequence".into()));
516 };
517 let TypeDef::Tuple(pair) = &self.resolve(seq.type_param.id)?.type_def else {
518 return Err(CoreError::Codec("BTreeMap pair is not a tuple".into()));
519 };
520 let (key_ty, value_ty) = match pair.fields.as_slice() {
521 [k, v] => (k.id, v.id),
522 _ => return Err(CoreError::Codec("BTreeMap pair is not 2-ary".into())),
523 };
524 let len = compact_len(cursor)?;
525 let mut entries = Vec::with_capacity(len.min(4096));
526 for _ in 0..len {
527 cursor.charge_element()?;
528 let key = self.decode_id(key_ty, cursor)?;
529 let value = self.decode_id(value_ty, cursor)?;
530 entries.push((key, value));
531 }
532 Ok(Value::Dict(entries))
533 }
534
535 fn decode_outer_event(&self, cursor: &mut Cursor) -> Result<DecodedEvent, CoreError> {
539 let outer_id = self
540 .outer_event_type
541 .ok_or_else(|| CoreError::Codec("runtime has no outer event enum".into()))?;
542 let TypeDef::Variant(outer) = &self.resolve(outer_id)?.type_def else {
543 return Err(CoreError::Codec("outer event type is not an enum".into()));
544 };
545 let pallet_index = cursor.byte()?;
546 let pallet_variant = outer
547 .variants
548 .iter()
549 .find(|v| v.index == pallet_index)
550 .ok_or_else(|| CoreError::Codec(format!("no event pallet at index {pallet_index}")))?;
551 let inner_id = pallet_variant
552 .fields
553 .first()
554 .map(|f| f.ty.id)
555 .ok_or_else(|| CoreError::Codec("outer event variant has no payload".into()))?;
556 let TypeDef::Variant(inner) = &self.resolve(inner_id)?.type_def else {
557 return Err(CoreError::Codec("pallet event type is not an enum".into()));
558 };
559 let event_index = cursor.byte()?;
560 let event = inner
561 .variants
562 .iter()
563 .find(|v| v.index == event_index)
564 .ok_or_else(|| {
565 CoreError::Codec(format!(
566 "no event at index {event_index} in pallet {}",
567 pallet_variant.name
568 ))
569 })?;
570 let attributes = if event.fields.is_empty() {
571 Value::Null
572 } else {
573 self.decode_fields_payload(&event.fields, cursor)?
574 };
575 Ok(DecodedEvent {
576 pallet_index,
577 event_index,
578 module_id: pallet_variant.name.clone(),
579 event_id: event.name.clone(),
580 attributes,
581 })
582 }
583
584 fn decode_event_record(
588 &self,
589 ty: &scale_info::Type<PortableForm>,
590 cursor: &mut Cursor,
591 ) -> Result<Value, CoreError> {
592 let TypeDef::Composite(composite) = &ty.type_def else {
593 return Err(CoreError::Codec("EventRecord is not a composite".into()));
594 };
595 let field_id = |name: &str| -> Result<u32, CoreError> {
596 composite
597 .fields
598 .iter()
599 .find(|f| f.name.as_deref() == Some(name))
600 .map(|f| f.ty.id)
601 .ok_or_else(|| CoreError::Codec(format!("EventRecord has no {name} field")))
602 };
603 let phase_id = field_id("phase")?;
606 let TypeDef::Variant(phase_def) = &self.resolve(phase_id)?.type_def else {
607 return Err(CoreError::Codec("Phase is not an enum".into()));
608 };
609 let phase_index = cursor.byte()?;
610 let phase = phase_def
611 .variants
612 .iter()
613 .find(|v| v.index == phase_index)
614 .ok_or_else(|| CoreError::Codec(format!("bad Phase variant {phase_index}")))?;
615 let extrinsic_idx = if phase.fields.is_empty() {
616 Value::Null
617 } else {
618 self.decode_fields_payload(&phase.fields, cursor)?
619 };
620
621 let event = self.decode_outer_event(cursor)?;
622
623 let topics_id = field_id("topics")?;
624 let topics = self.decode_id(topics_id, cursor)?;
625
626 Ok(Value::record(vec![
627 ("phase".into(), Value::Str(phase.name.clone())),
628 ("extrinsic_idx".into(), extrinsic_idx),
629 ("event".into(), event.clone().into_value()),
630 (
631 "event_index".into(),
632 Value::Int(i128::from(event.pallet_index)),
633 ),
634 ("module_id".into(), Value::Str(event.module_id.clone())),
635 ("event_id".into(), Value::Str(event.event_id.clone())),
636 ("attributes".into(), event.attributes.clone()),
637 ("topics".into(), topics),
638 ]))
639 }
640
641 fn decode_era(&self, cursor: &mut Cursor) -> Result<Value, CoreError> {
644 let first = cursor.byte()?;
645 if first == 0 {
646 return Ok(Value::str("00"));
647 }
648 let second = cursor.byte()?;
649 let encoded = u64::from(u16::from_le_bytes([first, second]));
650 let period = 2u64 << (encoded % 16);
651 let quantize_factor = (period >> 12).max(1);
652 let phase = (encoded >> 4) * quantize_factor;
653 Ok(Value::Tuple(vec![
654 Value::Int(i128::from(period)),
655 Value::Int(i128::from(phase)),
656 ]))
657 }
658
659 pub fn decode_call_value(&self, cursor: &mut Cursor) -> Result<Value, CoreError> {
663 let start = cursor.offset;
664 let pallet_index = cursor.byte()?;
665 let call_index = cursor.byte()?;
666 let pallet = self
667 .pallet_at(pallet_index)
668 .ok_or_else(|| CoreError::Codec(format!("no pallet at index {pallet_index}")))?;
669 let calls_type = pallet
670 .calls_type
671 .ok_or_else(|| CoreError::Codec(format!("pallet {} has no calls", pallet.name)))?;
672 let TypeDef::Variant(variant) = &self.resolve(calls_type)?.type_def else {
673 return Err(CoreError::Codec("call type is not an enum".into()));
674 };
675 let function = variant
676 .variants
677 .iter()
678 .find(|v| v.index == call_index)
679 .ok_or_else(|| {
680 CoreError::Codec(format!(
681 "no call at index {call_index} in pallet {}",
682 pallet.name
683 ))
684 })?;
685 let mut args = Vec::with_capacity(function.fields.len());
686 for field in &function.fields {
687 let value = self.decode_id(field.ty.id, cursor)?;
688 args.push(Value::record(vec![
689 (
690 "name".into(),
691 Value::Str(field.name.clone().unwrap_or_default()),
692 ),
693 (
694 "type".into(),
695 Value::Str(convert_type_string(
696 field.type_name.as_deref().unwrap_or_default(),
697 )),
698 ),
699 ("value".into(), value),
700 ]));
701 }
702 let call_bytes = &cursor.data[start..cursor.offset];
703 let call_hash = sp_core::hashing::blake2_256(call_bytes);
704 Ok(Value::record(vec![
705 (
706 "call_index".into(),
707 Value::str(format!("0x{:02x}{:02x}", pallet_index, call_index)),
708 ),
709 ("call_function".into(), Value::Str(function.name.clone())),
710 ("call_module".into(), Value::Str(pallet.name.clone())),
711 ("call_args".into(), Value::List(args)),
712 ("call_hash".into(), Value::hex(&call_hash)),
713 ]))
714 }
715}
716
717#[derive(Clone)]
719struct DecodedEvent {
720 pallet_index: u8,
721 event_index: u8,
722 module_id: String,
723 event_id: String,
724 attributes: Value,
725}
726
727impl DecodedEvent {
728 fn into_value(self) -> Value {
729 Value::record(vec![
730 (
731 "event_index".into(),
732 Value::str(format!("{:02x}{:02x}", self.pallet_index, self.event_index)),
733 ),
734 ("module_id".into(), Value::Str(self.module_id)),
735 ("event_id".into(), Value::Str(self.event_id)),
736 ("attributes".into(), self.attributes),
737 ])
738 }
739}
740
741pub fn convert_type_string(name: &str) -> String {
745 fn remove_ci(haystack: &mut String, needle: &str) {
746 let lower_needle = needle.to_lowercase();
747 loop {
748 let lower = haystack.to_lowercase();
749 let Some(pos) = lower.find(&lower_needle) else {
750 break;
751 };
752 haystack.replace_range(pos..pos.saturating_add(needle.len()), "");
753 }
754 }
755
756 let mut name = name.replace("T::", "");
757 if name.to_lowercase().starts_with("t::") {
758 name.replace_range(..3, "");
759 }
760 remove_ci(&mut name, "<T>");
761 remove_ci(&mut name, "<T as Trait>::");
762 remove_ci(&mut name, "<T as Trait<I>>::");
763 remove_ci(&mut name, "<T as Config>::");
764 remove_ci(&mut name, "<T as Config<I>>::");
765 name = name.replace('\n', "");
766 for prefix in [
767 "grandpa::",
768 "session::",
769 "slashing::",
770 "limits::",
771 "beefy_primitives::",
772 "xcm::opaque::",
773 ] {
774 if let Some(stripped) = name.strip_prefix(prefix) {
775 name = stripped.to_string();
776 break;
777 }
778 }
779 loop {
781 let lower = name.to_lowercase();
782 let Some(pos) = lower.find("vecdeque<") else {
783 break;
784 };
785 name.replace_range(pos..pos.saturating_add("VecDeque<".len()), "Vec<");
786 }
787 let lower = name.to_lowercase();
788 if lower.starts_with("box<") && lower.ends_with('>') && name.len() > 5 {
789 name = name[4..name.len().saturating_sub(1)].to_string();
790 }
791
792 match name.to_lowercase().as_str() {
793 _ if name == "()" => "Null".into(),
794 "vec<u8>" | "&[u8]" | "& 'static[u8]" => "Bytes".into(),
795 "<lookup as staticlookup>::source" => "LookupSource".into(),
796 "<balance as hascompact>::type" => "Compact<Balance>".into(),
797 "<blocknumber as hascompact>::type" => "Compact<BlockNumber>".into(),
798 "<moment as hascompact>::type" => "Compact<Moment>".into(),
799 "<inherentofflinereport as inherentofflinereport>::inherent" => {
800 "InherentOfflineReport".into()
801 }
802 _ => name,
803 }
804}
805
806fn is_path(segments: &[String], expected: &[&str]) -> bool {
807 segments.len() == expected.len() && segments.iter().zip(expected).all(|(a, b)| a == b)
808}
809
810fn uint_value(v: u128) -> Value {
811 match i128::try_from(v) {
812 Ok(i) => Value::Int(i),
813 Err(_) => Value::Uint(v),
814 }
815}
816
817fn bytes_value(data: &[u8]) -> Value {
818 match core::str::from_utf8(data) {
819 Ok(s) => Value::str(s),
820 Err(_) => Value::hex(data),
821 }
822}
823
824fn decode_primitive(p: &TypeDefPrimitive, cursor: &mut Cursor) -> Result<Value, CoreError> {
825 use TypeDefPrimitive as P;
826 let strict = cursor.strict;
827 Ok(match p {
828 P::Bool => {
829 let byte = cursor.byte()?;
830 if strict && byte > 1 {
831 return Err(CoreError::Codec(format!(
832 "non-canonical bool byte {byte:#x}"
833 )));
834 }
835 Value::Bool(byte != 0)
836 }
837 P::Char => {
838 let raw = cursor.take(4)?;
839 let code = u32::from_le_bytes([raw[0], raw[1], raw[2], raw[3]]);
840 match char::from_u32(code) {
841 Some(c) => Value::Str(c.to_string()),
842 None if strict => {
843 return Err(CoreError::Codec(format!(
844 "invalid Unicode scalar value {code:#x}"
845 )))
846 }
847 None => Value::Str('\u{fffd}'.to_string()),
848 }
849 }
850 P::Str => {
851 let len = compact_len(cursor)?;
852 let raw = cursor.take(len)?;
853 if strict {
854 let s = core::str::from_utf8(raw)
855 .map_err(|e| CoreError::Codec(format!("invalid UTF-8 string: {e}")))?;
856 Value::Str(s.to_owned())
857 } else {
858 Value::Str(String::from_utf8_lossy(raw).into_owned())
859 }
860 }
861 P::U8 => Value::Int(i128::from(cursor.byte()?)),
862 P::U16 => Value::Int(i128::from(u16::from_le_bytes(fixed(cursor.take(2)?)?))),
863 P::U32 => Value::Int(i128::from(u32::from_le_bytes(fixed(cursor.take(4)?)?))),
864 P::U64 => Value::Int(i128::from(u64::from_le_bytes(fixed(cursor.take(8)?)?))),
865 P::U128 => uint_value(u128::from_le_bytes(fixed(cursor.take(16)?)?)),
866 P::U256 => Value::U256(fixed(cursor.take(32)?)?),
867 P::I8 => Value::Int(i128::from(cursor.byte()? as i8)),
868 P::I16 => Value::Int(i128::from(i16::from_le_bytes(fixed(cursor.take(2)?)?))),
869 P::I32 => Value::Int(i128::from(i32::from_le_bytes(fixed(cursor.take(4)?)?))),
870 P::I64 => Value::Int(i128::from(i64::from_le_bytes(fixed(cursor.take(8)?)?))),
871 P::I128 => Value::Int(i128::from_le_bytes(fixed(cursor.take(16)?)?)),
872 P::I256 => {
873 Value::U256(fixed(cursor.take(32)?)?)
876 }
877 })
878}
879
880fn fixed<const N: usize>(slice: &[u8]) -> Result<[u8; N], CoreError> {
881 slice
882 .try_into()
883 .map_err(|_| CoreError::Codec("bad fixed-width slice".into()))
884}