1use std::{
2 any::TypeId,
3 collections::{BTreeMap, BTreeSet, HashSet},
4 path::PathBuf,
5 rc::Rc,
6 str::FromStr,
7};
8
9use client::{dump::ClientDump, live::ClientShared, Client, ClientT};
10use directories::BaseDirs;
11use frame_metadata::{
12 PalletMetadata, RuntimeMetadata, RuntimeMetadataPrefixed, RuntimeMetadataV14,
13 StorageEntryModifier, StorageEntryType, StorageHasher,
14};
15use hex::{builtin_from_hex, builtin_to_hex, Hex};
16use jrsonnet_evaluator::{
17 bail,
18 error::{Error as JrError, Result},
19 function::builtin,
20 in_description_frame, runtime_error,
21 typed::{Either2, NativeFn, Typed},
22 val::{ArrValue, NumValue, ThunkValue},
23 ContextInitializer, Either, IStr, ObjValue, ObjValueBuilder, Pending, ResultExt, Thunk, Val,
24};
25use jrsonnet_gcmodule::Trace;
26use num_bigint::BigInt;
27use parity_scale_codec::{Compact, Encode, Input, Output};
28use rebuild::rebuild;
29use scale_info::{
30 form::PortableForm, interner::UntrackedSymbol, Field, PortableRegistry, TypeDef,
31 TypeDefPrimitive,
32};
33use serde::Deserialize;
34use sp_core::{
35 blake2_128, blake2_256, crypto::Ss58Codec, storage::StateVersion, twox_128, twox_256, twox_64,
36 ByteArray, U256,
37};
38use sp_io::{hashing::keccak_256, trie::blake2_256_root};
39use tracing::{info, warn};
40use wasm::{builtin_runtime_wasm, RuntimeContainer};
41
42use crate::address::{verify_signature, AddressSchema, AddressType, Ss58Format};
43
44use self::{
45 address::{
46 builtin_address_seed, builtin_ecdsa_address_seed, builtin_ecdsa_seed,
47 builtin_ed25519_address_seed, builtin_ed25519_seed, builtin_ethereum_address_seed,
48 builtin_ethereum_seed, builtin_seed, builtin_sr25519_address_seed, builtin_sr25519_seed,
49 SignatureType,
50 },
51 ethereum::builtin_eth_encode,
52};
53
54pub mod address;
55mod client;
56pub mod ethereum;
57pub mod hex;
58pub mod rebuild;
59pub mod wasm;
60
61fn metadata_obj(meta: &RuntimeMetadataV14) -> Val {
63 let ty = serde_json::to_value(meta).expect("valid value");
64 Val::deserialize(ty).expect("valid value")
65}
66
67macro_rules! simple_thunk {
69 (
70 $(
71 $(#[trace($meta:meta)])?
72 let $name:ident: $ty:ty = $expr:expr;
73 )*
74 Thunk::<$out:ty>::evaluated($val:expr)
75 ) => {{
76 #[derive(Trace)]
77 struct InvisThunk {
78 $(
79 $(#[trace($meta)])?
80 $name: $ty
81 ),*
82 }
83 impl ThunkValue for InvisThunk {
84 type Output = $out;
85
86 fn get(self: Box<Self>) -> Result<Self::Output> {
87 let Self {$($name),*} = *self;
88 Ok($val)
89 }
90 }
91
92 #[allow(clippy::redundant_field_names)]
93 Thunk::new(InvisThunk {
94 $($name: $expr,)*
95 })
96 }};
97}
98
99#[macro_export]
101macro_rules! ensure {
102 ($cond:expr, $($tt:tt)+) => {
103 if !($cond) {
104 jrsonnet_evaluator::bail!($($tt)+)
105 }
106 };
107}
108
109fn missing_resolve() -> JrError {
111 runtime_error!("invalid metadata: missing resolve key")
112}
113
114fn decode_maybe_compact<I, T>(dec: &mut I, compact: bool) -> Result<T>
116where
117 I: Input,
118 T: DecodeExt,
119 Compact<T>: DecodeExt,
120{
121 if compact {
122 <Compact<T>>::decode_ext(dec).map(|v| v.0)
123 } else {
124 <T as DecodeExt>::decode_ext(dec)
125 }
126}
127
128fn encode_maybe_compact<T, O>(compact: bool, val: T, dest: &mut O)
130where
131 T: Encode,
132 O: Output,
133 Compact<T>: Encode,
134{
135 if compact {
136 Compact(val).encode_to(dest)
137 } else {
138 val.encode_to(dest)
139 }
140}
141
142fn encode_obj_value<O>(
144 reg: &PortableRegistry,
145 typ: &[Field<PortableForm>],
146 compact: bool,
147 val: Val,
148 out: &mut O,
149) -> Result<()>
150where
151 O: Output,
152{
153 if typ.len() == 1 {
154 return encode_value(reg, typ[0].ty, compact, val, out, false);
155 }
156 let val = ObjValue::from_untyped(val)?;
157 for (i, f) in typ.iter().enumerate() {
158 let field_name: IStr = f
159 .name
160 .clone()
161 .unwrap_or_else(|| format!("unnamed{}", i))
162 .into();
163 in_description_frame(
164 || format!(".{field_name}"),
165 || {
166 let field = val
167 .get(field_name.clone())?
168 .ok_or_else(|| runtime_error!("missing field {field_name}"))?;
169 encode_value(reg, f.ty, compact, field, out, false)?;
170 Ok(())
171 },
172 )?;
173 }
174 Ok(())
175}
176
177fn decode_obj_value<I>(
179 dec: &mut I,
180 reg: &PortableRegistry,
181 typ: &[Field<PortableForm>],
182 compact: bool,
183) -> Result<Val>
184where
185 I: Input,
186{
187 if typ.len() == 1 {
188 return decode_value(dec, reg, typ[0].ty, compact);
189 }
190 let mut out = ObjValueBuilder::new();
191 for (i, f) in typ.iter().enumerate() {
192 let field_name = f.name.clone().unwrap_or_else(|| format!("unnamed{i}"));
193 let field = decode_value(dec, reg, f.ty, compact)
194 .with_description(|| format!("field <{field_name}> decode"))?;
195 out.field(field_name).try_value(field)?;
196 }
197 Ok(Val::Obj(out.build()))
198}
199
200fn extract_newtypes(
202 reg: &PortableRegistry,
203 typ: UntrackedSymbol<TypeId>,
204 compact: bool,
205) -> Result<(bool, UntrackedSymbol<TypeId>)> {
206 match ®.resolve(typ.id).ok_or_else(missing_resolve)?.type_def {
207 TypeDef::Composite(c) if c.fields.len() == 1 => {
208 extract_newtypes(reg, c.fields[0].ty, compact)
209 }
210 TypeDef::Array(a) if a.len == 1 => extract_newtypes(reg, a.type_param, compact),
211 TypeDef::Tuple(d) if d.fields.len() == 1 => extract_newtypes(reg, d.fields[0], compact),
212 TypeDef::Compact(c) => extract_newtypes(reg, c.type_param, true),
213 _ => Ok((compact, typ)),
214 }
215}
216
217fn maybe_json_parse(v: Val, from_string: bool) -> Result<Val> {
219 if !from_string {
220 return Ok(v);
221 }
222 if let Some(str) = v.as_str() {
223 let value: Val = serde_json::from_str(&str).map_err(|e| runtime_error!("json: {e}"))?;
224 Ok(value)
225 } else {
226 Ok(v)
227 }
228}
229
230fn bigint_encode<T: FromStr>(v: Val) -> Result<T>
231where
232 T::Err: std::fmt::Display,
233{
234 let v = match v {
235 Val::BigInt(n) => (*n).clone(),
236 Val::Str(v) => {
237 BigInt::from_str(&v.to_string()).map_err(|e| runtime_error!("bigint parse: {e}"))?
238 }
239 _ => bail!("unexpected type for bigint decoder: {}", v.value_type()),
240 };
241 v.to_string()
242 .parse()
243 .map_err(|e| runtime_error!("bigint encode: {e}"))
244}
245fn bigint_decode<T: std::fmt::Display>(v: T) -> Result<Val> {
246 let v = v.to_string();
247 let v: BigInt = v
248 .parse()
249 .map_err(|e| runtime_error!("bigint decode: {e}"))?;
250 Ok(Val::BigInt(Box::new(v)))
251}
252fn encode_value<O>(
254 reg: &PortableRegistry,
255 mut typ: UntrackedSymbol<TypeId>,
256 mut compact: bool,
257 val: Val,
258 out: &mut O,
259 from_string: bool,
260) -> Result<()>
261where
262 O: Output,
263{
264 let (new_compact, new_typ) = extract_newtypes(reg, typ, compact)?;
265 compact = new_compact;
266 typ = new_typ;
267 match ®.resolve(typ.id).ok_or_else(missing_resolve)?.type_def {
268 TypeDef::Composite(comp) => {
269 let val = maybe_json_parse(val, from_string)?;
270 encode_obj_value(reg, &comp.fields, compact, val, out)?;
271 }
272 TypeDef::Variant(e) => {
273 if let Some(str) = val.as_str() {
274 for variant in e.variants.iter() {
275 if variant.name.as_str() == str.as_str() && variant.fields.is_empty() {
276 variant.index.encode_to(out);
277 return Ok(());
278 }
279 }
280 }
281 let val = maybe_json_parse(val, from_string)?;
282 let v = ObjValue::from_untyped(val)?;
283 let name = &v.fields(true);
284 ensure!(name.len() == 1, "not a enum");
285 let name = name[0].clone();
286 let value = v
287 .get(name.clone())?
288 .expect("value exists, as name is obtained from .fields()");
289
290 for variant in e.variants.iter() {
291 if variant.name.as_str() == name.as_str() {
292 variant.index.encode_to(out);
293 return encode_obj_value(reg, &variant.fields, compact, value, out);
294 }
295 }
296 bail!("variant not found: {name}");
297 }
298 TypeDef::Sequence(e) => {
299 if matches!(
300 reg.resolve(e.type_param.id)
301 .ok_or_else(missing_resolve)?
302 .type_def,
303 TypeDef::Primitive(TypeDefPrimitive::U8)
304 ) {
305 let raw = Hex::from_untyped(val)?;
306 raw.encode_to(out);
307 return Ok(());
308 }
309 let val = maybe_json_parse(val, from_string)?;
310 let v = Vec::<Val>::from_untyped(val)?;
311 Compact(v.len() as u32).encode_to(out);
312 for val in v.iter() {
313 encode_value(reg, e.type_param, compact, val.clone(), out, false)?;
314 }
315 }
316 TypeDef::Array(e) => {
317 if matches!(
318 reg.resolve(e.type_param.id)
319 .ok_or_else(missing_resolve)?
320 .type_def,
321 TypeDef::Primitive(TypeDefPrimitive::U8)
322 ) {
323 let raw = Hex::from_untyped(val)?;
324 ensure!(
325 e.len as usize == raw.len(),
326 "array has wrong number for elements, expected {}, got {}",
327 e.len,
328 raw.len()
329 );
330 for i in &*raw {
331 i.encode_to(out);
332 }
333 return Ok(());
334 }
335 let val = maybe_json_parse(val, from_string)?;
336 let v = Vec::<Val>::from_untyped(val)?;
337 ensure!(
338 e.len as usize == v.len(),
339 "array has wrong number of elements, expected {}, got {}",
340 e.len,
341 v.len(),
342 );
343 for val in v.iter() {
344 encode_value(reg, e.type_param, compact, val.clone(), out, false)?;
345 }
346 }
347 TypeDef::Tuple(e) => {
348 let val = maybe_json_parse(val, from_string)?;
349 let v = ArrValue::from_untyped(val)?;
350 ensure!(
351 e.fields.len() == v.len(),
352 "tuple has wrong number of elements"
353 );
354 for (ty, val) in e.fields.iter().zip(v.iter()) {
355 let val = val?;
356 encode_value(reg, *ty, compact, val.clone(), out, false)?;
357 }
358 }
359 TypeDef::Primitive(p) => match p {
360 TypeDefPrimitive::Bool => {
361 let val = maybe_json_parse(val, from_string)?;
362 let b = bool::from_untyped(val)?;
363 b.encode_to(out)
364 }
365 TypeDefPrimitive::Char => bail!("char not supported"),
366 TypeDefPrimitive::Str => {
367 let s = String::from_untyped(val)?;
368 s.encode_to(out)
369 }
370 TypeDefPrimitive::U8 => {
371 let val = maybe_json_parse(val, from_string)?;
372 let v = u8::from_untyped(val)?;
373 v.encode_to(out)
374 }
375 TypeDefPrimitive::U16 => {
376 let val = maybe_json_parse(val, from_string)?;
377 let v = u16::from_untyped(val)?;
378 encode_maybe_compact::<u16, _>(compact, v, out)
379 }
380 TypeDefPrimitive::U32 => {
381 let val = maybe_json_parse(val, from_string)?;
382 let v = u32::from_untyped(val)?;
383 encode_maybe_compact::<u32, _>(compact, v, out)
384 }
385 TypeDefPrimitive::U64 => {
386 let v = bigint_encode(val)?;
387 encode_maybe_compact::<u64, _>(compact, v, out)
388 }
389 TypeDefPrimitive::U128 => {
390 let v = bigint_encode(val)?;
391 encode_maybe_compact::<u128, _>(compact, v, out)
392 }
393 TypeDefPrimitive::U256 => {
394 ensure!(!compact, "U256 can't be compact");
395 let v: U256 = bigint_encode(val)?;
396 v.encode_to(out)
397 }
398 TypeDefPrimitive::I8 => {
399 let val = maybe_json_parse(val, from_string)?;
400 let v = i8::from_untyped(val)?;
401 v.encode_to(out)
402 }
403 TypeDefPrimitive::I16 => {
404 let val = maybe_json_parse(val, from_string)?;
405 ensure!(!compact, "int can't be compact");
406 let v = i16::from_untyped(val)?;
407 v.encode_to(out)
408 }
409 TypeDefPrimitive::I32 => {
410 let val = maybe_json_parse(val, from_string)?;
411 ensure!(!compact, "int can't be compact");
412 let v = i32::from_untyped(val)?;
413 v.encode_to(out)
414 }
415 TypeDefPrimitive::I64 => {
416 ensure!(!compact, "int can't be compact");
417 let v: i64 = bigint_encode(val)?;
418 v.encode_to(out)
419 }
420 TypeDefPrimitive::I128 => {
421 ensure!(!compact, "int can't be compact");
422 let v: i128 = bigint_encode(val)?;
423 v.encode_to(out)
424 }
425 TypeDefPrimitive::I256 => {
426 bail!("i256 not supported");
427 }
428 },
429 TypeDef::Compact(_) => encode_value(reg, typ, true, val, out, from_string)?,
430 TypeDef::BitSequence(_) => bail!("bitseq not supported"),
431 }
432 Ok(())
433}
434
435trait DecodeExt
436where
437 Self: parity_scale_codec::Decode,
438{
439 fn decode_ext<I: Input>(input: &mut I) -> Result<Self> {
440 let remaining = input
441 .remaining_len()
442 .map_err(|err| runtime_error!("codec: failed to read remaining len: {err}"))?;
443
444 match <Self as parity_scale_codec::Decode>::decode(input) {
445 Ok(value) => Ok(value),
446 Err(err) => {
447 if err == "Not enough data to fill buffer".into()
448 && let Some(expected) = Self::encoded_fixed_size()
449 && let Some(remaining) = remaining
450 {
451 Err(runtime_error!(
452 "codec: not enough bytes to decode {}: expected {} bytes, but only {} byte is available",
453 core::any::type_name::<Self>(),
454 expected,
455 remaining
456 ))
457 } else {
458 Err(runtime_error!("codec: {err}"))
459 }
460 }
461 }
462 }
463}
464
465impl<T> DecodeExt for T where T: parity_scale_codec::Decode {}
466
467fn decode_value_or_default<I>(
470 dec: &mut I,
471 reg: &PortableRegistry,
472 name: &str,
473 typ: UntrackedSymbol<TypeId>,
474 compact: bool,
475 default: Option<Vec<u8>>,
476 use_default_for_corrupted_storages: bool,
477) -> Result<Val>
478where
479 I: Input,
480{
481 let mut value = decode_value(dec, reg, typ, compact);
482
483 if let Err(err) = &value
484 && use_default_for_corrupted_storages
485 {
486 warn!("storage {name} is corrupted, default values will be used: {err}");
487
488 value = if let Some(default) = default {
489 decode_value(&mut default.as_ref(), reg, typ, compact)
490 } else {
491 Ok(Val::Null)
492 };
493 }
494
495 value
496}
497
498fn decode_value<I>(
500 dec: &mut I,
501 reg: &PortableRegistry,
502 mut typ: UntrackedSymbol<TypeId>,
503 mut compact: bool,
504) -> Result<Val>
505where
506 I: Input,
507{
508 let (new_compact, new_typ) = extract_newtypes(reg, typ, compact)?;
509 compact = new_compact;
510 typ = new_typ;
511 Ok(
512 match ®.resolve(typ.id).ok_or_else(missing_resolve)?.type_def {
513 TypeDef::Composite(c) => decode_obj_value(dec, reg, &c.fields, compact)?,
514 TypeDef::Variant(e) => {
515 let idx = u8::decode_ext(dec)?;
516 for var in e.variants.iter() {
517 if var.index == idx {
518 if var.fields.is_empty() {
519 return Ok(Val::string(var.name.as_str()));
520 }
521 let mut obj = ObjValueBuilder::new();
522 let val = decode_obj_value(dec, reg, &var.fields, compact)
523 .with_description(|| format!("variant <{}> decode", var.name))?;
524 obj.field(var.name.as_str()).try_value(val)?;
525
526 return Ok(Val::Obj(obj.build()));
527 }
528 }
529 bail!("invalid metadata: missing variant")
530 }
531 TypeDef::Sequence(seq) => {
532 if matches!(
533 reg.resolve(seq.type_param.id)
534 .ok_or_else(missing_resolve)?
535 .type_def,
536 TypeDef::Primitive(TypeDefPrimitive::U8)
537 ) {
538 let raw = <Vec<u8>>::decode_ext(dec)?;
539 return Hex::into_untyped(Hex(raw.as_slice().into()));
540 }
541
542 let mut out = vec![];
543 let size = <Compact<u32>>::decode_ext(dec)?;
544 for _ in 0..size.0 {
545 let val = decode_value(dec, reg, seq.type_param, compact)?;
546 out.push(val);
547 }
548 Val::Arr(ArrValue::eager(out))
549 }
550 TypeDef::Array(arr) => {
551 if matches!(
552 reg.resolve(arr.type_param.id)
553 .ok_or_else(missing_resolve)?
554 .type_def,
555 TypeDef::Primitive(TypeDefPrimitive::U8)
556 ) {
557 let mut raw = vec![0; arr.len as usize];
558 for v in raw.iter_mut() {
559 *v = u8::decode_ext(dec).expect("byte");
560 }
561 return Hex::into_untyped(Hex(raw.as_slice().into()));
562 }
563
564 let mut out = vec![];
565 for _ in 0..arr.len {
566 let val = decode_value(dec, reg, arr.type_param, compact)?;
567 out.push(val);
568 }
569 Val::Arr(ArrValue::eager(out))
570 }
571 TypeDef::Tuple(t) => {
572 let mut out = Vec::with_capacity(t.fields.len());
573 for t in t.fields.iter() {
574 let val = decode_value(dec, reg, *t, compact)?;
575 out.push(val);
576 }
577 Val::Arr(ArrValue::eager(out))
578 }
579 TypeDef::Primitive(p) => match p {
580 TypeDefPrimitive::Bool => {
581 let val = bool::decode_ext(dec)?;
582 Val::Bool(val)
583 }
584 TypeDefPrimitive::Char => bail!("char not supported"),
585 TypeDefPrimitive::Str => {
586 let val = String::decode_ext(dec)?;
587 Val::string(val)
588 }
589 TypeDefPrimitive::U8 => {
590 let val = u8::decode_ext(dec)?;
591 Val::Num(val.into())
592 }
593 TypeDefPrimitive::U16 => {
594 let val = decode_maybe_compact::<_, u16>(dec, compact)?;
595 Val::Num(val.into())
596 }
597 TypeDefPrimitive::U32 => {
598 let val = decode_maybe_compact::<_, u32>(dec, compact)?;
599 Val::Num(val.into())
600 }
601 TypeDefPrimitive::U64 => {
602 let val = decode_maybe_compact::<_, u64>(dec, compact)?;
603 Val::string(val.to_string())
604 }
605 TypeDefPrimitive::U128 => {
606 let val = decode_maybe_compact::<_, u128>(dec, compact)?;
607 bigint_decode(val)?
608 }
609 TypeDefPrimitive::U256 => {
610 ensure!(!compact, "u256 can't be compact");
611 let val = U256::decode_ext(dec)?;
612 bigint_decode(val)?
613 }
614 TypeDefPrimitive::I8 => {
615 let val = i8::decode_ext(dec)?;
616 Val::Num(val.into())
617 }
618 TypeDefPrimitive::I16 => {
619 ensure!(!compact, "int can't be compact");
620 let val = i16::decode_ext(dec)?;
621 Val::Num(val.into())
622 }
623 TypeDefPrimitive::I32 => {
624 ensure!(!compact, "int can't be compact");
625 let val = i32::decode_ext(dec)?;
626 Val::Num(val.into())
627 }
628 TypeDefPrimitive::I64 => {
629 ensure!(!compact, "int can't be compact");
630 let val = i64::decode_ext(dec)?;
631 bigint_decode(val)?
632 }
633 TypeDefPrimitive::I128 => {
634 ensure!(!compact, "int can't be compact");
635 let val = i128::decode_ext(dec)?;
636 bigint_decode(val)?
637 }
638 TypeDefPrimitive::I256 => {
639 bail!("i256 not supported");
640 }
641 },
642 TypeDef::Compact(c) => decode_value(dec, reg, c.type_param, true)?,
643 TypeDef::BitSequence(_) => bail!("bitseq not supported"),
644 },
645 )
646}
647
648fn fetch_decode_key(
650 key: &[u8],
651 client: Client,
652 registry: Rc<PortableRegistry>,
653 name: &str,
654 typ: UntrackedSymbol<TypeId>,
655 default: Option<Vec<u8>>,
656 use_default_for_corrupted_storages: bool,
657) -> Result<Val> {
658 let value = client.get_storage(key)?;
659 Ok(if let Some(value) = value {
660 decode_value_or_default(
661 &mut &value[..],
662 ®istry,
663 name,
664 typ,
665 false,
666 default,
667 use_default_for_corrupted_storages,
668 )?
669 } else if let Some(default) = default {
670 decode_value(&mut &default[..], ®istry, typ, false)?
671 } else {
672 unreachable!("unknown keys should not be present")
673 })
674}
675
676struct SharedMapFetcherContext {
678 client: Client,
679 reg: Rc<PortableRegistry>,
680 fetched: Vec<Vec<u8>>,
681 keys: Vec<(StorageHasher, UntrackedSymbol<TypeId>)>,
682 value_typ: UntrackedSymbol<TypeId>,
683 value_default: Option<Vec<u8>>,
684 opts: ChainOpts,
685}
686
687#[derive(Clone)]
689struct MapFetcherContext {
690 shared: Rc<SharedMapFetcherContext>,
691 name: Rc<String>,
692 prefix: Rc<Vec<u8>>,
693 current_key_depth: usize,
694}
695
696impl MapFetcherContext {
697 fn key(&self) -> Option<&(StorageHasher, UntrackedSymbol<TypeId>)> {
699 self.shared.keys.get(self.current_key_depth)
700 }
701}
702
703fn make_fetched_keys_storage(c: MapFetcherContext) -> Result<Val> {
705 let Some(key) = c.key() else {
706 return fetch_decode_key(
708 &c.prefix,
709 c.shared.client.clone(),
710 c.shared.reg.clone(),
711 &c.name,
712 c.shared.value_typ,
713 c.shared.value_default.clone(),
714 c.shared.opts.use_default_for_corrupted_storages(),
715 );
716 };
717 let hash_bytes = match key.0 {
718 StorageHasher::Blake2_128Concat => Ok(128 / 8),
719 StorageHasher::Twox64Concat => Ok(64 / 8),
720 StorageHasher::Identity => Ok(0),
721 StorageHasher::Blake2_128 => Err(128 / 8),
722 StorageHasher::Blake2_256 => Err(256 / 8),
723 StorageHasher::Twox128 => Err(128 / 8),
724 StorageHasher::Twox256 => Err(256 / 8),
725 };
726 let key_ty = key.1;
727 let mut out = ObjValueBuilder::new();
728 let mut keyout = ObjValueBuilder::new();
729 let pending_out = Pending::<ObjValue>::new();
730 let mut visited_prefixes = HashSet::new();
731 for key in &c.shared.fetched {
732 if !key.starts_with(&c.prefix) {
733 continue;
734 }
735 let key = &key[c.prefix.len()..];
736 let mut prefix = c.prefix.to_vec();
737 prefix.extend_from_slice(&key[..hash_bytes.unwrap_or(0)]);
738 let mut key = &key[hash_bytes.unwrap_or(0)..];
739 let orig_key = key;
740 let key_plus_value_len = key.len();
741 let value = if let Err(e) = hash_bytes {
742 let mut bytes = vec![0u8; e];
743 bytes.copy_from_slice(&key[..e]);
744 key = &key[e..];
745 Hex::into_untyped(Hex(bytes))?
746 } else {
747 decode_value_or_default(
748 &mut key,
749 &c.shared.reg,
750 &c.name,
751 key_ty,
752 false,
753 c.shared.value_default.clone(),
754 c.shared.opts.use_default_for_corrupted_storages(),
755 )?
756 };
757 let value_len = key_plus_value_len - key.len();
759
760 if visited_prefixes.contains(&orig_key[..value_len]) {
761 continue;
762 }
763 visited_prefixes.insert(&orig_key[..value_len]);
764
765 prefix.extend_from_slice(&orig_key[..value_len]);
766 let value = if let Some(str) = value.as_str() {
767 str
768 } else {
769 value.to_string()?
770 };
771 keyout
772 .field(value.clone())
773 .try_value(Hex::into_untyped(Hex(prefix.clone()))?)?;
774
775 if c.current_key_depth + 1 == c.shared.keys.len() {
776 let should_have_entry = c.shared.opts.include_defaults
779 && c.shared.value_default.is_some()
780 || c.shared.client.contains_key(&prefix)?;
781 if !should_have_entry {
782 continue;
783 }
784 } else {
785 let should_have_entry = c.shared.opts.include_defaults
788 && c.shared.value_default.is_some()
789 || c.shared.client.contains_data_for(&prefix)?;
790 if !should_have_entry {
791 continue;
792 }
793 }
794 let c = MapFetcherContext {
795 shared: c.shared.clone(),
796 name: Rc::new(value.to_string()),
797 prefix: Rc::new(prefix),
798 current_key_depth: c.current_key_depth + 1,
799 };
800 let bound = simple_thunk! {
801 #[trace(skip)]
802 let c: MapFetcherContext = c;
803 Thunk::<Val>::evaluated(make_fetched_keys_storage(c)?)
804 };
805 out.field(value.clone()).try_thunk(bound)?;
806 }
807 let preload_keys = simple_thunk! {
808 let shared: Rc<SharedMapFetcherContext> = c.shared;
809 let prefix: Rc<Vec<u8>> = c.prefix;
810 let pending_out: Pending<ObjValue> = pending_out.clone();
811 Thunk::<Val>::evaluated({
812 eprintln!("preloading subset of keys by prefix: {prefix:0>2x?}");
813 let prefixes = shared.fetched.iter().filter(|k| k.starts_with(&prefix)).collect::<Vec<_>>();
814 shared.client.preload_storage(prefixes.as_slice())?;
815 Val::Obj(pending_out.unwrap())
816 })
817 };
818 out.field("_preloadKeys").hide().try_thunk(preload_keys)?;
819 out.field("_key").hide().try_value(keyout.build())?;
820 let out = out.build();
821 pending_out.fill(out.clone());
822 Ok(Val::Obj(out))
823}
824
825fn make_fetch_keys_storage(
827 client: Client,
828 name: String,
829 prefix: Vec<u8>,
830 reg: Rc<PortableRegistry>,
831 keys: Vec<(StorageHasher, UntrackedSymbol<TypeId>)>,
832 value_typ: UntrackedSymbol<TypeId>,
833 value_default: Option<Vec<u8>>,
834 opts: ChainOpts,
835) -> Result<Val> {
836 let fetched = client.get_keys(prefix.as_slice())?;
837 make_fetched_keys_storage(MapFetcherContext {
838 shared: Rc::new(SharedMapFetcherContext {
839 client,
840 reg,
841 fetched,
842 keys,
843 value_typ,
844 value_default,
845 opts,
846 }),
847 name: Rc::new(name),
848 prefix: Rc::new(prefix),
849 current_key_depth: 0,
850 })
851}
852
853fn make_pallet_key(
855 client: Client,
856 data: PalletMetadata<PortableForm>,
857 registry: Rc<PortableRegistry>,
858 opts: ChainOpts,
859) -> Result<ObjValue> {
860 let mut out = ObjValueBuilder::new();
861 let mut keyout = ObjValueBuilder::new();
862 let mut encode_keyout = ObjValueBuilder::new();
863 let mut encode_valueout = ObjValueBuilder::new();
864 let mut decode_valueout = ObjValueBuilder::new();
865 let mut key_args = ObjValueBuilder::new();
866 let Some(storage) = data.storage else {
867 unreachable!("pallets with no storage are not added to the state map");
868 };
869 let pallet_key = sp_core::twox_128(storage.prefix.as_bytes());
870 let mut known_prefixes = Vec::new();
871 for entry in storage.entries {
872 let key_key = sp_core::twox_128(entry.name.as_bytes());
873 let mut entry_key = vec![];
874 entry_key.extend_from_slice(&pallet_key);
875 entry_key.extend_from_slice(&key_key);
876 known_prefixes.push(entry_key.clone());
877 if opts.omit_empty && !client.contains_data_for(&entry_key)? {
878 continue;
879 }
880 let default = match entry.modifier {
881 StorageEntryModifier::Optional => None,
882 StorageEntryModifier::Default => Some(entry.default),
883 };
884 keyout
885 .field(entry.name.clone())
886 .try_value(Hex::into_untyped(Hex(entry_key.clone()))?)?;
887 match entry.ty {
888 StorageEntryType::Plain(v) => {
889 encode_keyout.try_method(
890 entry.name.clone(),
891 builtin_encode_key {
892 reg: registry.clone(),
893 prefix: Rc::new(entry_key.clone()),
894 key: Key(vec![]),
895 },
896 )?;
897 encode_valueout.try_method(
898 entry.name.clone(),
899 builtin_encode_value {
900 reg: registry.clone(),
901 ty: ValueId(v),
902 },
903 )?;
904 decode_valueout.try_method(
905 entry.name.clone(),
906 builtin_decode_value {
907 reg: registry.clone(),
908 ty: ValueId(v),
909 },
910 )?;
911
912 let should_have_entry = opts.include_defaults && default.is_some()
914 || client.contains_key(&entry_key)?;
915 if !should_have_entry {
916 continue;
917 }
918
919 out.field(entry.name.clone()).try_thunk(simple_thunk! {
920 let entry_name: String = entry.name.clone();
921 let entry_key: Vec<u8> = entry_key;
922 let client: Client = client.clone();
923 #[trace(skip)]
924 let typ: UntrackedSymbol<TypeId> = v;
925 let default: Option<Vec<u8>> = default;
926 let registry: Rc<PortableRegistry> = registry.clone();
927 let use_default_for_corrupted_storages: bool = opts.use_default_for_corrupted_storages();
928 Thunk::<Val>::evaluated(fetch_decode_key(
929 entry_key.as_slice(),
930 client,
931 registry,
932 &entry_name,
933 typ,
934 default,
935 use_default_for_corrupted_storages,
936 )?)
937 })?;
938 }
939 StorageEntryType::Map {
940 hashers,
941 key,
942 value,
943 } => {
944 let keys = normalize_storage_map_keys(®istry, key, &hashers)?;
945 encode_keyout.try_method(
946 entry.name.clone(),
947 builtin_encode_key {
948 reg: registry.clone(),
949 prefix: Rc::new(entry_key.clone()),
950 key: Key(keys.clone()),
951 },
952 )?;
953 encode_valueout.try_method(
954 entry.name.clone(),
955 builtin_encode_value {
956 reg: registry.clone(),
957 ty: ValueId(value),
958 },
959 )?;
960 decode_valueout.try_method(
961 entry.name.clone(),
962 builtin_decode_value {
963 reg: registry.clone(),
964 ty: ValueId(value),
965 },
966 )?;
967 key_args
968 .field(entry.name.clone())
969 .try_value(Val::Num(NumValue::new(keys.len() as f64).unwrap()))?;
970
971 out.field(entry.name.clone()).try_thunk(simple_thunk! {
972 let entry_name: String = entry.name.clone();
973 let entry_key: Vec<u8> = entry_key;
974 let client: Client = client.clone();
975 #[trace(skip)]
976 let value: UntrackedSymbol<TypeId> = value;
977 let default: Option<Vec<u8>> = default;
978 let registry: Rc<PortableRegistry> = registry.clone();
979 #[trace(skip)]
980 let keys: Vec<(StorageHasher, UntrackedSymbol<TypeId>)> = keys;
981 let opts: ChainOpts = opts;
982 Thunk::<Val>::evaluated(make_fetch_keys_storage(
983 client,
984 entry_name,
985 entry_key,
986 registry,
987 keys,
988 value,
989 default,
990 opts,
991 )?)
992 })?;
993 }
994 }
995 }
996 out.field("_unknown").try_thunk(simple_thunk! {
997 let client: Client = client.clone();
998 let known_prefixes: Vec<Vec<u8>> = known_prefixes;
999 let pallet_key: Vec<u8> = pallet_key.to_vec();
1000 Thunk::<Val>::evaluated({
1003 Val::Obj(make_unknown_key(client, &pallet_key, &known_prefixes.iter().collect::<Vec<_>>())?)
1004 })
1005 })?;
1006 out.field("_key").hide().try_value(keyout.build())?;
1007 out.field("_encodeKey")
1008 .hide()
1009 .try_value(encode_keyout.build())?;
1010 out.field("_encodeValue")
1011 .hide()
1012 .try_value(encode_valueout.build())?;
1013 out.field("_decodeValue")
1014 .hide()
1015 .try_value(decode_valueout.build())?;
1016 out.field("_keyArgs").hide().try_value(key_args.build())?;
1017 Ok(out.build())
1018}
1019
1020#[builtin(fields(
1021 meta: Rc<RuntimeMetadataV14>,
1022))]
1023fn builtin_rebuild(this: &builtin_rebuild, data: ObjValue) -> Result<BTreeMap<Hex, Hex>> {
1024 rebuild(data, &this.meta)
1025}
1026
1027fn fetch_raw(key: Vec<u8>, client: Client) -> Result<Val> {
1029 let value = client.get_storage(key.as_slice())?;
1030 Ok(if let Some(value) = value {
1031 Hex::into_untyped(Hex(value))?
1032 } else {
1033 Val::Null
1035 })
1036}
1037fn make_unknown_key(client: Client, prefix: &[u8], known: &[&Vec<u8>]) -> Result<ObjValue> {
1038 let mut out = ObjValueBuilder::new();
1039 let pending_out = Pending::<ObjValue>::new();
1040 let fetched = client.get_unknown_keys(prefix, known)?;
1041 for key in fetched.iter().cloned() {
1042 let key_str = hex::to_hex(&key[prefix.len()..]);
1043 let value = simple_thunk! {
1044 let key: Vec<u8> = key;
1045 let client: Client = client.clone();
1046 Thunk::<Val>::evaluated(fetch_raw(key, client)?)
1047 };
1048 out.field(key_str).try_thunk(value)?;
1049 }
1050 let preload_keys = simple_thunk! {
1052 let pending_out: Pending<ObjValue> = pending_out.clone();
1053 let client: Client = client;
1054 let fetched: Vec<Vec<u8>> = fetched;
1055 Thunk::<Val>::evaluated({
1056 info!("preloading all storage keys");
1057 client.preload_storage(&fetched.iter().collect::<Vec<_>>())?;
1058 Val::Obj(pending_out.unwrap())
1059 })
1060 };
1061 out.field("_preloadKeys").hide().try_thunk(preload_keys)?;
1062 let out = out.build();
1063 pending_out.fill(out.clone());
1064 Ok(out)
1065}
1066
1067#[derive(Trace, Clone)]
1069struct Key(#[trace(skip)] Vec<(StorageHasher, UntrackedSymbol<TypeId>)>);
1070
1071#[builtin(fields(
1075 reg: Rc<PortableRegistry>,
1076 prefix: Rc<Vec<u8>>,
1077 key: Key,
1078))]
1079fn builtin_encode_key(
1080 this: &builtin_encode_key,
1081 keyi: Vec<Val>,
1082 from_string: Option<bool>,
1083) -> Result<Hex> {
1084 let from_string = from_string.unwrap_or(false);
1085 let reg = this.reg.clone();
1086 let key = this.key.clone();
1087
1088 ensure!(
1089 key.0.len() == keyi.len(),
1090 "wrong number of keys, expected {}, got {}",
1091 key.0.len(),
1092 keyi.len()
1093 );
1094
1095 let mut out = this.prefix.as_slice().to_owned();
1096
1097 for ((h, t), k) in key.0.iter().zip(keyi) {
1098 encode_single_key(®, h.clone(), *t, k, &mut out, from_string)?;
1099 }
1100
1101 Ok(Hex(out))
1102}
1103
1104fn encode_single_key(
1105 reg: &PortableRegistry,
1106 hasher: StorageHasher,
1107 ty: UntrackedSymbol<TypeId>,
1108 value: Val,
1109 out: &mut Vec<u8>,
1110 from_string: bool,
1111) -> Result<()> {
1112 if from_string {
1113 'fs: {
1114 let size = match hasher {
1115 StorageHasher::Blake2_128 => 128 / 8,
1116 StorageHasher::Blake2_256 => 256 / 8,
1117 StorageHasher::Twox128 => 128 / 8,
1118 StorageHasher::Twox256 => 256 / 8,
1119 _ => break 'fs,
1120 };
1121
1122 let Some(str) = value.as_str() else {
1123 bail!("key from string encoding with non-concat hasher only accepts hash string");
1124 };
1125
1126 ensure!(
1127 str.len() == size * 2 + 2 && str.starts_with("0x"),
1128 "key from string encoding with non-concat hasher only accepts hash string"
1129 );
1130 let hex = hex::from_hex(&str)?;
1131 out.extend_from_slice(&hex);
1132 return Ok(());
1133 }
1134 }
1135
1136 let mut encoded_key = vec![];
1137 encode_value(reg, ty, false, value, &mut encoded_key, from_string)?;
1138 let (hash, concat) = match hasher {
1139 StorageHasher::Blake2_128 => (blake2_128(&encoded_key).to_vec(), false),
1140 StorageHasher::Blake2_256 => (blake2_256(&encoded_key).to_vec(), false),
1141 StorageHasher::Blake2_128Concat => (blake2_128(&encoded_key).to_vec(), true),
1142 StorageHasher::Twox128 => (twox_128(&encoded_key).to_vec(), false),
1143 StorageHasher::Twox256 => (twox_256(&encoded_key).to_vec(), false),
1144 StorageHasher::Twox64Concat => (twox_64(&encoded_key).to_vec(), true),
1145 StorageHasher::Identity => (vec![], true),
1146 };
1147 out.extend(&hash);
1148 if concat {
1149 out.extend(&encoded_key);
1150 }
1151 Ok(())
1152}
1153
1154#[derive(Trace, Clone)]
1156struct ValueId(#[trace(skip)] UntrackedSymbol<TypeId>);
1157
1158#[builtin(fields(
1162 reg: Rc<PortableRegistry>,
1163 ty: ValueId,
1164))]
1165fn builtin_encode_value(this: &builtin_encode_value, value: Val) -> Result<Hex> {
1166 let reg = this.reg.clone();
1167
1168 let mut out = Vec::new();
1169 encode_value(®, this.ty.0, false, value, &mut out, false)?;
1170 Ok(Hex(out))
1171}
1172
1173#[builtin(fields(
1177 reg: Rc<PortableRegistry>,
1178 ty: ValueId,
1179))]
1180fn builtin_decode_value(this: &builtin_decode_value, value: Hex) -> Result<Val> {
1181 decode_value(&mut value.0.as_slice(), &this.reg, this.ty.0, false).map(Val::from)
1182}
1183
1184#[builtin(fields(
1188 reg: Rc<PortableRegistry>,
1189))]
1190fn builtin_encode(this: &builtin_encode, typ: u32, v: Val) -> Result<Hex> {
1191 let typ = Compact(typ).encode();
1192 let sym = <UntrackedSymbol<TypeId>>::decode_ext(&mut typ.as_slice()).expect("just encoded u32");
1193 let mut out = Vec::new();
1194 encode_value(&this.reg, sym, false, v, &mut out, false)?;
1195
1196 Ok(Hex(out))
1197}
1198
1199#[builtin(fields(
1203 reg: Rc<PortableRegistry>,
1204))]
1205fn builtin_decode(this: &builtin_decode, typ: u32, v: Hex) -> Result<Val> {
1206 let typ = Compact(typ).encode();
1207 let sym = <UntrackedSymbol<TypeId>>::decode_ext(&mut typ.as_slice()).expect("just encoded u32");
1208
1209 decode_value(&mut v.0.as_slice(), &this.reg, sym, false).map(Val::from)
1210}
1211
1212#[derive(Typed)]
1213struct ExtrinsicData {
1214 signature: Option<Signature>,
1215 call: Val,
1216}
1217#[derive(Typed)]
1218struct Signature {
1219 address: Val,
1220 signature: Val,
1221 extra: BTreeMap<String, Val>,
1222}
1223
1224struct ExtrinsicEncoding {
1225 version: u8,
1226 address: UntrackedSymbol<TypeId>,
1227 address_type: AddressType,
1228 call: UntrackedSymbol<TypeId>,
1229 signature: UntrackedSymbol<TypeId>,
1230 signature_type: SignatureType,
1231 extra: Vec<(String, UntrackedSymbol<TypeId>, UntrackedSymbol<TypeId>)>,
1233}
1234fn guess_extrinsic_encoding(metadata: &RuntimeMetadataV14) -> Result<ExtrinsicEncoding> {
1235 let extrinsic_ty = metadata.extrinsic.ty;
1236 let extrinsic = metadata
1237 .types
1238 .resolve(extrinsic_ty.id)
1239 .expect("extrinsic ty");
1240
1241 let mut params = extrinsic.type_params.iter();
1242 let Some(address) = params.next() else {
1243 bail!("param not found");
1244 };
1245 ensure!(address.name == "Address", "not address");
1246 let Some(address) = address.ty else {
1247 bail!("param not set");
1248 };
1249
1250 let Some(call) = params.next() else {
1251 bail!("param not found");
1252 };
1253 ensure!(call.name == "Call", "not call");
1254 let Some(call) = call.ty else {
1255 bail!("param not set");
1256 };
1257
1258 let Some(signature) = params.next() else {
1259 bail!("param not found");
1260 };
1261 ensure!(signature.name == "Signature", "not signature");
1262 let Some(signature) = signature.ty else {
1263 bail!("param not set");
1264 };
1265
1266 let Some(extra) = params.next() else {
1267 bail!("param not found");
1268 };
1269 ensure!(extra.name == "Extra", "not extra");
1270 let Some(extra) = extra.ty else {
1271 bail!("param not set");
1272 };
1273 let _ = extra;
1274
1275 let mut extra = vec![];
1276 let mut had_extra = BTreeSet::new();
1277 for ele in metadata.extrinsic.signed_extensions.iter() {
1278 extra.push((ele.identifier.clone(), ele.ty, ele.additional_signed));
1279 if !had_extra.insert(&ele.identifier) {
1280 bail!(
1281 "signed extension {} appeared twice, this is not supported",
1282 ele.identifier
1283 );
1284 };
1285 }
1286
1287 let sigty = metadata
1288 .types
1289 .resolve(signature.id)
1290 .expect("missing signature");
1291 let signature_type = if sigty.path.segments == ["sp_runtime", "MultiSignature"] {
1292 SignatureType::MultiSignature
1293 } else {
1294 bail!("unknown signature type: {:?}", sigty.path);
1295 };
1296
1297 let addrty = metadata.types.resolve(address.id).expect("missing address");
1298 let address_type = if addrty.path.segments == ["sp_runtime", "multiaddress", "MultiAddress"] {
1299 let mut params = addrty.type_params.iter();
1300 let Some(addr) = params.next() else {
1301 bail!("missing multiaddr generic");
1302 };
1303 ensure!(addr.name == "AccountId", "not param");
1304 let Some(addr) = addr.ty else {
1305 bail!("missing addr");
1306 };
1307
1308 let inaddrty = metadata.types.resolve(addr.id).expect("missing inaddr");
1309 dbg!(&inaddrty.path);
1310
1311 let default = if inaddrty.path.segments == ["sp_core", "crypto", "AccountId32"] {
1312 AddressSchema::Id32
1313 } else {
1314 bail!("unknown inaddr type: {:?}", inaddrty.path);
1315 };
1316
1317 AddressType::MultiAddress { default }
1318 } else {
1319 bail!("unknown address type: {:?}", addrty.path);
1320 };
1321
1322 Ok(ExtrinsicEncoding {
1323 version: metadata.extrinsic.version,
1324 address,
1325 address_type,
1326 call,
1327 signature,
1328 signature_type,
1329 extra,
1330 })
1331}
1332
1333#[builtin(fields(
1334 meta: Rc<RuntimeMetadataV14>,
1335))]
1336fn builtin_decode_extrinsic(
1337 this: &builtin_decode_extrinsic,
1338 value: Hex,
1339 additional_signed: Option<NativeFn<((Val,), ObjValue)>>,
1340) -> Result<ExtrinsicData> {
1341 let encoding = guess_extrinsic_encoding(&this.meta)?;
1342
1343 let data = value.0;
1344 let mut cursor = data.as_slice();
1345
1346 let length =
1347 <Compact<u32>>::decode_ext(&mut cursor).map_err(|e| runtime_error!("bad length: {e}"))?;
1348 ensure!(cursor.len() == length.0 as usize, "length mismatch");
1349
1350 let version = u8::decode_ext(&mut cursor).map_err(|e| runtime_error!("bad ver: {e}"))?;
1351
1352 let is_signed = version & 0b10000000 != 0;
1353 let version = version & 0b01111111;
1354
1355 ensure!(version == encoding.version, "extrinsic version mismatch");
1356
1357 let signature = if is_signed {
1358 let address = decode_value(&mut cursor, &this.meta.types, encoding.address, false)
1359 .map_err(|e| runtime_error!("bad address: {e}"))?;
1360 let signature = decode_value(&mut cursor, &this.meta.types, encoding.signature, false)
1361 .map_err(|e| runtime_error!("bad signature encoding: {e}"))?;
1362 let mut extra = BTreeMap::new();
1363 for (name, data, _) in encoding.extra.iter() {
1364 let data = decode_value(&mut cursor, &this.meta.types, *data, false)?;
1365 extra.insert(name.clone(), data);
1366 }
1367 Some(Signature {
1369 address,
1370 signature,
1371 extra,
1372 })
1373 } else {
1374 None
1375 };
1376 let call = decode_value(&mut cursor, &this.meta.types, encoding.call, false)
1377 .map_err(|e| runtime_error!("bad call encoding: {e}"))?;
1378 ensure!(cursor.is_empty(), "unexpected trailing data");
1379
1380 if let Some(signature) = &signature {
1381 let mut call_data = vec![];
1382 encode_value(
1383 &this.meta.types,
1384 encoding.call,
1385 false,
1386 call.clone(),
1387 &mut call_data,
1388 false,
1389 )?;
1390 let mut signing_payload = call_data;
1391 for (name, format, _) in encoding.extra.iter() {
1392 let data = signature.extra.get(name).expect("aaa");
1393 encode_value(
1394 &this.meta.types,
1395 *format,
1396 false,
1397 data.clone(),
1398 &mut signing_payload,
1399 false,
1400 )
1401 .with_description(|| format!("while encoding extra {name} ([] by default)"))?;
1402 }
1403 if let Some(data) = additional_signed {
1404 for (name, _, format) in encoding.extra.iter() {
1405 let data = data(BTreeMap::into_untyped(signature.extra.clone())?)?
1406 .get(name.into())
1407 .with_description(|| format!("getting data for {name}"))?
1408 .unwrap_or_else(|| Val::Arr(ArrValue::empty()));
1409 encode_value(
1410 &this.meta.types,
1411 *format,
1412 false,
1413 data,
1414 &mut signing_payload,
1415 false,
1416 )
1417 .with_description(|| {
1418 format!("while encoding signedextra {name} ([] by default)")
1419 })?;
1420 }
1421 }
1422 dbg!(signing_payload.len());
1423 if !verify_signature(
1424 encoding.signature_type,
1425 signature.signature.clone(),
1426 encoding.address_type,
1427 signature.address.clone(),
1428 Hex(signing_payload),
1429 )? {
1430 bail!("invalid signature");
1431 }
1432 }
1433
1434 Ok(ExtrinsicData { signature, call })
1435}
1436
1437#[builtin]
1448fn builtin_ss58(v: IStr) -> Result<Hex> {
1449 let s = sp_core::crypto::AccountId32::from_string(&v)
1450 .map_err(|e| runtime_error!("wrong ss58: {e}"))?;
1451 Ok(Hex(s.as_slice().into()))
1452}
1453#[builtin]
1454fn builtin_ss58_encode(raw: Hex, format: Option<Ss58Format>) -> Result<IStr> {
1455 let format = format.unwrap_or_default();
1456 let s = sp_core::crypto::AccountId32::from_slice(&raw)
1457 .map_err(|()| runtime_error!("bad accountid32 length"))?;
1458 let out = s.to_ss58check_with_version(format.0);
1459 Ok(out.into())
1460}
1461
1462#[builtin]
1463fn builtin_description(description: IStr, value: Thunk<Val>) -> Result<Val> {
1464 value.evaluate().description(&description)
1465}
1466
1467fn make_block(client: Client, opts: ChainOpts) -> Result<ObjValue> {
1469 let mut out = ObjValueBuilder::new();
1470 let pending_out = Pending::<ObjValue>::new();
1471 let meta = client.get_metadata()?;
1472 let reg = Rc::new(meta.types.clone());
1473 for pallet in &meta.pallets {
1474 let Some(storage) = &pallet.storage else {
1475 continue;
1476 };
1477 if opts.omit_empty {
1478 let pallet_key = sp_core::twox_128(storage.prefix.as_bytes());
1479 if !client.contains_data_for(&pallet_key)? {
1480 continue;
1481 }
1482 }
1483 out.field(pallet.name.clone()).try_thunk(simple_thunk! {
1484 let client: Client = client.clone();
1485 #[trace(skip)]
1486 let pallet: PalletMetadata<PortableForm> = pallet.clone();
1487 let reg: Rc<PortableRegistry> = reg.clone();
1488 let opts: ChainOpts = opts;
1489 Thunk::<Val>::evaluated(Val::Obj(make_pallet_key(client, pallet, reg, opts)?))
1490 })?;
1491 }
1492 out.field("_raw").hide().try_thunk(simple_thunk! {
1493 let client: Client = client.clone();
1494 Thunk::<Val>::evaluated(Val::Obj(make_unknown_key(client, &[], &[])?))
1495 })?;
1496 let meta_key = metadata_obj(&meta);
1497 out.field("_meta").hide().try_value(meta_key)?;
1498 let meta = Rc::new(meta);
1499 out.field("_unknown").try_thunk(simple_thunk! {
1500 let client: Client = client.clone();
1501 #[trace(skip)]
1502 let meta: Rc<RuntimeMetadataV14> = meta.clone();
1503 Thunk::<Val>::evaluated({
1504 let mut known = Vec::new();
1505 for pallet in &meta.pallets {
1506 let Some(storage) = &pallet.storage else {
1507 continue;
1508 };
1509 let pallet_key = sp_core::twox_128(storage.prefix.as_bytes());
1510 known.push(pallet_key.to_vec());
1511 }
1512 Val::Obj(make_unknown_key(client, &[], &known.iter().collect::<Vec<_>>())?)
1513 })
1514 })?;
1515 out.method("_encode", builtin_encode { reg: reg.clone() });
1516 out.method("_decode", builtin_decode { reg });
1517 out.method(
1518 "_decodeExtrinsic",
1519 builtin_decode_extrinsic { meta: meta.clone() },
1520 );
1521 out.method("_rebuild", builtin_rebuild { meta: meta.clone() });
1522
1523 let preload_keys = simple_thunk! {
1524 let pending_out: Pending<ObjValue> = pending_out.clone();
1525 let client: Client = client.clone();
1526 Thunk::<Val>::evaluated({
1527 info!("preloading all keys");
1528 let keys = client.get_keys(&[])?;
1529 client.preload_storage(keys.iter().collect::<Vec<_>>().as_slice())?;
1530 Val::Obj(pending_out.unwrap())
1531 })
1532 };
1533 out.field("_preloadKeys").hide().try_thunk(preload_keys)?;
1534 let out = out.build();
1535 pending_out.fill(out.clone());
1536 Ok(out)
1537}
1538
1539#[builtin(fields(
1543 client: ClientShared,
1544 opts: ChainOpts,
1545))]
1546fn chain_block(this: &chain_block, block: u32) -> Result<ObjValue> {
1547 make_block(
1548 Client::new(
1549 this.client
1550 .block(Some(block))
1551 .map_err(client::Error::Live)?,
1552 ),
1553 this.opts,
1554 )
1555}
1556
1557#[derive(Typed, Trace, Default, Clone, Copy, Debug)]
1559pub struct ChainOpts {
1560 pub omit_empty: bool,
1562 pub include_defaults: bool,
1564 pub use_default_for_corrupted_storages: Option<bool>,
1566}
1567
1568impl ChainOpts {
1569 fn use_default_for_corrupted_storages(&self) -> bool {
1570 self.use_default_for_corrupted_storages.unwrap_or(false)
1571 }
1572}
1573
1574#[builtin(fields(
1584 default_opts: ChainOpts,
1585))]
1586fn builtin_chain(this: &builtin_chain, url: String, opts: Option<ChainOpts>) -> Result<ObjValue> {
1587 let opts = opts.unwrap_or(this.default_opts);
1588 let client = ClientShared::new(url).map_err(client::Error::Live)?;
1589 let mut obj = ObjValueBuilder::new();
1590 obj.method(
1591 "block",
1592 chain_block {
1593 client: client.clone(),
1594 opts,
1595 },
1596 );
1597 obj.field("latest")
1598 .hide()
1599 .try_thunk(simple_thunk!{
1600 let client: ClientShared = client;
1601 let opts: ChainOpts = opts;
1602 Thunk::<Val>::evaluated(Val::Obj(make_block(Client::new(client.block(None).map_err(client::Error::Live)?), opts)?))
1603 })?;
1604 Ok(obj.build())
1605}
1606
1607#[builtin]
1608fn builtin_twox128_of_string(data: IStr) -> Result<Hex> {
1609 let data = sp_core::twox_128(data.as_bytes());
1610 Ok(Hex(data.into()))
1611}
1612
1613#[builtin]
1614fn builtin_keccak256(data: Hex) -> Hex {
1615 Hex(keccak_256(&data).into())
1616}
1617
1618#[builtin(fields(
1632 default_opts: ChainOpts,
1633))]
1634fn builtin_dump(
1635 this: &builtin_dump,
1636 meta: Either![ObjValue, Hex],
1637 data: BTreeMap<Hex, Hex>,
1638 opts: Option<ChainOpts>,
1639) -> Result<ObjValue> {
1640 let opts = opts.unwrap_or(this.default_opts);
1641
1642 fn types_ordered(r: &PortableRegistry) -> bool {
1643 for (i, t) in r.types.iter().enumerate() {
1644 if i as u32 != t.id {
1645 return false;
1646 }
1647 }
1648 true
1649 }
1650
1651 let mut meta: RuntimeMetadataV14 = match meta {
1652 Either2::A(obj) => serde_json::from_value(
1653 serde_json::to_value(Val::Obj(obj)).map_err(|e| runtime_error!("bad metadata: {e}"))?,
1654 )
1655 .map_err(|e| runtime_error!("bad metadata: {e}"))?,
1656 Either2::B(meta) => {
1657 match RuntimeMetadataPrefixed::decode_ext(&mut meta.0.as_slice())
1658 .map_err(|e| runtime_error!("bad metadata: {e}"))?
1659 .1
1660 {
1661 RuntimeMetadata::V14(meta) => meta,
1662 _ => bail!("unknown metadata version"),
1663 }
1664 }
1665 };
1666
1667 if !types_ordered(&meta.types) {
1668 meta.types.types.sort_by_key(|t| t.id);
1669 ensure!(
1670 types_ordered(&meta.types),
1671 "there are gaps in portable registry data"
1672 );
1673 }
1674
1675 make_block(
1676 Client::new(ClientDump {
1677 meta,
1678 data: data.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
1679 }),
1680 opts,
1681 )
1682}
1683
1684#[builtin(fields(
1685 cache_path: Option<PathBuf>,
1686 default_opts: ChainOpts,
1687))]
1688fn builtin_full_dump(
1689 this: &builtin_full_dump,
1690 data: BTreeMap<Hex, Hex>,
1691 opts: Option<ChainOpts>,
1692) -> Result<ObjValue> {
1693 let Some(code) = data.get(&Hex::encode_str(":code")) else {
1694 bail!("there is no code stored in the provided dump");
1695 };
1696 let runtime = RuntimeContainer::new(code.0.clone(), this.cache_path.as_deref());
1697 let meta = runtime.metadata()?;
1698 builtin_dump(
1699 &builtin_dump {
1700 default_opts: this.default_opts,
1701 },
1702 Either2::B(Hex(meta)),
1703 data,
1704 opts,
1705 )
1706}
1707
1708#[builtin]
1709fn builtin_blake2_256_root(tree: BTreeMap<Hex, Hex>, state_version: u8) -> Result<Hex> {
1710 let state_version = match state_version {
1711 0 => StateVersion::V0,
1712 1 => StateVersion::V1,
1713 _ => bail!("unknown state version"),
1714 };
1715 let pairs = tree
1716 .into_iter()
1717 .map(|(k, v)| (k.0, v.0))
1718 .collect::<Vec<_>>();
1719 Ok(Hex(blake2_256_root(pairs, state_version).as_bytes().into()))
1720}
1721
1722pub fn create_cql(wasm_cache_path: Option<PathBuf>, default_opts: ChainOpts) -> ObjValue {
1723 let mut cql = ObjValueBuilder::new();
1725 cql.method("chain", builtin_chain { default_opts });
1726 cql.method("dump", builtin_dump { default_opts });
1727
1728 cql.method("toHex", builtin_to_hex::INST);
1729 cql.method("fromHex", builtin_from_hex::INST);
1730
1731 cql.method("ss58", builtin_ss58::INST);
1732 cql.method("ss58Encode", builtin_ss58_encode::INST);
1733 cql.method("ss58Decode", builtin_ss58::INST);
1734 cql.method("ethEncode", builtin_eth_encode::INST);
1735
1736 cql.method("seed", builtin_seed::INST);
1737 cql.method("sr25519Seed", builtin_sr25519_seed::INST);
1738 cql.method("ed25519Seed", builtin_ed25519_seed::INST);
1739 cql.method("ecdsaSeed", builtin_ecdsa_seed::INST);
1740 cql.method("ethereumSeed", builtin_ethereum_seed::INST);
1741
1742 cql.method("addressSeed", builtin_address_seed::INST);
1743 cql.method("sr25519AddressSeed", builtin_sr25519_address_seed::INST);
1744 cql.method("ed25519AddressSeed", builtin_ed25519_address_seed::INST);
1745 cql.method("ecdsaAddressSeed", builtin_ecdsa_address_seed::INST);
1746 cql.method("ethereumAddressSeed", builtin_ethereum_address_seed::INST);
1747
1748 cql.method("twox128String", builtin_twox128_of_string::INST);
1749 cql.method("keccak256", builtin_keccak256::INST);
1750
1751 cql.method("blake2_256Root", builtin_blake2_256_root::INST);
1752
1753 cql.method(
1754 "fullDump",
1755 builtin_full_dump {
1756 cache_path: wasm_cache_path.clone(),
1757 default_opts,
1758 },
1759 );
1760 cql.method(
1761 "runtimeWasm",
1762 builtin_runtime_wasm {
1763 cache_path: wasm_cache_path,
1764 },
1765 );
1766
1767 cql.method("description", builtin_description::INST);
1768
1769 cql.build()
1770}
1771
1772#[derive(Trace)]
1773pub struct CqlContextInitializer {
1774 cql: Thunk<Val>,
1775}
1776impl CqlContextInitializer {
1777 pub fn new(wasm_cache_path: Option<PathBuf>, opts: Option<ChainOpts>) -> Self {
1778 let wasm_cache_path = wasm_cache_path.or_else(|| {
1779 BaseDirs::new().map(|b| {
1780 let mut d = b.cache_dir().to_owned();
1781 d.push("chainql");
1782 d
1783 })
1784 });
1785 let opts = opts.unwrap_or_default();
1786 Self {
1787 cql: Thunk::evaluated(Val::Obj(create_cql(wasm_cache_path, opts))),
1788 }
1789 }
1790}
1791impl Default for CqlContextInitializer {
1792 fn default() -> Self {
1793 Self::new(None, None)
1794 }
1795}
1796
1797impl ContextInitializer for CqlContextInitializer {
1798 fn reserve_vars(&self) -> usize {
1799 1
1800 }
1801 fn populate(
1802 &self,
1803 _for_file: jrsonnet_evaluator::parser::Source,
1804 _builder: &mut jrsonnet_evaluator::ContextBuilder,
1805 ) {
1806 _builder.bind("cql", self.cql.clone());
1807 }
1808 fn as_any(&self) -> &dyn std::any::Any {
1809 self
1810 }
1811}
1812
1813pub fn normalize_storage_map_keys(
1814 registry: &PortableRegistry,
1815 key: UntrackedSymbol<TypeId>,
1816 hashers: &[StorageHasher],
1817) -> Result<Vec<(StorageHasher, UntrackedSymbol<TypeId>)>> {
1818 let tuple = registry.resolve(key.id).expect("key tuple");
1819 let fields: Vec<_> = match &tuple.type_def {
1820 TypeDef::Composite(t) => t.fields.iter().map(|f| f.ty).collect(),
1821 TypeDef::Tuple(t) if hashers.len() != 1 => t.fields.to_vec(),
1822 _ => [key].into_iter().collect(),
1823 };
1824
1825 let keys = if hashers.len() == 1 {
1826 vec![(hashers[0].clone(), key)]
1827 } else {
1828 ensure!(
1829 hashers.len() == fields.len(),
1830 "bad tuple: {:?} {:?}",
1831 hashers,
1832 tuple.type_def,
1833 );
1834
1835 hashers
1836 .iter()
1837 .cloned()
1838 .zip(fields.iter().copied())
1839 .collect::<Vec<(_, _)>>()
1840 };
1841 Ok(keys)
1842}