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