chainql_core/
lib.rs

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
54/// Translate metadata into Jrsonnet's Val.
55fn 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
60/// Create a lazily-evaluated thunk by wrapping the call inside.
61macro_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/// Return an Err from a formatted string if the condition is not met.
93#[macro_export]
94macro_rules! ensure {
95    ($cond:expr, $($tt:tt)+) => {
96        if !($cond) {
97            jrsonnet_evaluator::bail!($($tt)+)
98        }
99    };
100}
101
102/// Return a missing resolve error.
103fn missing_resolve() -> JrError {
104	runtime_error!("invalid metadata: missing resolve key")
105}
106
107/// Return a codec error.
108fn codec_error(err: parity_scale_codec::Error) -> JrError {
109	runtime_error!("codec: {}", err)
110}
111
112/// Decode a value as it is or into compact.
113fn 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
126/// Encode a value as it is or into compact, adding the output to [`dest`].
127fn 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
140/// Encode the contents of an object according to the supplied types [`typ`] into [`Val`], adding it to [`out`].
141fn 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
175/// Decode the contents of an object according to the supplied types [`typ`].
176fn 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
197/// Unpack a complex or wrapping type into the type it wraps.
198fn extract_newtypes(
199	reg: &PortableRegistry,
200	typ: UntrackedSymbol<TypeId>,
201	compact: bool,
202) -> Result<(bool, UntrackedSymbol<TypeId>)> {
203	match &reg.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
214/// Parse a value generated from a string into JSON.
215fn 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}
249/// Encode a value [`val`] according to the type [`typ`] registered in the [`reg`], adding it to [`out`].
250fn 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 &reg.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
432/// Decode some value [`dec`] into the type [`typ`] in the registry [`reg`].
433fn 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 &reg.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
581/// Fetch some value under a key in the storage and decode it according to the type [`typ`], or optionally use a default if the decoding fails.
582fn 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[..], &registry, typ, false)?
592	} else if let Some(default) = default {
593		decode_value(&mut &default[..], &registry, typ, false)?
594	} else {
595		unreachable!("unknown keys should not be present")
596	})
597}
598
599/// Contains all the necessary data for correct loading of and decoding keys, uniformly accessed by entries' thunks.
600struct 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/// Contains smart pointers to shared data to be accessed by entries' thunks, together with the pointer to own latest key depth.
611#[derive(Clone)]
612struct MapFetcherContext {
613	shared: Rc<SharedMapFetcherContext>,
614	prefix: Rc<Vec<u8>>,
615	current_key_depth: usize,
616}
617
618impl MapFetcherContext {
619	/// Get the latest key.
620	fn key(&self) -> Option<&(StorageHasher, UntrackedSymbol<TypeId>)> {
621		self.shared.keys.get(self.current_key_depth)
622	}
623}
624
625/// Cache and objectify all keys from the fetched and return the resulting cache.
626fn make_fetched_keys_storage(c: MapFetcherContext) -> Result<Val> {
627	let key = if let Some(k) = c.key() {
628		k
629	} else {
630		// TODO: bulk fetching for last key and assert!(!keys.is_empty())
631		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		// dbg!(&value);
672		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			// Next value is not submap
691			// Optional values have no map entry by convention, so we skip this key even when !include_defaults
692			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			// Submap
700			// Optional values have no map entry by convention, so we skip this key even when !include_defaults
701			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
738/// Fetch keys of some storage and cache them, returning the resulting cache value.
739fn 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
764/// Create a Jsonnet object out of given pallets' storage and assign appropriate methods.
765fn 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				// Optional values have no map entry by convention, so we skip this key even when !include_defaults
824				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(&registry, 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		// #[trace(skip)]
900		// let meta: RuntimeMetadataV14 = meta;
901		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
926/// Get some value under a key in client's storage as a byte array value.
927fn 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		// Should never occur?
933		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	// TODO: key filter?
950	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/// Possibly multi-type key, pointing to a single storage entry.
967#[derive(Trace, Clone)]
968struct Key(#[trace(skip)] Vec<(StorageHasher, UntrackedSymbol<TypeId>)>);
969
970/// Encode the value [`v`] into some type, denoted in the calling object's inner registry by the number [`typ`].
971///
972/// This function is passed to Jsonnet and is callable from the code on certain objects.
973#[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(&reg, 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/// Traceable wrapper of an [`UntrackedSymbol`].
1054#[derive(Trace, Clone)]
1055struct ValueId(#[trace(skip)] UntrackedSymbol<TypeId>);
1056
1057/// Encode the value [`v`] into some type according to the object's supplied type [`ty`].
1058///
1059/// This function is passed to Jsonnet and is callable from the code on certain objects.
1060#[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(&reg, this.ty.0, false, value, &mut out, false)?;
1069	Ok(Hex(out))
1070}
1071
1072/// Decode a [`value`] according to [`ty`], the type number of the calling object's inner registry.
1073///
1074/// This function is passed to Jsonnet and is callable from the code on certain objects.
1075#[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/// Encode the value [`v`] into some type, denoted in the calling object's inner registry by the number [`typ`].
1084///
1085/// This function is passed to Jsonnet and is callable from the code on certain objects.
1086#[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/// Decode the value [`v`] according to [`typ`], the type number of the calling object's inner registry.
1099///
1100/// This function is passed to Jsonnet and is callable from the code on certain objects.
1101#[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: UntrackedSymbol<TypeId>,
1131	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	// decode_value(&mut value.0.as_slice(), &this.reg, this.ty.0, false).map(Val::from)
1241	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		// dbg!(&address);
1268		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/// Convert an address from SS58 to a hex string.
1338///
1339/// This function is passed to Jsonnet and is callable from the code.
1340///
1341/// # Example
1342///
1343/// ```text
1344/// cql.ss58("5F6kd9bskZE53HP4JZqadDvEzvrCi4179F6ma3ZV4G3U3x7Y") ==
1345///     "0x864481616c4bd8689a578cb28e1da470f7b819d6b6df8f4d65b50aba8f996508"
1346/// ```
1347#[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
1367/// Create a Jsonnet object of a blockchain block.
1368fn 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/// Create a Jsonnet object of a blockchain block.
1440///
1441/// This function is passed to Jsonnet and is callable from the code on certain objects.
1442#[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/// Selection of optional flags for chain data processing.
1458#[derive(Typed, Trace, Default, Clone, Copy)]
1459struct ChainOpts {
1460	/// Whether or not to ignore trie prefixes with no keys
1461	omit_empty: bool,
1462	/// Should default values be included in output
1463	include_defaults: bool,
1464}
1465
1466/// Get chain data from a URL, including queryable storage, metadata, and blocks.
1467///
1468/// This function is passed to Jsonnet and is callable from the code.
1469///
1470/// # Example
1471///
1472/// ```text
1473/// cql.chain("ws://localhost:9944")
1474/// ```
1475#[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/// Create a mock block Jsonnet object from some parsed data dump.
1509///
1510/// This function is passed to Jsonnet and is callable from the code.
1511///
1512/// # Example
1513///
1514/// ```text
1515/// cql.dump(cql.chain("ws://localhost:9944").latest._meta, {
1516///     "a": 1,
1517///     "b": 2,
1518///     "c": 3,
1519/// }, {omit_empty:true})
1520/// ```
1521#[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	// Pass the built-in functions as macro-generated structs into the cql object available from Jsonnet code.
1603	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}