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