1#![warn(missing_docs)]
77#![cfg_attr(not(feature = "std"), no_std)]
78#![cfg_attr(enable_alloc_error_handler, feature(alloc_error_handler))]
79
80extern crate alloc;
81
82use alloc::vec::Vec;
83
84#[cfg(not(bizinikiwi_runtime))]
85use tracing;
86
87#[cfg(not(bizinikiwi_runtime))]
88use pezsp_core::{
89 crypto::Pair,
90 hexdisplay::HexDisplay,
91 offchain::{OffchainDbExt, OffchainWorkerExt, TransactionPoolExt},
92 storage::ChildInfo,
93};
94#[cfg(not(bizinikiwi_runtime))]
95use pezsp_keystore::KeystoreExt;
96
97#[cfg(feature = "bandersnatch-experimental")]
98use pezsp_core::bandersnatch;
99use pezsp_core::{
100 crypto::KeyTypeId,
101 ecdsa, ed25519,
102 offchain::{
103 HttpError, HttpRequestId, HttpRequestStatus, OpaqueNetworkState, StorageKind, Timestamp,
104 },
105 sr25519,
106 storage::StateVersion,
107 LogLevelFilter, OpaquePeerId, RuntimeInterfaceLogLevel, H256,
108};
109
110#[cfg(feature = "bls-experimental")]
111use pezsp_core::{bls381, ecdsa_bls381};
112
113#[cfg(not(bizinikiwi_runtime))]
114use pezsp_trie::{LayoutV0, LayoutV1, TrieConfiguration};
115
116use pezsp_runtime_interface::{
117 pass_by::{
118 AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs,
119 PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, PassFatPointerAndRead,
120 PassFatPointerAndReadWrite, PassPointerAndRead, PassPointerAndReadCopy, ReturnAs,
121 },
122 runtime_interface, Pointer,
123};
124
125use codec::{Decode, Encode};
126
127#[cfg(not(bizinikiwi_runtime))]
128use secp256k1::{
129 ecdsa::{RecoverableSignature, RecoveryId},
130 Message,
131};
132
133#[cfg(not(bizinikiwi_runtime))]
134use pezsp_externalities::{Externalities, ExternalitiesExt};
135
136pub use pezsp_externalities::MultiRemovalResults;
137
138#[cfg(all(not(feature = "disable_allocator"), bizinikiwi_runtime, target_family = "wasm"))]
139mod global_alloc_wasm;
140
141#[cfg(all(
142 not(feature = "disable_allocator"),
143 bizinikiwi_runtime,
144 any(target_arch = "riscv32", target_arch = "riscv64")
145))]
146mod global_alloc_riscv;
147
148#[cfg(not(bizinikiwi_runtime))]
149const LOG_TARGET: &str = "runtime::io";
150
151#[derive(Encode, Decode)]
153pub enum EcdsaVerifyError {
154 BadRS,
156 BadV,
158 BadSignature,
160}
161
162#[derive(Encode, Decode)]
165pub enum KillStorageResult {
166 AllRemoved(u32),
169 SomeRemaining(u32),
172}
173
174impl From<MultiRemovalResults> for KillStorageResult {
175 fn from(r: MultiRemovalResults) -> Self {
176 match r.maybe_cursor {
180 None => Self::AllRemoved(r.loops),
181 Some(..) => Self::SomeRemaining(r.loops),
182 }
183 }
184}
185
186#[runtime_interface]
188pub trait Storage {
189 fn get(
191 &mut self,
192 key: PassFatPointerAndRead<&[u8]>,
193 ) -> AllocateAndReturnByCodec<Option<bytes::Bytes>> {
194 self.storage(key).map(|s| bytes::Bytes::from(s.to_vec()))
195 }
196
197 fn read(
203 &mut self,
204 key: PassFatPointerAndRead<&[u8]>,
205 value_out: PassFatPointerAndReadWrite<&mut [u8]>,
206 value_offset: u32,
207 ) -> AllocateAndReturnByCodec<Option<u32>> {
208 self.storage(key).map(|value| {
209 let value_offset = value_offset as usize;
210 let data = &value[value_offset.min(value.len())..];
211 let written = core::cmp::min(data.len(), value_out.len());
212 value_out[..written].copy_from_slice(&data[..written]);
213 data.len() as u32
214 })
215 }
216
217 fn set(&mut self, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>) {
219 self.set_storage(key.to_vec(), value.to_vec());
220 }
221
222 fn clear(&mut self, key: PassFatPointerAndRead<&[u8]>) {
224 self.clear_storage(key)
225 }
226
227 fn exists(&mut self, key: PassFatPointerAndRead<&[u8]>) -> bool {
229 self.exists_storage(key)
230 }
231
232 fn clear_prefix(&mut self, prefix: PassFatPointerAndRead<&[u8]>) {
234 let _ = Externalities::clear_prefix(*self, prefix, None, None);
235 }
236
237 #[version(2)]
263 fn clear_prefix(
264 &mut self,
265 prefix: PassFatPointerAndRead<&[u8]>,
266 limit: PassFatPointerAndDecode<Option<u32>>,
267 ) -> AllocateAndReturnByCodec<KillStorageResult> {
268 Externalities::clear_prefix(*self, prefix, limit, None).into()
269 }
270
271 #[version(3, register_only)]
304 fn clear_prefix(
305 &mut self,
306 maybe_prefix: PassFatPointerAndRead<&[u8]>,
307 maybe_limit: PassFatPointerAndDecode<Option<u32>>,
308 maybe_cursor: PassFatPointerAndDecode<Option<Vec<u8>>>, ) -> AllocateAndReturnByCodec<MultiRemovalResults> {
311 Externalities::clear_prefix(
312 *self,
313 maybe_prefix,
314 maybe_limit,
315 maybe_cursor.as_ref().map(|x| &x[..]),
316 )
317 .into()
318 }
319
320 fn append(&mut self, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<Vec<u8>>) {
329 self.storage_append(key.to_vec(), value);
330 }
331
332 fn root(&mut self) -> AllocateAndReturnFatPointer<Vec<u8>> {
338 self.storage_root(StateVersion::V0)
339 }
340
341 #[version(2)]
347 fn root(&mut self, version: PassAs<StateVersion, u8>) -> AllocateAndReturnFatPointer<Vec<u8>> {
348 self.storage_root(version)
349 }
350
351 fn changes_root(
353 &mut self,
354 _parent_hash: PassFatPointerAndRead<&[u8]>,
355 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
356 None
357 }
358
359 fn next_key(
361 &mut self,
362 key: PassFatPointerAndRead<&[u8]>,
363 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
364 self.next_storage_key(key)
365 }
366
367 fn start_transaction(&mut self) {
380 self.storage_start_transaction();
381 }
382
383 fn rollback_transaction(&mut self) {
391 self.storage_rollback_transaction()
392 .expect("No open transaction that can be rolled back.");
393 }
394
395 fn commit_transaction(&mut self) {
403 self.storage_commit_transaction()
404 .expect("No open transaction that can be committed.");
405 }
406}
407
408#[runtime_interface]
411pub trait DefaultChildStorage {
412 fn get(
417 &mut self,
418 storage_key: PassFatPointerAndRead<&[u8]>,
419 key: PassFatPointerAndRead<&[u8]>,
420 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
421 let child_info = ChildInfo::new_default(storage_key);
422 self.child_storage(&child_info, key).map(|s| s.to_vec())
423 }
424
425 fn read(
433 &mut self,
434 storage_key: PassFatPointerAndRead<&[u8]>,
435 key: PassFatPointerAndRead<&[u8]>,
436 value_out: PassFatPointerAndReadWrite<&mut [u8]>,
437 value_offset: u32,
438 ) -> AllocateAndReturnByCodec<Option<u32>> {
439 let child_info = ChildInfo::new_default(storage_key);
440 self.child_storage(&child_info, key).map(|value| {
441 let value_offset = value_offset as usize;
442 let data = &value[value_offset.min(value.len())..];
443 let written = core::cmp::min(data.len(), value_out.len());
444 value_out[..written].copy_from_slice(&data[..written]);
445 data.len() as u32
446 })
447 }
448
449 fn set(
453 &mut self,
454 storage_key: PassFatPointerAndRead<&[u8]>,
455 key: PassFatPointerAndRead<&[u8]>,
456 value: PassFatPointerAndRead<&[u8]>,
457 ) {
458 let child_info = ChildInfo::new_default(storage_key);
459 self.set_child_storage(&child_info, key.to_vec(), value.to_vec());
460 }
461
462 fn clear(
466 &mut self,
467 storage_key: PassFatPointerAndRead<&[u8]>,
468 key: PassFatPointerAndRead<&[u8]>,
469 ) {
470 let child_info = ChildInfo::new_default(storage_key);
471 self.clear_child_storage(&child_info, key);
472 }
473
474 fn storage_kill(&mut self, storage_key: PassFatPointerAndRead<&[u8]>) {
479 let child_info = ChildInfo::new_default(storage_key);
480 let _ = self.kill_child_storage(&child_info, None, None);
481 }
482
483 #[version(2)]
487 fn storage_kill(
488 &mut self,
489 storage_key: PassFatPointerAndRead<&[u8]>,
490 limit: PassFatPointerAndDecode<Option<u32>>,
491 ) -> bool {
492 let child_info = ChildInfo::new_default(storage_key);
493 let r = self.kill_child_storage(&child_info, limit, None);
494 r.maybe_cursor.is_none()
495 }
496
497 #[version(3)]
501 fn storage_kill(
502 &mut self,
503 storage_key: PassFatPointerAndRead<&[u8]>,
504 limit: PassFatPointerAndDecode<Option<u32>>,
505 ) -> AllocateAndReturnByCodec<KillStorageResult> {
506 let child_info = ChildInfo::new_default(storage_key);
507 self.kill_child_storage(&child_info, limit, None).into()
508 }
509
510 #[version(4, register_only)]
514 fn storage_kill(
515 &mut self,
516 storage_key: PassFatPointerAndRead<&[u8]>,
517 maybe_limit: PassFatPointerAndDecode<Option<u32>>,
518 maybe_cursor: PassFatPointerAndDecode<Option<Vec<u8>>>,
519 ) -> AllocateAndReturnByCodec<MultiRemovalResults> {
520 let child_info = ChildInfo::new_default(storage_key);
521 self.kill_child_storage(&child_info, maybe_limit, maybe_cursor.as_ref().map(|x| &x[..]))
522 .into()
523 }
524
525 fn exists(
529 &mut self,
530 storage_key: PassFatPointerAndRead<&[u8]>,
531 key: PassFatPointerAndRead<&[u8]>,
532 ) -> bool {
533 let child_info = ChildInfo::new_default(storage_key);
534 self.exists_child_storage(&child_info, key)
535 }
536
537 fn clear_prefix(
541 &mut self,
542 storage_key: PassFatPointerAndRead<&[u8]>,
543 prefix: PassFatPointerAndRead<&[u8]>,
544 ) {
545 let child_info = ChildInfo::new_default(storage_key);
546 let _ = self.clear_child_prefix(&child_info, prefix, None, None);
547 }
548
549 #[version(2)]
553 fn clear_prefix(
554 &mut self,
555 storage_key: PassFatPointerAndRead<&[u8]>,
556 prefix: PassFatPointerAndRead<&[u8]>,
557 limit: PassFatPointerAndDecode<Option<u32>>,
558 ) -> AllocateAndReturnByCodec<KillStorageResult> {
559 let child_info = ChildInfo::new_default(storage_key);
560 self.clear_child_prefix(&child_info, prefix, limit, None).into()
561 }
562
563 #[version(3, register_only)]
567 fn clear_prefix(
568 &mut self,
569 storage_key: PassFatPointerAndRead<&[u8]>,
570 prefix: PassFatPointerAndRead<&[u8]>,
571 maybe_limit: PassFatPointerAndDecode<Option<u32>>,
572 maybe_cursor: PassFatPointerAndDecode<Option<Vec<u8>>>,
573 ) -> AllocateAndReturnByCodec<MultiRemovalResults> {
574 let child_info = ChildInfo::new_default(storage_key);
575 self.clear_child_prefix(
576 &child_info,
577 prefix,
578 maybe_limit,
579 maybe_cursor.as_ref().map(|x| &x[..]),
580 )
581 .into()
582 }
583
584 fn root(
591 &mut self,
592 storage_key: PassFatPointerAndRead<&[u8]>,
593 ) -> AllocateAndReturnFatPointer<Vec<u8>> {
594 let child_info = ChildInfo::new_default(storage_key);
595 self.child_storage_root(&child_info, StateVersion::V0)
596 }
597
598 #[version(2)]
605 fn root(
606 &mut self,
607 storage_key: PassFatPointerAndRead<&[u8]>,
608 version: PassAs<StateVersion, u8>,
609 ) -> AllocateAndReturnFatPointer<Vec<u8>> {
610 let child_info = ChildInfo::new_default(storage_key);
611 self.child_storage_root(&child_info, version)
612 }
613
614 fn next_key(
618 &mut self,
619 storage_key: PassFatPointerAndRead<&[u8]>,
620 key: PassFatPointerAndRead<&[u8]>,
621 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
622 let child_info = ChildInfo::new_default(storage_key);
623 self.next_child_storage_key(&child_info, key)
624 }
625}
626
627#[runtime_interface]
629pub trait Trie {
630 fn blake2_256_root(
632 input: PassFatPointerAndDecode<Vec<(Vec<u8>, Vec<u8>)>>,
633 ) -> AllocateAndReturnPointer<H256, 32> {
634 LayoutV0::<pezsp_core::Blake2Hasher>::trie_root(input)
635 }
636
637 #[version(2)]
639 fn blake2_256_root(
640 input: PassFatPointerAndDecode<Vec<(Vec<u8>, Vec<u8>)>>,
641 version: PassAs<StateVersion, u8>,
642 ) -> AllocateAndReturnPointer<H256, 32> {
643 match version {
644 StateVersion::V0 => LayoutV0::<pezsp_core::Blake2Hasher>::trie_root(input),
645 StateVersion::V1 => LayoutV1::<pezsp_core::Blake2Hasher>::trie_root(input),
646 }
647 }
648
649 fn blake2_256_ordered_root(
651 input: PassFatPointerAndDecode<Vec<Vec<u8>>>,
652 ) -> AllocateAndReturnPointer<H256, 32> {
653 LayoutV0::<pezsp_core::Blake2Hasher>::ordered_trie_root(input)
654 }
655
656 #[version(2)]
658 fn blake2_256_ordered_root(
659 input: PassFatPointerAndDecode<Vec<Vec<u8>>>,
660 version: PassAs<StateVersion, u8>,
661 ) -> AllocateAndReturnPointer<H256, 32> {
662 match version {
663 StateVersion::V0 => LayoutV0::<pezsp_core::Blake2Hasher>::ordered_trie_root(input),
664 StateVersion::V1 => LayoutV1::<pezsp_core::Blake2Hasher>::ordered_trie_root(input),
665 }
666 }
667
668 fn keccak_256_root(
670 input: PassFatPointerAndDecode<Vec<(Vec<u8>, Vec<u8>)>>,
671 ) -> AllocateAndReturnPointer<H256, 32> {
672 LayoutV0::<pezsp_core::KeccakHasher>::trie_root(input)
673 }
674
675 #[version(2)]
677 fn keccak_256_root(
678 input: PassFatPointerAndDecode<Vec<(Vec<u8>, Vec<u8>)>>,
679 version: PassAs<StateVersion, u8>,
680 ) -> AllocateAndReturnPointer<H256, 32> {
681 match version {
682 StateVersion::V0 => LayoutV0::<pezsp_core::KeccakHasher>::trie_root(input),
683 StateVersion::V1 => LayoutV1::<pezsp_core::KeccakHasher>::trie_root(input),
684 }
685 }
686
687 fn keccak_256_ordered_root(
689 input: PassFatPointerAndDecode<Vec<Vec<u8>>>,
690 ) -> AllocateAndReturnPointer<H256, 32> {
691 LayoutV0::<pezsp_core::KeccakHasher>::ordered_trie_root(input)
692 }
693
694 #[version(2)]
696 fn keccak_256_ordered_root(
697 input: PassFatPointerAndDecode<Vec<Vec<u8>>>,
698 version: PassAs<StateVersion, u8>,
699 ) -> AllocateAndReturnPointer<H256, 32> {
700 match version {
701 StateVersion::V0 => LayoutV0::<pezsp_core::KeccakHasher>::ordered_trie_root(input),
702 StateVersion::V1 => LayoutV1::<pezsp_core::KeccakHasher>::ordered_trie_root(input),
703 }
704 }
705
706 fn blake2_256_verify_proof(
708 root: PassPointerAndReadCopy<H256, 32>,
709 proof: PassFatPointerAndDecodeSlice<&[Vec<u8>]>,
710 key: PassFatPointerAndRead<&[u8]>,
711 value: PassFatPointerAndRead<&[u8]>,
712 ) -> bool {
713 pezsp_trie::verify_trie_proof::<LayoutV0<pezsp_core::Blake2Hasher>, _, _, _>(
714 &root,
715 proof,
716 &[(key, Some(value))],
717 )
718 .is_ok()
719 }
720
721 #[version(2)]
723 fn blake2_256_verify_proof(
724 root: PassPointerAndReadCopy<H256, 32>,
725 proof: PassFatPointerAndDecodeSlice<&[Vec<u8>]>,
726 key: PassFatPointerAndRead<&[u8]>,
727 value: PassFatPointerAndRead<&[u8]>,
728 version: PassAs<StateVersion, u8>,
729 ) -> bool {
730 match version {
731 StateVersion::V0 => pezsp_trie::verify_trie_proof::<
732 LayoutV0<pezsp_core::Blake2Hasher>,
733 _,
734 _,
735 _,
736 >(&root, proof, &[(key, Some(value))])
737 .is_ok(),
738 StateVersion::V1 => pezsp_trie::verify_trie_proof::<
739 LayoutV1<pezsp_core::Blake2Hasher>,
740 _,
741 _,
742 _,
743 >(&root, proof, &[(key, Some(value))])
744 .is_ok(),
745 }
746 }
747
748 fn keccak_256_verify_proof(
750 root: PassPointerAndReadCopy<H256, 32>,
751 proof: PassFatPointerAndDecodeSlice<&[Vec<u8>]>,
752 key: PassFatPointerAndRead<&[u8]>,
753 value: PassFatPointerAndRead<&[u8]>,
754 ) -> bool {
755 pezsp_trie::verify_trie_proof::<LayoutV0<pezsp_core::KeccakHasher>, _, _, _>(
756 &root,
757 proof,
758 &[(key, Some(value))],
759 )
760 .is_ok()
761 }
762
763 #[version(2)]
765 fn keccak_256_verify_proof(
766 root: PassPointerAndReadCopy<H256, 32>,
767 proof: PassFatPointerAndDecodeSlice<&[Vec<u8>]>,
768 key: PassFatPointerAndRead<&[u8]>,
769 value: PassFatPointerAndRead<&[u8]>,
770 version: PassAs<StateVersion, u8>,
771 ) -> bool {
772 match version {
773 StateVersion::V0 => pezsp_trie::verify_trie_proof::<
774 LayoutV0<pezsp_core::KeccakHasher>,
775 _,
776 _,
777 _,
778 >(&root, proof, &[(key, Some(value))])
779 .is_ok(),
780 StateVersion::V1 => pezsp_trie::verify_trie_proof::<
781 LayoutV1<pezsp_core::KeccakHasher>,
782 _,
783 _,
784 _,
785 >(&root, proof, &[(key, Some(value))])
786 .is_ok(),
787 }
788 }
789}
790
791#[runtime_interface]
794pub trait Misc {
795 fn print_num(val: u64) {
800 log::debug!(target: "runtime", "{}", val);
801 }
802
803 fn print_utf8(utf8: PassFatPointerAndRead<&[u8]>) {
805 if let Ok(data) = core::str::from_utf8(utf8) {
806 log::debug!(target: "runtime", "{}", data)
807 }
808 }
809
810 fn print_hex(data: PassFatPointerAndRead<&[u8]>) {
812 log::debug!(target: "runtime", "{}", HexDisplay::from(&data));
813 }
814
815 fn runtime_version(
831 &mut self,
832 wasm: PassFatPointerAndRead<&[u8]>,
833 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
834 use pezsp_core::traits::ReadRuntimeVersionExt;
835
836 let mut ext = pezsp_state_machine::BasicExternalities::default();
837
838 match self
839 .extension::<ReadRuntimeVersionExt>()
840 .expect("No `ReadRuntimeVersionExt` associated for the current context!")
841 .read_runtime_version(wasm, &mut ext)
842 {
843 Ok(v) => Some(v),
844 Err(err) => {
845 log::debug!(
846 target: LOG_TARGET,
847 "cannot read version from the given runtime: {}",
848 err,
849 );
850 None
851 },
852 }
853 }
854}
855
856#[cfg(not(bizinikiwi_runtime))]
857pezsp_externalities::decl_extension! {
858 pub struct UseDalekExt;
875}
876
877#[cfg(not(bizinikiwi_runtime))]
878impl Default for UseDalekExt {
879 fn default() -> Self {
880 Self
881 }
882}
883
884#[runtime_interface]
886pub trait Crypto {
887 fn ed25519_public_keys(
889 &mut self,
890 id: PassPointerAndReadCopy<KeyTypeId, 4>,
891 ) -> AllocateAndReturnByCodec<Vec<ed25519::Public>> {
892 self.extension::<KeystoreExt>()
893 .expect("No `keystore` associated for the current context!")
894 .ed25519_public_keys(id)
895 }
896
897 fn ed25519_generate(
904 &mut self,
905 id: PassPointerAndReadCopy<KeyTypeId, 4>,
906 seed: PassFatPointerAndDecode<Option<Vec<u8>>>,
907 ) -> AllocateAndReturnPointer<ed25519::Public, 32> {
908 let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!"));
909 self.extension::<KeystoreExt>()
910 .expect("No `keystore` associated for the current context!")
911 .ed25519_generate_new(id, seed)
912 .expect("`ed25519_generate` failed")
913 }
914
915 fn ed25519_sign(
920 &mut self,
921 id: PassPointerAndReadCopy<KeyTypeId, 4>,
922 pub_key: PassPointerAndRead<&ed25519::Public, 32>,
923 msg: PassFatPointerAndRead<&[u8]>,
924 ) -> AllocateAndReturnByCodec<Option<ed25519::Signature>> {
925 self.extension::<KeystoreExt>()
926 .expect("No `keystore` associated for the current context!")
927 .ed25519_sign(id, pub_key, msg)
928 .ok()
929 .flatten()
930 }
931
932 fn ed25519_verify(
936 sig: PassPointerAndRead<&ed25519::Signature, 64>,
937 msg: PassFatPointerAndRead<&[u8]>,
938 pub_key: PassPointerAndRead<&ed25519::Public, 32>,
939 ) -> bool {
940 if pezsp_externalities::with_externalities(|mut e| e.extension::<UseDalekExt>().is_some())
944 .unwrap_or_default()
945 {
946 use ed25519_dalek::Verifier;
947
948 let Ok(public_key) = ed25519_dalek::VerifyingKey::from_bytes(&pub_key.0) else {
949 return false;
950 };
951
952 let sig = ed25519_dalek::Signature::from_bytes(&sig.0);
953
954 public_key.verify(msg, &sig).is_ok()
955 } else {
956 ed25519::Pair::verify(sig, msg, pub_key)
957 }
958 }
959
960 #[version(1, register_only)]
974 fn ed25519_batch_verify(
975 &mut self,
976 sig: PassPointerAndRead<&ed25519::Signature, 64>,
977 msg: PassFatPointerAndRead<&[u8]>,
978 pub_key: PassPointerAndRead<&ed25519::Public, 32>,
979 ) -> bool {
980 let res = ed25519_verify(sig, msg, pub_key);
981
982 if let Some(ext) = self.extension::<VerificationExtDeprecated>() {
983 ext.0 &= res;
984 }
985
986 res
987 }
988
989 #[version(2)]
993 fn sr25519_verify(
994 sig: PassPointerAndRead<&sr25519::Signature, 64>,
995 msg: PassFatPointerAndRead<&[u8]>,
996 pub_key: PassPointerAndRead<&sr25519::Public, 32>,
997 ) -> bool {
998 sr25519::Pair::verify(sig, msg, pub_key)
999 }
1000
1001 #[version(1, register_only)]
1015 fn sr25519_batch_verify(
1016 &mut self,
1017 sig: PassPointerAndRead<&sr25519::Signature, 64>,
1018 msg: PassFatPointerAndRead<&[u8]>,
1019 pub_key: PassPointerAndRead<&sr25519::Public, 32>,
1020 ) -> bool {
1021 let res = sr25519_verify(sig, msg, pub_key);
1022
1023 if let Some(ext) = self.extension::<VerificationExtDeprecated>() {
1024 ext.0 &= res;
1025 }
1026
1027 res
1028 }
1029
1030 #[version(1, register_only)]
1037 fn start_batch_verify(&mut self) {
1038 self.register_extension(VerificationExtDeprecated(true))
1039 .expect("Failed to register required extension: `VerificationExt`");
1040 }
1041
1042 #[version(1, register_only)]
1054 fn finish_batch_verify(&mut self) -> bool {
1055 let result = self
1056 .extension::<VerificationExtDeprecated>()
1057 .expect("`finish_batch_verify` should only be called after `start_batch_verify`")
1058 .0;
1059
1060 self.deregister_extension::<VerificationExtDeprecated>()
1061 .expect("No verification extension in current context!");
1062
1063 result
1064 }
1065
1066 fn sr25519_public_keys(
1068 &mut self,
1069 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1070 ) -> AllocateAndReturnByCodec<Vec<sr25519::Public>> {
1071 self.extension::<KeystoreExt>()
1072 .expect("No `keystore` associated for the current context!")
1073 .sr25519_public_keys(id)
1074 }
1075
1076 fn sr25519_generate(
1083 &mut self,
1084 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1085 seed: PassFatPointerAndDecode<Option<Vec<u8>>>,
1086 ) -> AllocateAndReturnPointer<sr25519::Public, 32> {
1087 let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!"));
1088 self.extension::<KeystoreExt>()
1089 .expect("No `keystore` associated for the current context!")
1090 .sr25519_generate_new(id, seed)
1091 .expect("`sr25519_generate` failed")
1092 }
1093
1094 fn sr25519_sign(
1099 &mut self,
1100 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1101 pub_key: PassPointerAndRead<&sr25519::Public, 32>,
1102 msg: PassFatPointerAndRead<&[u8]>,
1103 ) -> AllocateAndReturnByCodec<Option<sr25519::Signature>> {
1104 self.extension::<KeystoreExt>()
1105 .expect("No `keystore` associated for the current context!")
1106 .sr25519_sign(id, pub_key, msg)
1107 .ok()
1108 .flatten()
1109 }
1110
1111 fn sr25519_verify(
1116 sig: PassPointerAndRead<&sr25519::Signature, 64>,
1117 msg: PassFatPointerAndRead<&[u8]>,
1118 pubkey: PassPointerAndRead<&sr25519::Public, 32>,
1119 ) -> bool {
1120 sr25519::Pair::verify_deprecated(sig, msg, pubkey)
1121 }
1122
1123 fn ecdsa_public_keys(
1125 &mut self,
1126 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1127 ) -> AllocateAndReturnByCodec<Vec<ecdsa::Public>> {
1128 self.extension::<KeystoreExt>()
1129 .expect("No `keystore` associated for the current context!")
1130 .ecdsa_public_keys(id)
1131 }
1132
1133 fn ecdsa_generate(
1140 &mut self,
1141 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1142 seed: PassFatPointerAndDecode<Option<Vec<u8>>>,
1143 ) -> AllocateAndReturnPointer<ecdsa::Public, 33> {
1144 let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!"));
1145 self.extension::<KeystoreExt>()
1146 .expect("No `keystore` associated for the current context!")
1147 .ecdsa_generate_new(id, seed)
1148 .expect("`ecdsa_generate` failed")
1149 }
1150
1151 fn ecdsa_sign(
1156 &mut self,
1157 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1158 pub_key: PassPointerAndRead<&ecdsa::Public, 33>,
1159 msg: PassFatPointerAndRead<&[u8]>,
1160 ) -> AllocateAndReturnByCodec<Option<ecdsa::Signature>> {
1161 self.extension::<KeystoreExt>()
1162 .expect("No `keystore` associated for the current context!")
1163 .ecdsa_sign(id, pub_key, msg)
1164 .ok()
1165 .flatten()
1166 }
1167
1168 fn ecdsa_sign_prehashed(
1173 &mut self,
1174 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1175 pub_key: PassPointerAndRead<&ecdsa::Public, 33>,
1176 msg: PassPointerAndRead<&[u8; 32], 32>,
1177 ) -> AllocateAndReturnByCodec<Option<ecdsa::Signature>> {
1178 self.extension::<KeystoreExt>()
1179 .expect("No `keystore` associated for the current context!")
1180 .ecdsa_sign_prehashed(id, pub_key, msg)
1181 .ok()
1182 .flatten()
1183 }
1184
1185 fn ecdsa_verify(
1190 sig: PassPointerAndRead<&ecdsa::Signature, 65>,
1191 msg: PassFatPointerAndRead<&[u8]>,
1192 pub_key: PassPointerAndRead<&ecdsa::Public, 33>,
1193 ) -> bool {
1194 #[allow(deprecated)]
1195 ecdsa::Pair::verify_deprecated(sig, msg, pub_key)
1196 }
1197
1198 #[version(2)]
1202 fn ecdsa_verify(
1203 sig: PassPointerAndRead<&ecdsa::Signature, 65>,
1204 msg: PassFatPointerAndRead<&[u8]>,
1205 pub_key: PassPointerAndRead<&ecdsa::Public, 33>,
1206 ) -> bool {
1207 ecdsa::Pair::verify(sig, msg, pub_key)
1208 }
1209
1210 fn ecdsa_verify_prehashed(
1214 sig: PassPointerAndRead<&ecdsa::Signature, 65>,
1215 msg: PassPointerAndRead<&[u8; 32], 32>,
1216 pub_key: PassPointerAndRead<&ecdsa::Public, 33>,
1217 ) -> bool {
1218 ecdsa::Pair::verify_prehashed(sig, msg, pub_key)
1219 }
1220
1221 #[version(1, register_only)]
1235 fn ecdsa_batch_verify(
1236 &mut self,
1237 sig: PassPointerAndRead<&ecdsa::Signature, 65>,
1238 msg: PassFatPointerAndRead<&[u8]>,
1239 pub_key: PassPointerAndRead<&ecdsa::Public, 33>,
1240 ) -> bool {
1241 let res = ecdsa_verify(sig, msg, pub_key);
1242
1243 if let Some(ext) = self.extension::<VerificationExtDeprecated>() {
1244 ext.0 &= res;
1245 }
1246
1247 res
1248 }
1249
1250 fn secp256k1_ecdsa_recover(
1259 sig: PassPointerAndRead<&[u8; 65], 65>,
1260 msg: PassPointerAndRead<&[u8; 32], 32>,
1261 ) -> AllocateAndReturnByCodec<Result<[u8; 64], EcdsaVerifyError>> {
1262 let rid = libsecp256k1::RecoveryId::parse(
1263 if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8,
1264 )
1265 .map_err(|_| EcdsaVerifyError::BadV)?;
1266 let sig = libsecp256k1::Signature::parse_overflowing_slice(&sig[..64])
1267 .map_err(|_| EcdsaVerifyError::BadRS)?;
1268 let msg = libsecp256k1::Message::parse(msg);
1269 let pubkey =
1270 libsecp256k1::recover(&msg, &sig, &rid).map_err(|_| EcdsaVerifyError::BadSignature)?;
1271 let mut res = [0u8; 64];
1272 res.copy_from_slice(&pubkey.serialize()[1..65]);
1273 Ok(res)
1274 }
1275
1276 #[version(2)]
1284 fn secp256k1_ecdsa_recover(
1285 sig: PassPointerAndRead<&[u8; 65], 65>,
1286 msg: PassPointerAndRead<&[u8; 32], 32>,
1287 ) -> AllocateAndReturnByCodec<Result<[u8; 64], EcdsaVerifyError>> {
1288 let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32)
1289 .map_err(|_| EcdsaVerifyError::BadV)?;
1290 let sig = RecoverableSignature::from_compact(&sig[..64], rid)
1291 .map_err(|_| EcdsaVerifyError::BadRS)?;
1292 let msg = Message::from_digest_slice(msg).expect("Message is 32 bytes; qed");
1293 #[cfg(feature = "std")]
1294 let ctx = secp256k1::SECP256K1;
1295 #[cfg(not(feature = "std"))]
1296 let ctx = secp256k1::Secp256k1::<secp256k1::VerifyOnly>::gen_new();
1297 let pubkey = ctx.recover_ecdsa(&msg, &sig).map_err(|_| EcdsaVerifyError::BadSignature)?;
1298 let mut res = [0u8; 64];
1299 res.copy_from_slice(&pubkey.serialize_uncompressed()[1..]);
1300 Ok(res)
1301 }
1302
1303 fn secp256k1_ecdsa_recover_compressed(
1310 sig: PassPointerAndRead<&[u8; 65], 65>,
1311 msg: PassPointerAndRead<&[u8; 32], 32>,
1312 ) -> AllocateAndReturnByCodec<Result<[u8; 33], EcdsaVerifyError>> {
1313 let rid = libsecp256k1::RecoveryId::parse(
1314 if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8,
1315 )
1316 .map_err(|_| EcdsaVerifyError::BadV)?;
1317 let sig = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1318 .map_err(|_| EcdsaVerifyError::BadRS)?;
1319 let msg = libsecp256k1::Message::parse(msg);
1320 let pubkey =
1321 libsecp256k1::recover(&msg, &sig, &rid).map_err(|_| EcdsaVerifyError::BadSignature)?;
1322 Ok(pubkey.serialize_compressed())
1323 }
1324
1325 #[version(2)]
1332 fn secp256k1_ecdsa_recover_compressed(
1333 sig: PassPointerAndRead<&[u8; 65], 65>,
1334 msg: PassPointerAndRead<&[u8; 32], 32>,
1335 ) -> AllocateAndReturnByCodec<Result<[u8; 33], EcdsaVerifyError>> {
1336 let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32)
1337 .map_err(|_| EcdsaVerifyError::BadV)?;
1338 let sig = RecoverableSignature::from_compact(&sig[..64], rid)
1339 .map_err(|_| EcdsaVerifyError::BadRS)?;
1340 let msg = Message::from_digest_slice(msg).expect("Message is 32 bytes; qed");
1341 #[cfg(feature = "std")]
1342 let ctx = secp256k1::SECP256K1;
1343 #[cfg(not(feature = "std"))]
1344 let ctx = secp256k1::Secp256k1::<secp256k1::VerifyOnly>::gen_new();
1345 let pubkey = ctx.recover_ecdsa(&msg, &sig).map_err(|_| EcdsaVerifyError::BadSignature)?;
1346 Ok(pubkey.serialize())
1347 }
1348
1349 #[cfg(feature = "bls-experimental")]
1356 fn bls381_generate(
1357 &mut self,
1358 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1359 seed: PassFatPointerAndDecode<Option<Vec<u8>>>,
1360 ) -> AllocateAndReturnPointer<bls381::Public, 144> {
1361 let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!"));
1362 self.extension::<KeystoreExt>()
1363 .expect("No `keystore` associated for the current context!")
1364 .bls381_generate_new(id, seed)
1365 .expect("`bls381_generate` failed")
1366 }
1367
1368 #[cfg(feature = "bls-experimental")]
1373 fn bls381_generate_proof_of_possession(
1374 &mut self,
1375 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1376 pub_key: PassPointerAndRead<&bls381::Public, 144>,
1377 owner: PassFatPointerAndRead<&[u8]>,
1378 ) -> AllocateAndReturnByCodec<Option<bls381::ProofOfPossession>> {
1379 self.extension::<KeystoreExt>()
1380 .expect("No `keystore` associated for the current context!")
1381 .bls381_generate_proof_of_possession(id, pub_key, owner)
1382 .ok()
1383 .flatten()
1384 }
1385
1386 #[cfg(feature = "bls-experimental")]
1393 fn ecdsa_bls381_generate(
1394 &mut self,
1395 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1396 seed: PassFatPointerAndDecode<Option<Vec<u8>>>,
1397 ) -> AllocateAndReturnPointer<ecdsa_bls381::Public, { 144 + 33 }> {
1398 let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!"));
1399 self.extension::<KeystoreExt>()
1400 .expect("No `keystore` associated for the current context!")
1401 .ecdsa_bls381_generate_new(id, seed)
1402 .expect("`ecdsa_bls381_generate` failed")
1403 }
1404
1405 #[cfg(feature = "bandersnatch-experimental")]
1412 fn bandersnatch_generate(
1413 &mut self,
1414 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1415 seed: PassFatPointerAndDecode<Option<Vec<u8>>>,
1416 ) -> AllocateAndReturnPointer<bandersnatch::Public, 32> {
1417 let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!"));
1418 self.extension::<KeystoreExt>()
1419 .expect("No `keystore` associated for the current context!")
1420 .bandersnatch_generate_new(id, seed)
1421 .expect("`bandernatch_generate` failed")
1422 }
1423
1424 #[cfg(feature = "bandersnatch-experimental")]
1429 fn bandersnatch_sign(
1430 &mut self,
1431 id: PassPointerAndReadCopy<KeyTypeId, 4>,
1432 pub_key: PassPointerAndRead<&bandersnatch::Public, 32>,
1433 msg: PassFatPointerAndRead<&[u8]>,
1434 ) -> AllocateAndReturnByCodec<Option<bandersnatch::Signature>> {
1435 self.extension::<KeystoreExt>()
1436 .expect("No `keystore` associated for the current context!")
1437 .bandersnatch_sign(id, pub_key, msg)
1438 .ok()
1439 .flatten()
1440 }
1441}
1442
1443#[runtime_interface]
1445pub trait Hashing {
1446 fn keccak_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> {
1448 pezsp_crypto_hashing::keccak_256(data)
1449 }
1450
1451 fn keccak_512(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 64], 64> {
1453 pezsp_crypto_hashing::keccak_512(data)
1454 }
1455
1456 fn sha2_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> {
1458 pezsp_crypto_hashing::sha2_256(data)
1459 }
1460
1461 fn blake2_128(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 16], 16> {
1463 pezsp_crypto_hashing::blake2_128(data)
1464 }
1465
1466 fn blake2_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> {
1468 pezsp_crypto_hashing::blake2_256(data)
1469 }
1470
1471 fn twox_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> {
1473 pezsp_crypto_hashing::twox_256(data)
1474 }
1475
1476 fn twox_128(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 16], 16> {
1478 pezsp_crypto_hashing::twox_128(data)
1479 }
1480
1481 fn twox_64(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 8], 8> {
1483 pezsp_crypto_hashing::twox_64(data)
1484 }
1485}
1486
1487#[runtime_interface]
1489pub trait TransactionIndex {
1490 fn index(
1492 &mut self,
1493 extrinsic: u32,
1494 size: u32,
1495 context_hash: PassPointerAndReadCopy<[u8; 32], 32>,
1496 ) {
1497 self.storage_index_transaction(extrinsic, &context_hash, size);
1498 }
1499
1500 fn renew(&mut self, extrinsic: u32, context_hash: PassPointerAndReadCopy<[u8; 32], 32>) {
1503 self.storage_renew_transaction_index(extrinsic, &context_hash);
1504 }
1505}
1506
1507#[runtime_interface]
1509pub trait OffchainIndex {
1510 fn set(&mut self, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>) {
1512 self.set_offchain_storage(key, Some(value));
1513 }
1514
1515 fn clear(&mut self, key: PassFatPointerAndRead<&[u8]>) {
1517 self.set_offchain_storage(key, None);
1518 }
1519}
1520
1521#[cfg(not(bizinikiwi_runtime))]
1522pezsp_externalities::decl_extension! {
1523 struct VerificationExtDeprecated(bool);
1527}
1528
1529#[runtime_interface]
1533pub trait Offchain {
1534 fn is_validator(&mut self) -> bool {
1539 self.extension::<OffchainWorkerExt>()
1540 .expect("is_validator can be called only in the offchain worker context")
1541 .is_validator()
1542 }
1543
1544 fn submit_transaction(
1548 &mut self,
1549 data: PassFatPointerAndRead<Vec<u8>>,
1550 ) -> AllocateAndReturnByCodec<Result<(), ()>> {
1551 self.extension::<TransactionPoolExt>()
1552 .expect(
1553 "submit_transaction can be called only in the offchain call context with
1554 TransactionPool capabilities enabled",
1555 )
1556 .submit_transaction(data)
1557 }
1558
1559 fn network_state(&mut self) -> AllocateAndReturnByCodec<Result<OpaqueNetworkState, ()>> {
1561 self.extension::<OffchainWorkerExt>()
1562 .expect("network_state can be called only in the offchain worker context")
1563 .network_state()
1564 }
1565
1566 fn timestamp(&mut self) -> ReturnAs<Timestamp, u64> {
1568 self.extension::<OffchainWorkerExt>()
1569 .expect("timestamp can be called only in the offchain worker context")
1570 .timestamp()
1571 }
1572
1573 fn sleep_until(&mut self, deadline: PassAs<Timestamp, u64>) {
1575 self.extension::<OffchainWorkerExt>()
1576 .expect("sleep_until can be called only in the offchain worker context")
1577 .sleep_until(deadline)
1578 }
1579
1580 fn random_seed(&mut self) -> AllocateAndReturnPointer<[u8; 32], 32> {
1585 self.extension::<OffchainWorkerExt>()
1586 .expect("random_seed can be called only in the offchain worker context")
1587 .random_seed()
1588 }
1589
1590 fn local_storage_set(
1595 &mut self,
1596 kind: PassAs<StorageKind, u32>,
1597 key: PassFatPointerAndRead<&[u8]>,
1598 value: PassFatPointerAndRead<&[u8]>,
1599 ) {
1600 self.extension::<OffchainDbExt>()
1601 .expect(
1602 "local_storage_set can be called only in the offchain call context with
1603 OffchainDb extension",
1604 )
1605 .local_storage_set(kind, key, value)
1606 }
1607
1608 fn local_storage_clear(
1613 &mut self,
1614 kind: PassAs<StorageKind, u32>,
1615 key: PassFatPointerAndRead<&[u8]>,
1616 ) {
1617 self.extension::<OffchainDbExt>()
1618 .expect(
1619 "local_storage_clear can be called only in the offchain call context with
1620 OffchainDb extension",
1621 )
1622 .local_storage_clear(kind, key)
1623 }
1624
1625 fn local_storage_compare_and_set(
1635 &mut self,
1636 kind: PassAs<StorageKind, u32>,
1637 key: PassFatPointerAndRead<&[u8]>,
1638 old_value: PassFatPointerAndDecode<Option<Vec<u8>>>,
1639 new_value: PassFatPointerAndRead<&[u8]>,
1640 ) -> bool {
1641 self.extension::<OffchainDbExt>()
1642 .expect(
1643 "local_storage_compare_and_set can be called only in the offchain call context
1644 with OffchainDb extension",
1645 )
1646 .local_storage_compare_and_set(kind, key, old_value.as_deref(), new_value)
1647 }
1648
1649 fn local_storage_get(
1655 &mut self,
1656 kind: PassAs<StorageKind, u32>,
1657 key: PassFatPointerAndRead<&[u8]>,
1658 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
1659 self.extension::<OffchainDbExt>()
1660 .expect(
1661 "local_storage_get can be called only in the offchain call context with
1662 OffchainDb extension",
1663 )
1664 .local_storage_get(kind, key)
1665 }
1666
1667 fn http_request_start(
1672 &mut self,
1673 method: PassFatPointerAndRead<&str>,
1674 uri: PassFatPointerAndRead<&str>,
1675 meta: PassFatPointerAndRead<&[u8]>,
1676 ) -> AllocateAndReturnByCodec<Result<HttpRequestId, ()>> {
1677 self.extension::<OffchainWorkerExt>()
1678 .expect("http_request_start can be called only in the offchain worker context")
1679 .http_request_start(method, uri, meta)
1680 }
1681
1682 fn http_request_add_header(
1684 &mut self,
1685 request_id: PassAs<HttpRequestId, u16>,
1686 name: PassFatPointerAndRead<&str>,
1687 value: PassFatPointerAndRead<&str>,
1688 ) -> AllocateAndReturnByCodec<Result<(), ()>> {
1689 self.extension::<OffchainWorkerExt>()
1690 .expect("http_request_add_header can be called only in the offchain worker context")
1691 .http_request_add_header(request_id, name, value)
1692 }
1693
1694 fn http_request_write_body(
1701 &mut self,
1702 request_id: PassAs<HttpRequestId, u16>,
1703 chunk: PassFatPointerAndRead<&[u8]>,
1704 deadline: PassFatPointerAndDecode<Option<Timestamp>>,
1705 ) -> AllocateAndReturnByCodec<Result<(), HttpError>> {
1706 self.extension::<OffchainWorkerExt>()
1707 .expect("http_request_write_body can be called only in the offchain worker context")
1708 .http_request_write_body(request_id, chunk, deadline)
1709 }
1710
1711 fn http_response_wait(
1719 &mut self,
1720 ids: PassFatPointerAndDecodeSlice<&[HttpRequestId]>,
1721 deadline: PassFatPointerAndDecode<Option<Timestamp>>,
1722 ) -> AllocateAndReturnByCodec<Vec<HttpRequestStatus>> {
1723 self.extension::<OffchainWorkerExt>()
1724 .expect("http_response_wait can be called only in the offchain worker context")
1725 .http_response_wait(ids, deadline)
1726 }
1727
1728 fn http_response_headers(
1733 &mut self,
1734 request_id: PassAs<HttpRequestId, u16>,
1735 ) -> AllocateAndReturnByCodec<Vec<(Vec<u8>, Vec<u8>)>> {
1736 self.extension::<OffchainWorkerExt>()
1737 .expect("http_response_headers can be called only in the offchain worker context")
1738 .http_response_headers(request_id)
1739 }
1740
1741 fn http_response_read_body(
1750 &mut self,
1751 request_id: PassAs<HttpRequestId, u16>,
1752 buffer: PassFatPointerAndReadWrite<&mut [u8]>,
1753 deadline: PassFatPointerAndDecode<Option<Timestamp>>,
1754 ) -> AllocateAndReturnByCodec<Result<u32, HttpError>> {
1755 self.extension::<OffchainWorkerExt>()
1756 .expect("http_response_read_body can be called only in the offchain worker context")
1757 .http_response_read_body(request_id, buffer, deadline)
1758 .map(|r| r as u32)
1759 }
1760
1761 fn set_authorized_nodes(
1763 &mut self,
1764 nodes: PassFatPointerAndDecode<Vec<OpaquePeerId>>,
1765 authorized_only: bool,
1766 ) {
1767 self.extension::<OffchainWorkerExt>()
1768 .expect("set_authorized_nodes can be called only in the offchain worker context")
1769 .set_authorized_nodes(nodes, authorized_only)
1770 }
1771}
1772
1773#[runtime_interface(wasm_only)]
1775pub trait Allocator {
1776 fn malloc(&mut self, size: u32) -> Pointer<u8> {
1778 self.allocate_memory(size).expect("Failed to allocate memory")
1779 }
1780
1781 fn free(&mut self, ptr: Pointer<u8>) {
1783 self.deallocate_memory(ptr).expect("Failed to deallocate memory")
1784 }
1785}
1786
1787#[runtime_interface(wasm_only)]
1790pub trait PanicHandler {
1791 #[trap_on_return]
1793 fn abort_on_panic(&mut self, message: PassFatPointerAndRead<&str>) {
1794 self.register_panic_error_message(message);
1795 }
1796}
1797
1798#[runtime_interface]
1800pub trait Logging {
1801 fn log(
1808 level: PassAs<RuntimeInterfaceLogLevel, u8>,
1809 target: PassFatPointerAndRead<&str>,
1810 message: PassFatPointerAndRead<&[u8]>,
1811 ) {
1812 if let Ok(message) = core::str::from_utf8(message) {
1813 log::log!(target: target, log::Level::from(level), "{}", message)
1814 }
1815 }
1816
1817 fn max_level() -> ReturnAs<LogLevelFilter, u8> {
1819 log::max_level().into()
1820 }
1821}
1822
1823#[runtime_interface(wasm_only, no_tracing)]
1826pub trait WasmTracing {
1827 fn enabled(&mut self, metadata: PassFatPointerAndDecode<pezsp_tracing::WasmMetadata>) -> bool {
1837 let metadata: &tracing_core::metadata::Metadata<'static> = (&metadata).into();
1838 tracing::dispatcher::get_default(|d| d.enabled(metadata))
1839 }
1840
1841 fn enter_span(
1848 &mut self,
1849 span: PassFatPointerAndDecode<pezsp_tracing::WasmEntryAttributes>,
1850 ) -> u64 {
1851 let span: tracing::Span = span.into();
1852 match span.id() {
1853 Some(id) => tracing::dispatcher::get_default(|d| {
1854 let final_id = d.clone_span(&id);
1857 d.enter(&final_id);
1858 final_id.into_u64()
1859 }),
1860 _ => 0,
1861 }
1862 }
1863
1864 fn event(&mut self, event: PassFatPointerAndDecode<pezsp_tracing::WasmEntryAttributes>) {
1866 event.emit();
1867 }
1868
1869 fn exit(&mut self, span: u64) {
1872 tracing::dispatcher::get_default(|d| {
1873 let id = tracing_core::span::Id::from_u64(span);
1874 d.exit(&id);
1875 });
1876 }
1877}
1878
1879#[cfg(all(bizinikiwi_runtime, feature = "with-tracing"))]
1880mod tracing_setup {
1881 use super::wasm_tracing;
1882 use core::sync::atomic::{AtomicBool, Ordering};
1883 use tracing_core::{
1884 dispatcher::{set_global_default, Dispatch},
1885 span::{Attributes, Id, Record},
1886 Event, Metadata,
1887 };
1888
1889 static TRACING_SET: AtomicBool = AtomicBool::new(false);
1890
1891 struct PassingTracingSubscriber;
1894
1895 impl tracing_core::Subscriber for PassingTracingSubscriber {
1896 fn enabled(&self, metadata: &Metadata<'_>) -> bool {
1897 wasm_tracing::enabled(metadata.into())
1898 }
1899 fn new_span(&self, attrs: &Attributes<'_>) -> Id {
1900 Id::from_u64(wasm_tracing::enter_span(attrs.into()))
1901 }
1902 fn enter(&self, _: &Id) {
1903 }
1905 fn record(&self, _: &Id, _: &Record<'_>) {
1908 unimplemented! {} }
1910 fn record_follows_from(&self, _: &Id, _: &Id) {
1913 unimplemented! {} }
1915 fn event(&self, event: &Event<'_>) {
1916 wasm_tracing::event(event.into())
1917 }
1918 fn exit(&self, span: &Id) {
1919 wasm_tracing::exit(span.into_u64())
1920 }
1921 }
1922
1923 pub fn init_tracing() {
1927 if TRACING_SET.load(Ordering::Relaxed) == false {
1928 set_global_default(Dispatch::new(PassingTracingSubscriber {}))
1929 .expect("We only ever call this once");
1930 TRACING_SET.store(true, Ordering::Relaxed);
1931 }
1932 }
1933}
1934
1935#[cfg(not(all(bizinikiwi_runtime, feature = "with-tracing")))]
1936mod tracing_setup {
1937 pub fn init_tracing() {}
1940}
1941
1942pub use tracing_setup::init_tracing;
1943
1944pub fn unreachable() -> ! {
1949 #[cfg(target_family = "wasm")]
1950 {
1951 core::arch::wasm32::unreachable();
1952 }
1953
1954 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
1955 unsafe {
1956 core::arch::asm!("unimp", options(noreturn));
1957 }
1958
1959 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64", target_family = "wasm")))]
1960 unreachable!();
1961}
1962
1963#[cfg(all(not(feature = "disable_panic_handler"), bizinikiwi_runtime))]
1965#[panic_handler]
1966pub fn panic(info: &core::panic::PanicInfo) -> ! {
1967 let message = alloc::format!("{}", info);
1968 #[cfg(feature = "improved_panic_error_reporting")]
1969 {
1970 panic_handler::abort_on_panic(&message);
1971 }
1972 #[cfg(not(feature = "improved_panic_error_reporting"))]
1973 {
1974 logging::log(RuntimeInterfaceLogLevel::Error, "runtime", message.as_bytes());
1975 unreachable();
1976 }
1977}
1978
1979#[cfg(all(not(feature = "disable_oom"), enable_alloc_error_handler))]
1981#[alloc_error_handler]
1982pub fn oom(_: core::alloc::Layout) -> ! {
1983 #[cfg(feature = "improved_panic_error_reporting")]
1984 {
1985 panic_handler::abort_on_panic("Runtime memory exhausted.");
1986 }
1987 #[cfg(not(feature = "improved_panic_error_reporting"))]
1988 {
1989 logging::log(
1990 RuntimeInterfaceLogLevel::Error,
1991 "runtime",
1992 b"Runtime memory exhausted. Aborting",
1993 );
1994 unreachable();
1995 }
1996}
1997
1998#[cfg(feature = "std")] pub type TestExternalities = pezsp_state_machine::TestExternalities<pezsp_core::Blake2Hasher>;
2001
2002#[docify::export]
2006#[cfg(not(bizinikiwi_runtime))]
2007pub type BizinikiwiHostFunctions = (
2008 storage::HostFunctions,
2009 default_child_storage::HostFunctions,
2010 misc::HostFunctions,
2011 wasm_tracing::HostFunctions,
2012 offchain::HostFunctions,
2013 crypto::HostFunctions,
2014 hashing::HostFunctions,
2015 allocator::HostFunctions,
2016 panic_handler::HostFunctions,
2017 logging::HostFunctions,
2018 crate::trie::HostFunctions,
2019 offchain_index::HostFunctions,
2020 transaction_index::HostFunctions,
2021);
2022
2023#[cfg(test)]
2024mod tests {
2025 use super::*;
2026 use pezsp_core::{crypto::UncheckedInto, map, storage::Storage};
2027 use pezsp_state_machine::BasicExternalities;
2028
2029 #[test]
2030 fn storage_works() {
2031 let mut t = BasicExternalities::default();
2032 t.execute_with(|| {
2033 assert_eq!(storage::get(b"hello"), None);
2034 storage::set(b"hello", b"world");
2035 assert_eq!(storage::get(b"hello"), Some(b"world".to_vec().into()));
2036 assert_eq!(storage::get(b"foo"), None);
2037 storage::set(b"foo", &[1, 2, 3][..]);
2038 });
2039
2040 t = BasicExternalities::new(Storage {
2041 top: map![b"foo".to_vec() => b"bar".to_vec()],
2042 children_default: map![],
2043 });
2044
2045 t.execute_with(|| {
2046 assert_eq!(storage::get(b"hello"), None);
2047 assert_eq!(storage::get(b"foo"), Some(b"bar".to_vec().into()));
2048 });
2049
2050 let value = vec![7u8; 35];
2051 let storage =
2052 Storage { top: map![b"foo00".to_vec() => value.clone()], children_default: map![] };
2053 t = BasicExternalities::new(storage);
2054
2055 t.execute_with(|| {
2056 assert_eq!(storage::get(b"hello"), None);
2057 assert_eq!(storage::get(b"foo00"), Some(value.clone().into()));
2058 });
2059 }
2060
2061 #[test]
2062 fn read_storage_works() {
2063 let value = b"\x0b\0\0\0Hello world".to_vec();
2064 let mut t = BasicExternalities::new(Storage {
2065 top: map![b":test".to_vec() => value.clone()],
2066 children_default: map![],
2067 });
2068
2069 t.execute_with(|| {
2070 let mut v = [0u8; 4];
2071 assert_eq!(storage::read(b":test", &mut v[..], 0).unwrap(), value.len() as u32);
2072 assert_eq!(v, [11u8, 0, 0, 0]);
2073 let mut w = [0u8; 11];
2074 assert_eq!(storage::read(b":test", &mut w[..], 4).unwrap(), value.len() as u32 - 4);
2075 assert_eq!(&w, b"Hello world");
2076 });
2077 }
2078
2079 #[test]
2080 fn clear_prefix_works() {
2081 let mut t = BasicExternalities::new(Storage {
2082 top: map![
2083 b":a".to_vec() => b"\x0b\0\0\0Hello world".to_vec(),
2084 b":abcd".to_vec() => b"\x0b\0\0\0Hello world".to_vec(),
2085 b":abc".to_vec() => b"\x0b\0\0\0Hello world".to_vec(),
2086 b":abdd".to_vec() => b"\x0b\0\0\0Hello world".to_vec()
2087 ],
2088 children_default: map![],
2089 });
2090
2091 t.execute_with(|| {
2092 assert!(matches!(
2098 storage::clear_prefix(b":abc", None),
2099 KillStorageResult::AllRemoved(2),
2100 ));
2101
2102 assert!(storage::get(b":a").is_some());
2103 assert!(storage::get(b":abdd").is_some());
2104 assert!(storage::get(b":abcd").is_none());
2105 assert!(storage::get(b":abc").is_none());
2106
2107 assert!(matches!(
2113 storage::clear_prefix(b":abc", None),
2114 KillStorageResult::AllRemoved(0),
2115 ));
2116 });
2117 }
2118
2119 fn zero_ed_pub() -> ed25519::Public {
2120 [0u8; 32].unchecked_into()
2121 }
2122
2123 fn zero_ed_sig() -> ed25519::Signature {
2124 ed25519::Signature::from_raw([0u8; 64])
2125 }
2126
2127 #[test]
2128 fn use_dalek_ext_works() {
2129 let mut ext = BasicExternalities::default();
2130 ext.register_extension(UseDalekExt::default());
2131
2132 ext.execute_with(|| {
2134 assert!(!crypto::ed25519_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()));
2135 });
2136
2137 BasicExternalities::default().execute_with(|| {
2139 assert!(crypto::ed25519_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()));
2140 })
2141 }
2142
2143 #[test]
2144 fn dalek_should_not_panic_on_invalid_signature() {
2145 let mut ext = BasicExternalities::default();
2146 ext.register_extension(UseDalekExt::default());
2147
2148 ext.execute_with(|| {
2149 let mut bytes = [0u8; 64];
2150 bytes[63] = 0b1110_0000;
2152
2153 assert!(!crypto::ed25519_verify(
2154 &ed25519::Signature::from_raw(bytes),
2155 &Vec::new(),
2156 &zero_ed_pub()
2157 ));
2158 });
2159 }
2160}