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