1use crate::e2e_invoke::ledger_entry_to_ledger_key;
2use crate::storage::EntryWithLiveUntil;
3use crate::{
4 budget::Budget,
5 builtin_contracts::testutils::create_account,
6 storage::{SnapshotSource, Storage},
7 xdr::{
8 AccountId, ContractCostType, LedgerEntry, LedgerKey, PublicKey, ScAddress, ScVal, ScVec,
9 Uint256,
10 },
11 AddressObject, BytesObject, Env, EnvBase, Host, HostError, LedgerInfo, MeteredOrdMap,
12 StorageType, SymbolSmall, Val, VecObject,
13};
14use ed25519_dalek::SigningKey;
15use rand::RngCore;
16use std::panic::{catch_unwind, set_hook, take_hook, UnwindSafe};
17use std::{cell::Cell, collections::BTreeMap, rc::Rc, sync::Once};
18
19pub fn call_with_suppressed_panic_hook<C, R>(closure: C) -> std::thread::Result<R>
32where
33 C: FnOnce() -> R + UnwindSafe,
34{
35 thread_local! {
36 static TEST_CONTRACT_CALL_COUNT: Cell<u64> = const { Cell::new(0) };
37 }
38
39 static WRAP_PANIC_HOOK: Once = Once::new();
40
41 WRAP_PANIC_HOOK.call_once(|| {
42 let existing_panic_hook = take_hook();
43 set_hook(Box::new(move |info| {
44 let calling_test_contract = TEST_CONTRACT_CALL_COUNT.with(|c| c.get() != 0);
45 if !calling_test_contract {
46 existing_panic_hook(info)
47 }
48 }))
49 });
50
51 TEST_CONTRACT_CALL_COUNT.with(|c| {
52 let old_count = c.get();
53 let new_count = old_count.checked_add(1).expect("overflow");
54 c.set(new_count);
55 });
56
57 let res = catch_unwind(closure);
58
59 TEST_CONTRACT_CALL_COUNT.with(|c| {
60 let old_count = c.get();
61 let new_count = old_count.checked_sub(1).expect("overflow");
62 c.set(new_count);
63 });
64
65 res
66}
67
68pub trait AsScVal {
70 fn as_scval(&self) -> ScVal;
71}
72
73impl AsScVal for u32 {
74 fn as_scval(&self) -> ScVal {
75 ScVal::U32(*self)
76 }
77}
78
79impl AsScVal for i32 {
80 fn as_scval(&self) -> ScVal {
81 ScVal::I32(*self)
82 }
83}
84
85impl AsScVal for u64 {
86 fn as_scval(&self) -> ScVal {
87 ScVal::U64(*self)
88 }
89}
90
91impl AsScVal for i64 {
92 fn as_scval(&self) -> ScVal {
93 ScVal::I64(*self)
94 }
95}
96
97impl AsScVal for ScVec {
98 fn as_scval(&self) -> ScVal {
99 ScVal::Vec(Some(self.clone()))
100 }
101}
102
103pub fn generate_account_id(host: &Host) -> AccountId {
104 AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(
105 generate_bytes_array(host),
106 )))
107}
108
109pub fn generate_bytes_array(host: &Host) -> [u8; 32] {
110 let mut bytes: [u8; 32] = Default::default();
111 host.with_test_prng(|chacha| {
112 chacha.fill_bytes(&mut bytes);
113 Ok(())
114 })
115 .unwrap();
116 bytes
117}
118
119pub struct MockSnapshotSource(BTreeMap<Rc<LedgerKey>, (Rc<LedgerEntry>, Option<u32>)>);
120
121impl MockSnapshotSource {
122 pub fn new() -> Self {
123 Self(BTreeMap::<Rc<LedgerKey>, (Rc<LedgerEntry>, Option<u32>)>::new())
124 }
125
126 pub fn from_entries(entries: Vec<(LedgerEntry, Option<u32>)>) -> Self {
127 let mut map = BTreeMap::<Rc<LedgerKey>, (Rc<LedgerEntry>, Option<u32>)>::new();
128 let dummy_budget = Budget::default();
129 for (e, maybe_ttl) in entries {
130 let key = Rc::new(ledger_entry_to_ledger_key(&e, &dummy_budget).unwrap());
131 map.insert(key, (Rc::new(e), maybe_ttl));
132 }
133 Self(map)
134 }
135}
136
137impl SnapshotSource for MockSnapshotSource {
138 fn get(&self, key: &Rc<LedgerKey>) -> Result<Option<EntryWithLiveUntil>, HostError> {
139 if let Some((entry, live_until)) = self.0.get(key) {
140 Ok(Some((Rc::clone(entry), *live_until)))
141 } else {
142 Ok(None)
143 }
144 }
145}
146
147#[cfg(test)]
148pub(crate) fn interface_meta_with_custom_versions(proto: u32, pre: u32) -> Vec<u8> {
149 use crate::xdr::{Limited, Limits, ScEnvMetaEntry, ScEnvMetaEntryInterfaceVersion, WriteXdr};
150 let entry = ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(ScEnvMetaEntryInterfaceVersion {
151 protocol: proto,
152 pre_release: pre,
153 });
154 let bytes = Vec::<u8>::new();
155 let mut w = Limited::new(bytes, Limits::none());
156 entry.write_xdr(&mut w).unwrap();
157 w.inner
158}
159
160impl Host {
161 pub const TEST_PRNG_SEED: &'static [u8; 32] = b"12345678901234567890123456789012";
162
163 pub fn set_test_prng(&self) {
164 self.set_base_prng_seed(*Self::TEST_PRNG_SEED).unwrap();
165 }
166
167 pub fn current_test_protocol() -> u32 {
168 let max_supported_protocol = crate::meta::INTERFACE_VERSION.protocol;
169 let min_supported_protocol = crate::host::MIN_LEDGER_PROTOCOL_VERSION;
170 if let Ok(vers) = std::env::var("TEST_PROTOCOL") {
171 let test_protocol = vers.parse().expect("parsing TEST_PROTOCOL");
172 if test_protocol >= min_supported_protocol && test_protocol <= max_supported_protocol {
173 test_protocol
174 } else if test_protocol > max_supported_protocol {
175 let next_advice = if cfg!(feature = "next") {
176 ""
177 } else {
178 " (consider building with --feature=next)"
179 };
180 panic!(
181 "TEST_PROTOCOL={} is higher than the max supported protocol {}{}",
182 test_protocol, max_supported_protocol, next_advice
183 );
184 } else {
185 panic!(
186 "TEST_PROTOCOL={} is lower than the min supported protocol {}",
187 test_protocol, min_supported_protocol
188 );
189 }
190 } else {
191 max_supported_protocol
192 }
193 }
194
195 pub fn set_test_ledger_info_with_current_test_protocol(&self) {
196 self.set_ledger_info(LedgerInfo {
197 protocol_version: Self::current_test_protocol(),
198 sequence_number: 0,
199 timestamp: 0,
200 network_id: [0; 32],
201 base_reserve: 0,
202 min_persistent_entry_ttl: 4096,
203 min_temp_entry_ttl: 16,
204 max_entry_ttl: 6_312_000,
205 })
206 .unwrap();
207 }
208
209 pub fn test_host() -> Self {
210 let host = Host::default();
211 host.set_test_ledger_info_with_current_test_protocol();
212 host
213 }
214
215 pub fn test_host_with_prng() -> Self {
216 let host = Self::test_host();
217 host.set_test_prng();
218 host
219 }
220
221 pub fn test_host_with_recording_footprint() -> Self {
222 let snapshot_source = Rc::<MockSnapshotSource>::new(MockSnapshotSource::new());
223 let storage = Storage::with_recording_footprint(snapshot_source);
224 let host = Host::with_storage_and_budget(storage, Budget::default());
225 host.set_test_ledger_info_with_current_test_protocol();
226 host.set_test_prng();
227 host
228 }
229
230 pub fn test_budget(self, cpu: u64, mem: u64) -> Self {
231 self.with_budget(|budget| {
232 budget.reset_limits(cpu, mem)?; budget.reset_models()?;
234 Ok(())
235 })
236 .unwrap();
237 self
238 }
239
240 pub fn enable_model(
241 self,
242 ty: ContractCostType,
243 const_cpu: u64,
244 lin_cpu: u64,
245 const_mem: u64,
246 lin_mem: u64,
247 ) -> Self {
248 self.with_budget(|budget| {
249 budget.override_model_with_unscaled_params(ty, const_cpu, lin_cpu, const_mem, lin_mem)
250 })
251 .unwrap();
252 self
253 }
254
255 pub fn test_scvec<T: AsScVal>(&self, vals: &[T]) -> Result<ScVec, HostError> {
256 let v: Vec<ScVal> = vals.iter().map(|x| x.as_scval()).collect();
257 self.map_err(v.try_into())
258 }
259
260 pub fn test_vec_obj<T: AsScVal>(&self, vals: &[T]) -> Result<VecObject, HostError> {
261 let v = self.test_scvec(vals)?;
262 Ok(self.to_host_val(&ScVal::Vec(Some(v)))?.try_into()?)
263 }
264
265 pub fn test_vec_val<T: AsScVal>(&self, vals: &[T]) -> Result<Val, HostError> {
266 let v = self.test_scvec(vals)?;
267 self.to_host_val(&ScVal::Vec(Some(v)))
268 }
269
270 pub fn test_bin_scobj(&self, vals: &[u8]) -> Result<ScVal, HostError> {
271 Ok(ScVal::Bytes(self.map_err(vals.to_vec().try_into())?))
272 }
273
274 pub fn test_bin_obj(&self, vals: &[u8]) -> Result<BytesObject, HostError> {
275 let scval: ScVal = self.test_bin_scobj(vals)?;
276 let val: Val = self.to_host_val(&scval)?;
277 Ok(val.try_into()?)
278 }
279
280 pub fn register_test_contract_wasm_from_source_account(
286 &self,
287 contract_wasm: &[u8],
288 account: AccountId,
289 salt: [u8; 32],
290 ) -> Result<AddressObject, HostError> {
291 let _span = tracy_span!("register_test_contract_wasm_from_source_account");
292 #[cfg(any(test, feature = "testutils"))]
293 let _invocation_meter_scope = self.maybe_meter_invocation()?;
294
295 let prev_source_account = self.source_account_id()?;
298 let prev_auth_manager = self.snapshot_auth_manager()?;
300 self.switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)?;
301
302 let wasm_hash = self.upload_wasm(self.bytes_new_from_slice(contract_wasm)?)?;
303 self.set_source_account(account.clone())?;
304 let contract_address = self.create_contract(
305 self.add_host_object(ScAddress::Account(account.clone()))?,
306 wasm_hash,
307 self.bytes_new_from_slice(&salt)?,
308 )?;
309 if let Some(prev_account) = prev_source_account {
310 self.set_source_account(prev_account)?;
311 }
312 self.set_auth_manager(prev_auth_manager)?;
313 Ok(contract_address)
314 }
315
316 pub fn register_test_contract_wasm(&self, contract_wasm: &[u8]) -> AddressObject {
321 self.register_test_contract_wasm_from_source_account(
322 contract_wasm,
323 generate_account_id(self),
324 generate_bytes_array(self),
325 )
326 .unwrap()
327 }
328
329 pub fn new_recording_fuzz_host(
330 contract_wasms: &[&[u8]],
331 data_keys: &BTreeMap<ScVal, (StorageType, bool)>,
332 n_signers: usize,
333 ) -> (Host, Vec<AddressObject>, Vec<ed25519_dalek::SigningKey>) {
334 use crate::builtin_contracts::testutils::{
335 generate_signing_key, signing_key_to_account_id,
336 };
337
338 let host = Self::test_host_with_recording_footprint();
339 host.switch_to_recording_auth(false).unwrap();
340 host.with_budget(|budget| {
341 budget.reset_unlimited()?;
342 Ok(())
343 })
344 .unwrap();
345 let mut contract_addresses = Vec::new();
346 for contract_wasm in contract_wasms.iter() {
347 contract_addresses.push(host.register_test_contract_wasm(contract_wasm));
348 }
349 let ScAddress::Contract(contract_hash) =
350 host.scaddress_from_address(contract_addresses[0]).unwrap()
351 else {
352 panic!()
353 };
354
355 let test = SymbolSmall::try_from_str("test").unwrap();
356
357 host.with_test_contract_frame(contract_hash.clone(), test.into(), || {
359 for (k, (t, _)) in data_keys.iter() {
360 let v = host.to_host_val(k).unwrap();
361 host.put_contract_data(v, v, *t).unwrap();
362 }
363 Ok(Val::VOID.into())
364 })
365 .unwrap();
366
367 let signing_keys = (0..n_signers)
369 .map(|_| generate_signing_key(&host))
370 .collect();
371 for signing_key in &signing_keys {
372 create_account(
373 &host,
374 &signing_key_to_account_id(signing_key),
375 vec![(&signing_key, 1)],
376 100_000_000,
377 1,
378 [1, 0, 0, 0],
379 None,
380 None,
381 0,
382 )
383 }
384
385 (host, contract_addresses, signing_keys)
386 }
387
388 pub fn switch_fuzz_host_to_enforcing(
389 &self,
390 data_keys: &BTreeMap<ScVal, (StorageType, bool)>,
391 signing_keys: &[ed25519_dalek::SigningKey],
392 ) {
393 use crate::builtin_contracts::testutils::TestSigner;
394 use crate::xdr::{
395 HashIdPreimage, HashIdPreimageSorobanAuthorization, SorobanAddressCredentials,
396 SorobanAuthorizationEntry, SorobanCredentials,
397 };
398 self.with_budget(|budget| {
399 budget.reset_unlimited()?;
400 Ok(())
401 })
402 .unwrap();
403
404 self.with_mut_storage(|storage| {
408 storage.footprint.0 = MeteredOrdMap::from_exact_iter(
409 storage
410 .footprint
411 .0
412 .iter(self.budget_ref())
413 .unwrap()
414 .map(|(k, accesstype)| {
415 let mut accesstype = *accesstype;
416 if let LedgerKey::ContractData(k) = k.as_ref() {
417 if let Some((_, ro)) = data_keys.get(&k.key) {
418 if *ro {
419 accesstype = crate::storage::AccessType::ReadOnly;
420 } else {
421 accesstype = crate::storage::AccessType::ReadWrite;
422 }
423 }
424 }
425 (k.clone(), accesstype)
426 }),
427 self.budget_ref(),
428 )
429 .unwrap();
430
431 let mut map = BTreeMap::new();
435 for (k, v) in storage.map.iter(self.budget_ref()).unwrap() {
436 map.insert(k.clone(), v.clone());
437 }
438 for (k, _) in storage.footprint.0.iter(self.budget_ref()).unwrap() {
439 if !map.contains_key(k) {
440 map.insert(k.clone(), None);
441 }
442 }
443 for (k, v) in map.iter_mut() {
445 if let LedgerKey::ContractData(k) = k.as_ref() {
446 if let ScVal::LedgerKeyNonce(_) = &k.key {
447 *v = None;
448 }
449 }
450 }
451 storage.map = MeteredOrdMap::from_exact_iter(
452 map.iter().map(|(k, v)| (k.clone(), v.clone())),
453 self.budget_ref(),
454 )
455 .unwrap();
456 storage.mode = crate::storage::FootprintMode::Enforcing;
457 Ok(())
458 })
459 .unwrap();
460
461 let mut auth_entries = Vec::new();
463 let account_signers = signing_keys
464 .iter()
465 .map(TestSigner::account)
466 .collect::<Vec<_>>();
467 for payload in self.get_recorded_auth_payloads().unwrap().iter() {
468 for signer in account_signers.iter() {
469 let Some(address) = &payload.address else {
470 continue;
471 };
472 let Some(nonce) = payload.nonce else { continue };
473 if *address == ScAddress::Account(signer.account_id()) {
474 let address = address.clone();
475 let signature_expiration_ledger =
476 u32::from(self.get_ledger_sequence().unwrap()) + 10000;
477 let network_id = self
478 .with_ledger_info(|li: &LedgerInfo| Ok(li.network_id))
479 .unwrap()
480 .try_into()
481 .unwrap();
482 let signature_payload_preimage =
483 HashIdPreimage::SorobanAuthorization(HashIdPreimageSorobanAuthorization {
484 network_id,
485 invocation: payload.invocation.clone(),
486 nonce,
487 signature_expiration_ledger,
488 });
489 let signature_payload =
490 self.metered_hash_xdr(&signature_payload_preimage).unwrap();
491 let signature = signer.sign(&self, &signature_payload);
492 let credentials = SorobanCredentials::Address(SorobanAddressCredentials {
493 address: address.clone(),
494 nonce: nonce,
495 signature_expiration_ledger,
496 signature,
497 });
498 let entry = SorobanAuthorizationEntry {
499 credentials,
500 root_invocation: payload.invocation.clone(),
501 };
502 auth_entries.push(entry);
503 }
504 }
505 }
506 self.set_authorization_entries(auth_entries).unwrap();
507 }
508
509 #[cfg(all(test, feature = "testutils"))]
510 pub(crate) fn measured_call(
511 &self,
512 contract: AddressObject,
513 func: crate::Symbol,
514 args: VecObject,
515 ) -> Result<Val, HostError> {
516 use crate::{budget::AsBudget, host::TraceEvent};
517 use soroban_bench_utils::HostTracker;
518 use std::cell::RefCell;
519
520 let _span = tracy_span!("measured_call");
521 let budget = self.as_budget();
522 budget.reset_unlimited()?;
523 let ht = Rc::new(RefCell::new(HostTracker::new()));
524
525 if std::env::var("EXCLUDE_VM_INSTANTIATION").is_ok() {
526 let ht2 = ht.clone();
527 let budget2 = budget.clone();
528 self.set_trace_hook(Some(Rc::new(move |_, evt| {
529 if let TraceEvent::PushCtx(_) = evt {
530 budget2.reset_unlimited()?;
531 ht2.borrow_mut().start(None);
532 }
533 Ok(())
534 })))?;
535 } else {
536 ht.borrow_mut().start(None);
537 }
538 let val = self.call(contract, func, args);
539 self.set_trace_hook(None)?;
540
541 let (cpu_actual, mem_actual, time_nsecs) = Rc::into_inner(ht).unwrap().into_inner().stop();
542
543 let cpu_metered = budget
544 .get_cpu_insns_consumed()
545 .expect("unable to retrieve cpu consumed");
546 let mem_metered = budget
547 .get_mem_bytes_consumed()
548 .expect("unable to retrieve mem consumed");
549
550 let cpu_diff = (cpu_metered - cpu_actual) as i64;
551 let cpu_metered_diff_percent = 100 * cpu_diff / (cpu_metered as i64).max(1);
552 let mem_diff = (mem_metered - mem_actual) as i64;
553 let mem_metered_diff_percent = 100 * mem_diff / (mem_metered as i64).max(1);
554 let metered_insn_nsecs_ratio: f64 = (cpu_metered as f64) / (time_nsecs as f64).max(1.0);
555 let actual_insn_nsecs_ratio: f64 = (cpu_actual as f64) / (time_nsecs as f64).max(1.0);
556
557 println!();
558 println!(
559 "metered cpu insns: {}, actual cpu insns {}, diff: {} ({:.3}%)",
560 cpu_metered, cpu_actual, cpu_diff, cpu_metered_diff_percent
561 );
562 println!(
563 "metered mem bytes: {}, actual mem bytes {}, diff: {} ({:.3}%)",
564 mem_metered, mem_actual, mem_diff, mem_metered_diff_percent
565 );
566 println!("time_nsecs: {}", time_nsecs);
567 println!(
568 "metered cpu_insn/time_nsecs ratio: {:.3}",
569 metered_insn_nsecs_ratio
570 );
571 println!(
572 "actual cpu_insn/time_nsecs ratio: {:.3}",
573 actual_insn_nsecs_ratio
574 );
575 println!();
576
577 val
578 }
579}
580
581#[cfg(test)]
582pub(crate) mod wasm {
583 use crate::{Symbol, Tag, U32Val, Val};
584 use soroban_synth_wasm::{Arity, FuncRef, LocalRef, ModEmitter, Operand};
585 use wasm_encoder::{ConstExpr, Elements, RefType};
586
587 pub(crate) fn wasm_module_with_4n_insns(n: usize) -> Vec<u8> {
588 let mut fe = ModEmitter::default_with_test_protocol().func(Arity(1), 0);
589 let arg = fe.args[0];
590 fe.push(Operand::Const64(1));
591 for i in 0..n {
592 fe.push(arg.0);
593 fe.push(Operand::Const64(i as i64));
594 fe.i64_mul();
595 fe.i64_add();
596 }
597 fe.drop();
598 fe.push(Symbol::try_from_small_str("pass").unwrap());
599 fe.finish_and_export("test").finish()
600 }
601
602 pub(crate) fn wasm_module_with_n_funcs_no_export(n: usize) -> Vec<u8> {
603 let mut me = ModEmitter::default_with_test_protocol();
604 for _i in 0..n {
605 let mut fe = me.func(Arity(0), 0);
606 fe.push(Symbol::try_from_small_str("pass").unwrap());
607 me = fe.finish().0;
608 }
609 me.finish()
610 }
611
612 pub(crate) fn wasm_module_with_repeated_exporting_the_same_func(n: usize) -> Vec<u8> {
613 let me = ModEmitter::default_with_test_protocol();
614 let mut fe = me.func(Arity(0), 0);
615 fe.push(Symbol::try_from_small_str("pass").unwrap());
616 let (mut me, fid) = fe.finish();
617 for i in 0..n {
618 me.export_func(fid, format!("test{}", i).as_str());
619 }
620 me.finish_no_validate()
621 }
622
623 pub(crate) fn wasm_module_with_mem_grow(n_pages: usize) -> Vec<u8> {
624 let mut fe = ModEmitter::default_with_test_protocol().func(Arity(0), 0);
625 fe.push(Operand::Const32(n_pages as i32));
626 fe.memory_grow();
627 fe.drop();
628 fe.push(Symbol::try_from_small_str("pass").unwrap());
629 fe.finish_and_export("test").finish()
630 }
631
632 pub(crate) fn wasm_module_with_linear_memory_logging() -> Vec<u8> {
633 let mut me = ModEmitter::default_with_test_protocol();
634 let f0 = me.import_func("x", "_", Arity(4));
636 let mut fe = me.func(Arity(4), 0);
638 fe.push(Operand::Local(LocalRef(0)));
639 fe.push(Operand::Local(LocalRef(1)));
640 fe.push(Operand::Local(LocalRef(2)));
641 fe.push(Operand::Local(LocalRef(3)));
642 fe.call_func(f0);
643 fe.drop();
644 fe.push(Symbol::try_from_small_str("pass").unwrap());
645 fe.finish_and_export("test").finish()
646 }
647
648 pub(crate) fn wasm_module_with_unreachable() -> Vec<u8> {
649 let me = ModEmitter::default_with_test_protocol();
650 let mut fe = me.func(Arity(0), 0);
651 fe.trap();
652 fe.finish_and_export("test").finish()
653 }
654
655 pub(crate) fn wasm_module_with_indirect_call() -> Vec<u8> {
656 let mut me = ModEmitter::default_with_test_protocol();
657 let f0 = me.import_func("t", "_", Arity(0));
659 let mut fe = me.func(Arity(0), 0);
661 fe.push(Symbol::try_from_small_str("pass").unwrap());
662 let (me, f1) = fe.finish();
663 let mut fe = me.func(Arity(0), 0);
665 fe.push(Symbol::try_from_small_str("pass2").unwrap());
666 let (mut me, f2) = fe.finish();
667 me.define_elem_funcs(&[f0, f1, f2]);
669 let ty = me.get_fn_type(Arity(0), Arity(1));
670 fe = me.func(Arity(1), 0);
672 fe.local_get(LocalRef(0));
673 fe.i32_wrap_i64();
674 fe.call_func_indirect(ty);
676 fe.finish_and_export("test").finish()
677 }
678
679 pub(crate) fn wasm_module_with_div_by_zero() -> Vec<u8> {
680 let me = ModEmitter::default_with_test_protocol();
681 let mut fe = me.func(Arity(0), 0);
682 fe.push(Operand::Const64(123));
683 fe.push(Operand::Const64(0));
684 fe.i64_div_s();
685 fe.finish_and_export("test").finish()
686 }
687
688 pub(crate) fn wasm_module_with_integer_overflow() -> Vec<u8> {
689 let me = ModEmitter::default_with_test_protocol();
690 let mut fe = me.func(Arity(0), 0);
691 fe.push(Operand::Const64(i64::MIN));
692 fe.push(Operand::Const64(-1));
693 fe.i64_div_s();
697 fe.finish_and_export("test").finish()
698 }
699
700 pub(crate) fn wasm_module_with_user_specified_initial_size(
701 mem_pages: u32,
702 elem_count: u32,
703 ) -> Vec<u8> {
704 let me = ModEmitter::from_configs(mem_pages, elem_count);
705 let mut fe = me.func(Arity(0), 0);
707 fe.push(Symbol::try_from_small_str("pass").unwrap());
708 fe.finish_and_export("test").finish()
709 }
710
711 pub(crate) fn wasm_module_with_large_data_segment(
712 mem_pages: u32,
713 mem_offset: u32,
714 len: u32,
715 ) -> Vec<u8> {
716 let mut me = ModEmitter::from_configs(mem_pages, 128);
717 me.define_data_segment(mem_offset, vec![0; len as usize]);
718 let mut fe = me.func(Arity(0), 0);
720 fe.push(Symbol::try_from_small_str("pass").unwrap());
721 fe.finish_and_export("test").finish()
722 }
723
724 pub(crate) fn wasm_module_with_multiple_data_segments(
725 num_pages: u32,
726 num_sgmts: u32,
727 seg_size: u32,
728 ) -> Vec<u8> {
729 let mut me = ModEmitter::from_configs(num_pages, 128);
730 let mem_len = num_pages * 0x10_000;
731 let max_segments = (mem_len / seg_size.max(1)).max(1);
734 for i in 0..num_sgmts % max_segments {
735 me.define_data_segment(i, vec![0; seg_size as usize]);
736 }
737 let mut fe = me.func(Arity(0), 0);
739 fe.push(Symbol::try_from_small_str("pass").unwrap());
740 fe.finish_and_export("test").finish()
741 }
742
743 pub(crate) fn wasm_module_with_large_bytes_from_linear_memory(
744 num_bytes: u32,
745 initial: u8,
746 ) -> Vec<u8> {
747 let num_pages = num_bytes / 0x10_000 + 1;
748 let mut me = ModEmitter::from_configs(num_pages, 128);
749 me.define_data_segment(0, vec![initial; num_bytes as usize]);
750 let mut fe = me.func(Arity(0), 0);
751 fe.bytes_new_from_linear_memory(U32Val::from(0), U32Val::from(num_bytes));
752 fe.finish_and_export("test").finish()
753 }
754
755 pub(crate) fn wasm_module_with_large_vector_from_linear_memory(
756 num_vals: u32,
757 initial: Val,
758 ) -> Vec<u8> {
759 let num_pages = num_vals * 8 / 0x10_000 + 1;
760 let mut me = ModEmitter::from_configs(num_pages, 128);
761 let bytes: Vec<u8> = (0..num_vals)
762 .map(|_| initial.get_payload().to_le_bytes())
763 .flat_map(|a| a.into_iter())
764 .collect();
765 me.define_data_segment(0, bytes);
766 let mut fe = me.func(Arity(0), 0);
767 fe.vec_new_from_linear_memory(U32Val::from(0), U32Val::from(num_vals));
768 fe.finish_and_export("test").finish()
769 }
770
771 pub(crate) fn wasm_module_with_large_map_from_linear_memory(
772 num_vals: u32,
773 initial: Val,
774 ) -> Vec<u8> {
775 let num_pages = (num_vals * 8) * 3 / 0x10_000 + 1;
777 let mut me = ModEmitter::from_configs(num_pages, 128);
778
779 let key_bytes: Vec<u8> = (0..num_vals)
780 .map(|i| format!("{:0>width$}", i, width = 8))
781 .flat_map(|s| s.into_bytes().into_iter())
782 .collect();
783
784 let val_bytes: Vec<u8> = (0..num_vals)
785 .map(|_| initial.get_payload().to_le_bytes())
786 .flat_map(|a| a.into_iter())
787 .collect();
788
789 let slices: Vec<u8> = (0..num_vals)
790 .map(|ptr| {
791 let slice = 8_u64 << 32 | (ptr * 8) as u64;
792 slice.to_le_bytes()
793 })
794 .flat_map(|s| s.into_iter())
795 .collect();
796
797 let bytes: Vec<u8> = key_bytes
798 .into_iter()
799 .chain(val_bytes)
800 .chain(slices)
801 .collect();
802
803 me.define_data_segment(0, bytes);
804 let mut fe = me.func(Arity(0), 0);
805
806 let vals_pos = U32Val::from(num_vals * 8);
807 let keys_pos = U32Val::from(num_vals * 16);
808 fe.map_new_from_linear_memory(keys_pos, vals_pos, U32Val::from(num_vals));
809
810 fe.finish_and_export("test").finish()
811 }
812
813 pub(crate) fn wasm_module_with_data_count(
814 num_sgmts: u32,
815 seg_size: u32,
816 data_count: u32,
817 ) -> Vec<u8> {
818 let pages = num_sgmts * seg_size / 0x10_000 + 1;
821 let mut me = ModEmitter::from_configs(pages, 128);
822 for i in 0..num_sgmts {
823 me.define_data_segment(i * seg_size, vec![7; seg_size as usize]);
824 }
825 me.data_count(data_count);
828 me.finish_no_validate()
829 }
830
831 pub fn post_mvp_wasm_module() -> Vec<u8> {
834 let mut me = ModEmitter::default_with_test_protocol();
835
836 me.define_global_i64(-100, true, Some("global"));
838
839 let mut fe = me.func(Arity(0), 0);
840 fe.i64_const(0x0000_0000_ffff_abcd_u64 as i64);
841
842 fe.i64_extend32s();
844
845 fe.i64_const(8);
847 fe.i64_shl();
848 fe.i64_const(Tag::I64Small as i64);
849 fe.i64_or();
850
851 fe.finish_and_export("test").finish()
852 }
853
854 pub fn empty_wasm_module() -> Vec<u8> {
855 ModEmitter::new().finish()
856 }
857
858 pub fn wasm_module_with_custom_section(name: &str, data: &[u8]) -> Vec<u8> {
859 let mut me = ModEmitter::new();
860 me.custom_section(name, data);
861 me.finish()
862 }
863
864 pub fn wasm_module_with_floating_point_ops() -> Vec<u8> {
865 let me = ModEmitter::default_with_test_protocol();
866 let mut fe = me.func(Arity(0), 0);
867 fe.f64_const(1.1f64);
868 fe.f64_const(2.2f64);
869 fe.f64_add();
870 fe.drop();
871 fe.push(Symbol::try_from_small_str("pass").unwrap());
872 fe.finish_and_export("test").finish()
873 }
874
875 pub fn wasm_module_with_multiple_memories() -> Vec<u8> {
876 let mut me = ModEmitter::new();
877 me.memory(1, None, false, false);
878 me.memory(1, None, false, false);
879 me.finish_no_validate()
880 }
881
882 pub fn wasm_module_lying_about_import_function_type() -> Vec<u8> {
883 let mut me = ModEmitter::default_with_test_protocol();
884 me.import_func("t", "_", Arity(1));
887 me.finish()
888 }
889
890 pub fn wasm_module_importing_nonexistent_function() -> Vec<u8> {
891 let mut me = ModEmitter::default_with_test_protocol();
892 me.import_func("t", "z", Arity(1));
893 me.finish()
894 }
895
896 pub fn wasm_module_with_duplicate_function_import(n: u32) -> Vec<u8> {
897 let mut me = ModEmitter::default_with_test_protocol();
898 for _ in 0..n {
899 me.import_func_no_check("t", "_", Arity(0));
900 }
901 me.finish_no_validate()
902 }
903
904 pub fn wasm_module_with_nonexistent_function_export() -> Vec<u8> {
905 let mut me = ModEmitter::default_with_test_protocol();
906 me.import_func("t", "_", Arity(0));
907 let mut fe = me.func(Arity(0), 0);
908 fe.push(Symbol::try_from_small_str("pass").unwrap());
909 let (mut me, fid) = fe.finish();
910 me.export_func(fid, "test");
912 me.export_func(FuncRef(0), "test0");
914 me.export_func(FuncRef(100), "test100");
916 me.finish_no_validate()
917 }
918
919 pub(crate) fn wasm_module_with_nonexistent_func_element() -> Vec<u8> {
920 let mut me = ModEmitter::default_with_test_protocol();
921 let f0 = me.import_func("t", "_", Arity(0));
923 let mut fe = me.func(Arity(0), 0);
925 fe.push(Symbol::try_from_small_str("pass").unwrap());
926 let (me, f1) = fe.finish();
927 let mut fe = me.func(Arity(0), 0);
929 fe.push(Symbol::try_from_small_str("pass2").unwrap());
930 let (mut me, f2) = fe.finish();
931 me.define_elem_funcs(&[f0, f1, f2, FuncRef(100)]);
933 me.finish_no_validate()
934 }
935
936 pub(crate) fn wasm_module_with_start_function() -> Vec<u8> {
937 let me = ModEmitter::default_with_test_protocol();
938 let fe = me.func_with_arity_and_ret(Arity(0), Arity(0), 0);
939 let (mut me, fid) = fe.finish();
940 me.export_func(fid, "start");
941 me.start(fid);
942 me.finish_no_validate()
943 }
944
945 pub(crate) fn wasm_module_with_multi_value() -> Vec<u8> {
946 let me = ModEmitter::default_with_test_protocol();
947 let mut fe = me.func_with_arity_and_ret(Arity(0), Arity(2), 0);
948 fe.push(Symbol::try_from_small_str("pass1").unwrap());
949 fe.push(Symbol::try_from_small_str("pass2").unwrap());
950 fe.finish_and_export("test").finish()
951 }
952
953 pub(crate) fn wasm_module_large_elements(m: u32, n: u32) -> Vec<u8> {
955 let mut me = ModEmitter::from_configs(1, m);
956 let f0 = me.import_func("t", "_", Arity(0));
958 me.define_elem_funcs(vec![f0; n as usize].as_slice());
959 me.finish()
960 }
961
962 pub(crate) fn wasm_module_various_constexpr_in_elements(case: u32) -> Vec<u8> {
963 let mut me = ModEmitter::default_with_test_protocol();
964 let f0 = me.import_func("t", "_", Arity(0));
966
967 match case {
968 0 =>
969 {
971 me.define_active_elements(
972 None,
973 &ConstExpr::i64_const(0),
974 Elements::Functions(&[f0.0]),
975 )
976 }
977 1 => me.define_active_elements(
979 None,
980 &ConstExpr::f64_const(1.0),
981 Elements::Functions(&[f0.0]),
982 ),
983 2 => me.define_active_elements(
985 None,
986 &ConstExpr::v128_const(1),
987 Elements::Functions(&[f0.0]),
988 ),
989 3 => me.define_active_elements(
991 None,
992 &ConstExpr::ref_func(f0.0),
993 Elements::Functions(&[f0.0]),
994 ),
995 _ => panic!("not a valid option"),
996 }
997 me.finish_no_validate()
998 }
999
1000 pub(crate) fn wasm_module_large_globals(n: u32) -> Vec<u8> {
1001 let mut me = ModEmitter::default_with_test_protocol();
1002 for i in 0..n {
1003 me.define_global_i64(i as i64, true, None);
1004 }
1005 me.finish()
1006 }
1007
1008 pub(crate) fn wasm_module_various_constexr_in_global(case: u32) -> Vec<u8> {
1009 let mut me = ModEmitter::default_with_test_protocol();
1010 match case {
1011 0 =>
1012 {
1014 me.define_global(wasm_encoder::ValType::I32, true, &ConstExpr::i64_const(1))
1015 }
1016 1 =>
1017 {
1019 me.define_global(wasm_encoder::ValType::F32, true, &ConstExpr::f32_const(1.0))
1020 }
1021 2 =>
1022 {
1024 me.define_global(wasm_encoder::ValType::V128, true, &ConstExpr::v128_const(1))
1025 }
1026 3 =>
1027 {
1029 let fr = me.import_func("t", "_", Arity(0));
1030 me.define_global(
1031 wasm_encoder::ValType::Ref(RefType::FUNCREF),
1032 true,
1033 &ConstExpr::ref_func(fr.0),
1034 )
1035 }
1036 _ => panic!("not a valid option"),
1037 }
1038 me.finish_no_validate()
1039 }
1040
1041 pub(crate) fn wasm_module_various_constexr_in_data_segment(case: u32) -> Vec<u8> {
1042 let mut me = ModEmitter::default_with_test_protocol();
1043 let f0 = me.import_func("t", "_", Arity(0));
1045
1046 match case {
1047 0 =>
1048 {
1050 me.define_active_data(0, &ConstExpr::i64_const(0), vec![0; 8]);
1051 }
1052 1 => {
1054 me.define_active_data(0, &ConstExpr::f64_const(0.0), vec![0; 8]);
1055 }
1056 2 => {
1058 me.define_active_data(0, &ConstExpr::v128_const(0), vec![0; 8]);
1059 }
1060 3 => {
1062 me.define_active_data(0, &ConstExpr::ref_func(f0.0), vec![0; 8]);
1063 }
1064 _ => panic!("not a valid option"),
1065 }
1066 me.finish_no_validate()
1067 }
1068
1069 pub(crate) fn wasm_module_with_extern_ref() -> Vec<u8> {
1070 let mut me = ModEmitter::new();
1071 me.table(RefType::EXTERNREF, 2, None);
1072 me.add_test_protocol_version_meta();
1073 me.finish_no_validate()
1074 }
1075
1076 pub(crate) fn wasm_module_with_additional_tables(n: u32) -> Vec<u8> {
1077 let mut me = ModEmitter::default_with_test_protocol();
1078 for _i in 0..n {
1081 me.table(RefType::FUNCREF, 2, None);
1082 }
1083 me.finish_no_validate()
1085 }
1086
1087 pub(crate) fn wasm_module_with_many_func_types(n: u32) -> Vec<u8> {
1091 let mut me = ModEmitter::default_with_test_protocol();
1092 for _i in 0..n {
1093 me.add_fn_type_no_check(Arity(0), Arity(0));
1095 }
1096 me.finish()
1097 }
1098
1099 pub(crate) fn wasm_module_with_simd_add_i32x4() -> Vec<u8> {
1100 let me = ModEmitter::default_with_test_protocol();
1101 let mut fe = me.func(Arity(0), 0);
1102 fe.i32_const(32); fe.i32_const(0); fe.v128_load(0, 0);
1106 fe.i32_const(16); fe.v128_load(0, 0);
1108 fe.i32x4_add();
1109 fe.v128_store(0, 0);
1110 fe.push(Symbol::try_from_small_str("pass").unwrap());
1111 fe.finish_and_export("test").finish()
1112 }
1113
1114 pub(crate) fn wasm_module_calling_protocol_gated_host_fn(wasm_proto: u32) -> Vec<u8> {
1115 let mut me = ModEmitter::new();
1116 me.add_protocol_version_meta(wasm_proto);
1117 let f0 = me.import_func("t", "0", Arity(0));
1119 let mut fe = me.func(Arity(0), 0);
1121 fe.call_func(f0);
1122 fe.finish_and_export("test").finish()
1123 }
1124
1125 pub(crate) fn wasm_module_with_a_bit_of_everything(wasm_proto: u32) -> Vec<u8> {
1126 let mut me = ModEmitter::new();
1127 me.add_protocol_version_meta(wasm_proto);
1128 me.table(RefType::FUNCREF, 128, None);
1129 me.memory(1, None, false, false);
1130 me.global(wasm_encoder::ValType::I64, true, &ConstExpr::i64_const(42));
1131 me.export("memory", wasm_encoder::ExportKind::Memory, 0);
1132 let _f0 = me.import_func("t", "_", Arity(0));
1133 let mut fe = me.func(Arity(0), 0);
1134 fe.push(Operand::Const64(1));
1135 fe.push(Operand::Const64(2));
1136 fe.i64_add();
1137 fe.drop();
1138 fe.push(Symbol::try_from_small_str("pass").unwrap());
1139 let (mut me, fid) = fe.finish();
1140 me.export_func(fid, "test");
1141 me.define_elem_funcs(&[fid]);
1142 me.define_data_segment(0x1234, vec![0; 512]);
1143 me.finish()
1144 }
1145}
1146
1147#[allow(clippy::type_complexity)]
1148pub fn simple_account_sign_fn<'a>(
1149 host: &'a Host,
1150 kp: &'a SigningKey,
1151) -> Box<dyn Fn(&[u8]) -> Val + 'a> {
1152 use crate::builtin_contracts::testutils::sign_payload_for_ed25519;
1153 Box::new(|payload: &[u8]| -> Val { sign_payload_for_ed25519(host, kp, payload).into() })
1154}