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, WriteXdr};
150 let iv = crate::meta::make_interface_version(proto, pre);
151 let entry = ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(iv);
152 let bytes = Vec::<u8>::new();
153 let mut w = Limited::new(bytes, Limits::none());
154 entry.write_xdr(&mut w).unwrap();
155 w.inner
156}
157
158impl Host {
159 pub const TEST_PRNG_SEED: &'static [u8; 32] = b"12345678901234567890123456789012";
160
161 pub fn set_test_prng(&self) {
162 self.set_base_prng_seed(*Self::TEST_PRNG_SEED).unwrap();
163 }
164
165 pub fn current_test_protocol() -> u32 {
166 use crate::meta::{get_ledger_protocol_version, INTERFACE_VERSION};
167 if let Ok(vers) = std::env::var("TEST_PROTOCOL") {
168 vers.parse().unwrap()
169 } else {
170 get_ledger_protocol_version(INTERFACE_VERSION)
171 }
172 }
173
174 pub fn set_test_ledger_info_with_current_test_protocol(&self) {
175 self.set_ledger_info(LedgerInfo {
176 protocol_version: Self::current_test_protocol(),
177 sequence_number: 0,
178 timestamp: 0,
179 network_id: [0; 32],
180 base_reserve: 0,
181 min_persistent_entry_ttl: 4096,
182 min_temp_entry_ttl: 16,
183 max_entry_ttl: 6_312_000,
184 })
185 .unwrap();
186 }
187
188 pub fn test_host() -> Self {
189 let host = Host::default();
190 host.set_test_ledger_info_with_current_test_protocol();
191 host
192 }
193
194 pub fn test_host_with_prng() -> Self {
195 let host = Self::test_host();
196 host.set_test_prng();
197 host
198 }
199
200 pub fn test_host_with_recording_footprint() -> Self {
201 let snapshot_source = Rc::<MockSnapshotSource>::new(MockSnapshotSource::new());
202 let storage = Storage::with_recording_footprint(snapshot_source);
203 let host = Host::with_storage_and_budget(storage, Budget::default());
204 host.set_test_ledger_info_with_current_test_protocol();
205 host.set_test_prng();
206 host
207 }
208
209 pub fn test_budget(self, cpu: u64, mem: u64) -> Self {
210 self.with_budget(|budget| {
211 budget.reset_limits(cpu, mem)?; budget.reset_models()?;
213 Ok(())
214 })
215 .unwrap();
216 self
217 }
218
219 pub fn enable_model(
220 self,
221 ty: ContractCostType,
222 const_cpu: u64,
223 lin_cpu: u64,
224 const_mem: u64,
225 lin_mem: u64,
226 ) -> Self {
227 self.with_budget(|budget| {
228 budget.override_model_with_unscaled_params(ty, const_cpu, lin_cpu, const_mem, lin_mem)
229 })
230 .unwrap();
231 self
232 }
233
234 pub fn test_scvec<T: AsScVal>(&self, vals: &[T]) -> Result<ScVec, HostError> {
235 let v: Vec<ScVal> = vals.iter().map(|x| x.as_scval()).collect();
236 self.map_err(v.try_into())
237 }
238
239 pub fn test_vec_obj<T: AsScVal>(&self, vals: &[T]) -> Result<VecObject, HostError> {
240 let v = self.test_scvec(vals)?;
241 Ok(self.to_host_val(&ScVal::Vec(Some(v)))?.try_into()?)
242 }
243
244 pub fn test_vec_val<T: AsScVal>(&self, vals: &[T]) -> Result<Val, HostError> {
245 let v = self.test_scvec(vals)?;
246 self.to_host_val(&ScVal::Vec(Some(v)))
247 }
248
249 pub fn test_bin_scobj(&self, vals: &[u8]) -> Result<ScVal, HostError> {
250 Ok(ScVal::Bytes(self.map_err(vals.to_vec().try_into())?))
251 }
252
253 pub fn test_bin_obj(&self, vals: &[u8]) -> Result<BytesObject, HostError> {
254 let scval: ScVal = self.test_bin_scobj(vals)?;
255 let val: Val = self.to_host_val(&scval)?;
256 Ok(val.try_into()?)
257 }
258
259 pub fn register_test_contract_wasm_from_source_account(
265 &self,
266 contract_wasm: &[u8],
267 account: AccountId,
268 salt: [u8; 32],
269 ) -> Result<AddressObject, HostError> {
270 let _span = tracy_span!("register_test_contract_wasm_from_source_account");
271 let prev_source_account = self.source_account_id()?;
274 let prev_auth_manager = self.snapshot_auth_manager()?;
276 self.switch_to_recording_auth(true)?;
277
278 let wasm_hash = self.upload_wasm(self.bytes_new_from_slice(contract_wasm)?)?;
279 self.set_source_account(account.clone())?;
280 let contract_address = self.create_contract(
281 self.add_host_object(ScAddress::Account(account.clone()))?,
282 wasm_hash,
283 self.bytes_new_from_slice(&salt)?,
284 )?;
285 if let Some(prev_account) = prev_source_account {
286 self.set_source_account(prev_account)?;
287 }
288 self.set_auth_manager(prev_auth_manager)?;
289 Ok(contract_address)
290 }
291
292 pub fn register_test_contract_wasm(&self, contract_wasm: &[u8]) -> AddressObject {
297 self.register_test_contract_wasm_from_source_account(
298 contract_wasm,
299 generate_account_id(self),
300 generate_bytes_array(self),
301 )
302 .unwrap()
303 }
304
305 pub fn new_recording_fuzz_host(
306 contract_wasms: &[&[u8]],
307 data_keys: &BTreeMap<ScVal, (StorageType, bool)>,
308 n_signers: usize,
309 ) -> (Host, Vec<AddressObject>, Vec<ed25519_dalek::SigningKey>) {
310 use crate::builtin_contracts::testutils::{
311 generate_signing_key, signing_key_to_account_id,
312 };
313
314 let host = Self::test_host_with_recording_footprint();
315 host.switch_to_recording_auth(false).unwrap();
316 host.with_budget(|budget| {
317 budget.reset_unlimited()?;
318 Ok(())
319 })
320 .unwrap();
321 let mut contract_addresses = Vec::new();
322 for contract_wasm in contract_wasms.iter() {
323 contract_addresses.push(host.register_test_contract_wasm(contract_wasm));
324 }
325 let ScAddress::Contract(contract_hash) =
326 host.scaddress_from_address(contract_addresses[0]).unwrap()
327 else {
328 panic!()
329 };
330
331 let test = SymbolSmall::try_from_str("test").unwrap();
332
333 host.with_test_contract_frame(contract_hash.clone(), test.into(), || {
335 for (k, (t, _)) in data_keys.iter() {
336 let v = host.to_host_val(k).unwrap();
337 host.put_contract_data(v, v, *t).unwrap();
338 }
339 Ok(Val::VOID.into())
340 })
341 .unwrap();
342
343 let signing_keys = (0..n_signers)
345 .map(|_| generate_signing_key(&host))
346 .collect();
347 for signing_key in &signing_keys {
348 create_account(
349 &host,
350 &signing_key_to_account_id(signing_key),
351 vec![(&signing_key, 1)],
352 100_000_000,
353 1,
354 [1, 0, 0, 0],
355 None,
356 None,
357 0,
358 )
359 }
360
361 (host, contract_addresses, signing_keys)
362 }
363
364 pub fn switch_fuzz_host_to_enforcing(
365 &self,
366 data_keys: &BTreeMap<ScVal, (StorageType, bool)>,
367 signing_keys: &[ed25519_dalek::SigningKey],
368 ) {
369 use crate::builtin_contracts::testutils::TestSigner;
370 use crate::xdr::{
371 HashIdPreimage, HashIdPreimageSorobanAuthorization, SorobanAddressCredentials,
372 SorobanAuthorizationEntry, SorobanCredentials,
373 };
374 self.with_budget(|budget| {
375 budget.reset_unlimited()?;
376 Ok(())
377 })
378 .unwrap();
379
380 self.with_mut_storage(|storage| {
384 storage.footprint.0 = MeteredOrdMap::from_exact_iter(
385 storage
386 .footprint
387 .0
388 .iter(self.budget_ref())
389 .unwrap()
390 .map(|(k, accesstype)| {
391 let mut accesstype = *accesstype;
392 if let LedgerKey::ContractData(k) = k.as_ref() {
393 if let Some((_, ro)) = data_keys.get(&k.key) {
394 if *ro {
395 accesstype = crate::storage::AccessType::ReadOnly;
396 } else {
397 accesstype = crate::storage::AccessType::ReadWrite;
398 }
399 }
400 }
401 (k.clone(), accesstype)
402 }),
403 self.budget_ref(),
404 )
405 .unwrap();
406
407 let mut map = BTreeMap::new();
411 for (k, v) in storage.map.iter(self.budget_ref()).unwrap() {
412 map.insert(k.clone(), v.clone());
413 }
414 for (k, _) in storage.footprint.0.iter(self.budget_ref()).unwrap() {
415 if !map.contains_key(k) {
416 map.insert(k.clone(), None);
417 }
418 }
419 for (k, v) in map.iter_mut() {
421 if let LedgerKey::ContractData(k) = k.as_ref() {
422 if let ScVal::LedgerKeyNonce(_) = &k.key {
423 *v = None;
424 }
425 }
426 }
427 storage.map = MeteredOrdMap::from_exact_iter(
428 map.iter().map(|(k, v)| (k.clone(), v.clone())),
429 self.budget_ref(),
430 )
431 .unwrap();
432 storage.mode = crate::storage::FootprintMode::Enforcing;
433 Ok(())
434 })
435 .unwrap();
436
437 let mut auth_entries = Vec::new();
439 let account_signers = signing_keys
440 .iter()
441 .map(TestSigner::account)
442 .collect::<Vec<_>>();
443 for payload in self.get_recorded_auth_payloads().unwrap().iter() {
444 for signer in account_signers.iter() {
445 let Some(address) = &payload.address else {
446 continue;
447 };
448 let Some(nonce) = payload.nonce else { continue };
449 if *address == ScAddress::Account(signer.account_id()) {
450 let address = address.clone();
451 let signature_expiration_ledger =
452 u32::from(self.get_ledger_sequence().unwrap()) + 10000;
453 let network_id = self
454 .with_ledger_info(|li: &LedgerInfo| Ok(li.network_id))
455 .unwrap()
456 .try_into()
457 .unwrap();
458 let signature_payload_preimage =
459 HashIdPreimage::SorobanAuthorization(HashIdPreimageSorobanAuthorization {
460 network_id,
461 invocation: payload.invocation.clone(),
462 nonce,
463 signature_expiration_ledger,
464 });
465 let signature_payload =
466 self.metered_hash_xdr(&signature_payload_preimage).unwrap();
467 let signature = signer.sign(&self, &signature_payload);
468 let credentials = SorobanCredentials::Address(SorobanAddressCredentials {
469 address: address.clone(),
470 nonce: nonce,
471 signature_expiration_ledger,
472 signature,
473 });
474 let entry = SorobanAuthorizationEntry {
475 credentials,
476 root_invocation: payload.invocation.clone(),
477 };
478 auth_entries.push(entry);
479 }
480 }
481 }
482 self.set_authorization_entries(auth_entries).unwrap();
483 }
484
485 #[cfg(all(test, feature = "testutils"))]
486 pub(crate) fn measured_call(
487 &self,
488 contract: AddressObject,
489 func: crate::Symbol,
490 args: VecObject,
491 ) -> Result<Val, HostError> {
492 use crate::{budget::AsBudget, host::TraceEvent};
493 use soroban_bench_utils::HostTracker;
494 use std::cell::RefCell;
495
496 let _span = tracy_span!("measured_call");
497 let budget = self.as_budget();
498 budget.reset_unlimited()?;
499 let ht = Rc::new(RefCell::new(HostTracker::new()));
500
501 if std::env::var("EXCLUDE_VM_INSTANTIATION").is_ok() {
502 let ht2 = ht.clone();
503 let budget2 = budget.clone();
504 self.set_trace_hook(Some(Rc::new(move |_, evt| {
505 if let TraceEvent::PushCtx(_) = evt {
506 budget2.reset_unlimited()?;
507 ht2.borrow_mut().start(None);
508 }
509 Ok(())
510 })))?;
511 } else {
512 ht.borrow_mut().start(None);
513 }
514 let val = self.call(contract, func, args);
515 self.set_trace_hook(None)?;
516
517 let (cpu_actual, mem_actual, time_nsecs) = Rc::into_inner(ht).unwrap().into_inner().stop();
518
519 let cpu_metered = budget
520 .get_cpu_insns_consumed()
521 .expect("unable to retrieve cpu consumed");
522 let mem_metered = budget
523 .get_mem_bytes_consumed()
524 .expect("unable to retrieve mem consumed");
525
526 let cpu_diff = (cpu_metered - cpu_actual) as i64;
527 let cpu_metered_diff_percent = 100 * cpu_diff / (cpu_metered as i64).max(1);
528 let mem_diff = (mem_metered - mem_actual) as i64;
529 let mem_metered_diff_percent = 100 * mem_diff / (mem_metered as i64).max(1);
530 let metered_insn_nsecs_ratio: f64 = (cpu_metered as f64) / (time_nsecs as f64).max(1.0);
531 let actual_insn_nsecs_ratio: f64 = (cpu_actual as f64) / (time_nsecs as f64).max(1.0);
532
533 println!();
534 println!(
535 "metered cpu insns: {}, actual cpu insns {}, diff: {} ({:.3}%)",
536 cpu_metered, cpu_actual, cpu_diff, cpu_metered_diff_percent
537 );
538 println!(
539 "metered mem bytes: {}, actual mem bytes {}, diff: {} ({:.3}%)",
540 mem_metered, mem_actual, mem_diff, mem_metered_diff_percent
541 );
542 println!("time_nsecs: {}", time_nsecs);
543 println!(
544 "metered cpu_insn/time_nsecs ratio: {:.3}",
545 metered_insn_nsecs_ratio
546 );
547 println!(
548 "actual cpu_insn/time_nsecs ratio: {:.3}",
549 actual_insn_nsecs_ratio
550 );
551 println!();
552
553 val
554 }
555}
556
557#[cfg(test)]
558pub(crate) mod wasm {
559 use crate::{Symbol, Tag, U32Val, Val};
560 use soroban_synth_wasm::{Arity, FuncRef, LocalRef, ModEmitter, Operand};
561 use wasm_encoder::{ConstExpr, Elements, RefType};
562
563 pub(crate) fn wasm_module_with_4n_insns(n: usize) -> Vec<u8> {
564 let mut fe = ModEmitter::default_with_test_protocol().func(Arity(1), 0);
565 let arg = fe.args[0];
566 fe.push(Operand::Const64(1));
567 for i in 0..n {
568 fe.push(arg.0);
569 fe.push(Operand::Const64(i as i64));
570 fe.i64_mul();
571 fe.i64_add();
572 }
573 fe.drop();
574 fe.push(Symbol::try_from_small_str("pass").unwrap());
575 fe.finish_and_export("test").finish()
576 }
577
578 pub(crate) fn wasm_module_with_n_funcs_no_export(n: usize) -> Vec<u8> {
579 let mut me = ModEmitter::default_with_test_protocol();
580 for _i in 0..n {
581 let mut fe = me.func(Arity(0), 0);
582 fe.push(Symbol::try_from_small_str("pass").unwrap());
583 me = fe.finish().0;
584 }
585 me.finish()
586 }
587
588 pub(crate) fn wasm_module_with_repeated_exporting_the_same_func(n: usize) -> Vec<u8> {
589 let me = ModEmitter::default_with_test_protocol();
590 let mut fe = me.func(Arity(0), 0);
591 fe.push(Symbol::try_from_small_str("pass").unwrap());
592 let (mut me, fid) = fe.finish();
593 for i in 0..n {
594 me.export_func(fid, format!("test{}", i).as_str());
595 }
596 me.finish_no_validate()
597 }
598
599 pub(crate) fn wasm_module_with_mem_grow(n_pages: usize) -> Vec<u8> {
600 let mut fe = ModEmitter::default_with_test_protocol().func(Arity(0), 0);
601 fe.push(Operand::Const32(n_pages as i32));
602 fe.memory_grow();
603 fe.drop();
604 fe.push(Symbol::try_from_small_str("pass").unwrap());
605 fe.finish_and_export("test").finish()
606 }
607
608 pub(crate) fn wasm_module_with_linear_memory_logging() -> Vec<u8> {
609 let mut me = ModEmitter::default_with_test_protocol();
610 let f0 = me.import_func("x", "_", Arity(4));
612 let mut fe = me.func(Arity(4), 0);
614 fe.push(Operand::Local(LocalRef(0)));
615 fe.push(Operand::Local(LocalRef(1)));
616 fe.push(Operand::Local(LocalRef(2)));
617 fe.push(Operand::Local(LocalRef(3)));
618 fe.call_func(f0);
619 fe.drop();
620 fe.push(Symbol::try_from_small_str("pass").unwrap());
621 fe.finish_and_export("test").finish()
622 }
623
624 pub(crate) fn wasm_module_with_unreachable() -> Vec<u8> {
625 let me = ModEmitter::default_with_test_protocol();
626 let mut fe = me.func(Arity(0), 0);
627 fe.trap();
628 fe.finish_and_export("test").finish()
629 }
630
631 pub(crate) fn wasm_module_with_indirect_call() -> Vec<u8> {
632 let mut me = ModEmitter::default_with_test_protocol();
633 let f0 = me.import_func("t", "_", Arity(0));
635 let mut fe = me.func(Arity(0), 0);
637 fe.push(Symbol::try_from_small_str("pass").unwrap());
638 let (me, f1) = fe.finish();
639 let mut fe = me.func(Arity(0), 0);
641 fe.push(Symbol::try_from_small_str("pass2").unwrap());
642 let (mut me, f2) = fe.finish();
643 me.define_elem_funcs(&[f0, f1, f2]);
645 let ty = me.get_fn_type(Arity(0), Arity(1));
646 fe = me.func(Arity(1), 0);
648 fe.local_get(LocalRef(0));
649 fe.i32_wrap_i64();
650 fe.call_func_indirect(ty);
652 fe.finish_and_export("test").finish()
653 }
654
655 pub(crate) fn wasm_module_with_div_by_zero() -> Vec<u8> {
656 let me = ModEmitter::default_with_test_protocol();
657 let mut fe = me.func(Arity(0), 0);
658 fe.push(Operand::Const64(123));
659 fe.push(Operand::Const64(0));
660 fe.i64_div_s();
661 fe.finish_and_export("test").finish()
662 }
663
664 pub(crate) fn wasm_module_with_integer_overflow() -> Vec<u8> {
665 let me = ModEmitter::default_with_test_protocol();
666 let mut fe = me.func(Arity(0), 0);
667 fe.push(Operand::Const64(i64::MIN));
668 fe.push(Operand::Const64(-1));
669 fe.i64_div_s();
673 fe.finish_and_export("test").finish()
674 }
675
676 pub(crate) fn wasm_module_with_user_specified_initial_size(
677 mem_pages: u32,
678 elem_count: u32,
679 ) -> Vec<u8> {
680 let me = ModEmitter::from_configs(mem_pages, elem_count);
681 let mut fe = me.func(Arity(0), 0);
683 fe.push(Symbol::try_from_small_str("pass").unwrap());
684 fe.finish_and_export("test").finish()
685 }
686
687 pub(crate) fn wasm_module_with_large_data_segment(
688 mem_pages: u32,
689 mem_offset: u32,
690 len: u32,
691 ) -> Vec<u8> {
692 let mut me = ModEmitter::from_configs(mem_pages, 128);
693 me.define_data_segment(mem_offset, vec![0; len as usize]);
694 let mut fe = me.func(Arity(0), 0);
696 fe.push(Symbol::try_from_small_str("pass").unwrap());
697 fe.finish_and_export("test").finish()
698 }
699
700 pub(crate) fn wasm_module_with_multiple_data_segments(
701 num_pages: u32,
702 num_sgmts: u32,
703 seg_size: u32,
704 ) -> Vec<u8> {
705 let mut me = ModEmitter::from_configs(num_pages, 128);
706 let mem_len = num_pages * 0x10_000;
707 let max_segments = (mem_len / seg_size.max(1)).max(1);
710 for _i in 0..num_sgmts % max_segments {
711 me.define_data_segment(0, vec![0; seg_size as usize]);
712 }
713 let mut fe = me.func(Arity(0), 0);
715 fe.push(Symbol::try_from_small_str("pass").unwrap());
716 fe.finish_and_export("test").finish()
717 }
718
719 pub(crate) fn wasm_module_with_large_bytes_from_linear_memory(
720 num_bytes: u32,
721 initial: u8,
722 ) -> Vec<u8> {
723 let num_pages = num_bytes / 0x10_000 + 1;
724 let mut me = ModEmitter::from_configs(num_pages, 128);
725 me.define_data_segment(0, vec![initial; num_bytes as usize]);
726 let mut fe = me.func(Arity(0), 0);
727 fe.bytes_new_from_linear_memory(U32Val::from(0), U32Val::from(num_bytes));
728 fe.finish_and_export("test").finish()
729 }
730
731 pub(crate) fn wasm_module_with_large_vector_from_linear_memory(
732 num_vals: u32,
733 initial: Val,
734 ) -> Vec<u8> {
735 let num_pages = num_vals * 8 / 0x10_000 + 1;
736 let mut me = ModEmitter::from_configs(num_pages, 128);
737 let bytes: Vec<u8> = (0..num_vals)
738 .into_iter()
739 .map(|_| initial.get_payload().to_le_bytes())
740 .flat_map(|a| a.into_iter())
741 .collect();
742 me.define_data_segment(0, bytes);
743 let mut fe = me.func(Arity(0), 0);
744 fe.vec_new_from_linear_memory(U32Val::from(0), U32Val::from(num_vals));
745 fe.finish_and_export("test").finish()
746 }
747
748 pub(crate) fn wasm_module_with_large_map_from_linear_memory(
749 num_vals: u32,
750 initial: Val,
751 ) -> Vec<u8> {
752 let num_pages = (num_vals * 8) * 3 / 0x10_000 + 1;
754 let mut me = ModEmitter::from_configs(num_pages, 128);
755
756 let key_bytes: Vec<u8> = (0..num_vals)
757 .into_iter()
758 .map(|i| format!("{:0>width$}", i, width = 8))
759 .flat_map(|s| s.into_bytes().into_iter())
760 .collect();
761
762 let val_bytes: Vec<u8> = (0..num_vals)
763 .into_iter()
764 .map(|_| initial.get_payload().to_le_bytes())
765 .flat_map(|a| a.into_iter())
766 .collect();
767
768 let slices: Vec<u8> = (0..num_vals)
769 .into_iter()
770 .map(|ptr| {
771 let slice = 8_u64 << 32 | (ptr * 8) as u64;
772 slice.to_le_bytes()
773 })
774 .flat_map(|s| s.into_iter())
775 .collect();
776
777 let bytes: Vec<u8> = key_bytes
778 .into_iter()
779 .chain(val_bytes.into_iter())
780 .chain(slices.into_iter())
781 .collect();
782
783 me.define_data_segment(0, bytes);
784 let mut fe = me.func(Arity(0), 0);
785
786 let vals_pos = U32Val::from(num_vals * 8);
787 let keys_pos = U32Val::from(num_vals * 16);
788 fe.map_new_from_linear_memory(keys_pos, vals_pos, U32Val::from(num_vals));
789
790 fe.finish_and_export("test").finish()
791 }
792
793 pub(crate) fn wasm_module_with_data_count(
794 num_sgmts: u32,
795 seg_size: u32,
796 data_count: u32,
797 ) -> Vec<u8> {
798 let pages = num_sgmts * seg_size / 0x10_000 + 1;
801 let mut me = ModEmitter::from_configs(pages, 128);
802 for i in 0..num_sgmts {
803 me.define_data_segment(i * seg_size, vec![7; seg_size as usize]);
804 }
805 me.data_count(data_count);
808 me.finish_no_validate()
809 }
810
811 pub fn post_mvp_wasm_module() -> Vec<u8> {
814 let mut me = ModEmitter::default_with_test_protocol();
815
816 me.define_global_i64(-100, true, Some("global"));
818
819 let mut fe = me.func(Arity(0), 0);
820 fe.i64_const(0x0000_0000_ffff_abcd_u64 as i64);
821
822 fe.i64_extend32s();
824
825 fe.i64_const(8);
827 fe.i64_shl();
828 fe.i64_const(Tag::I64Small as i64);
829 fe.i64_or();
830
831 fe.finish_and_export("test").finish()
832 }
833
834 pub fn empty_wasm_module() -> Vec<u8> {
835 ModEmitter::new().finish()
836 }
837
838 pub fn wasm_module_with_custom_section(name: &str, data: &[u8]) -> Vec<u8> {
839 let mut me = ModEmitter::new();
840 me.custom_section(name, data);
841 me.finish()
842 }
843
844 pub fn wasm_module_with_floating_point_ops() -> Vec<u8> {
845 let me = ModEmitter::default_with_test_protocol();
846 let mut fe = me.func(Arity(0), 0);
847 fe.f64_const(1.1f64);
848 fe.f64_const(2.2f64);
849 fe.f64_add();
850 fe.drop();
851 fe.push(Symbol::try_from_small_str("pass").unwrap());
852 fe.finish_and_export("test").finish()
853 }
854
855 pub fn wasm_module_with_multiple_memories() -> Vec<u8> {
856 let mut me = ModEmitter::new();
857 me.memory(1, None, false, false);
858 me.memory(1, None, false, false);
859 me.finish()
860 }
861
862 pub fn wasm_module_lying_about_import_function_type() -> Vec<u8> {
863 let mut me = ModEmitter::default_with_test_protocol();
864 me.import_func("t", "_", Arity(1));
867 me.finish()
868 }
869
870 pub fn wasm_module_importing_nonexistent_function() -> Vec<u8> {
871 let mut me = ModEmitter::default_with_test_protocol();
872 me.import_func("t", "z", Arity(1));
873 me.finish()
874 }
875
876 pub fn wasm_module_with_duplicate_function_import(n: u32) -> Vec<u8> {
877 let mut me = ModEmitter::default_with_test_protocol();
878 for _ in 0..n {
879 me.import_func_no_check("t", "_", Arity(0));
880 }
881 me.finish()
882 }
883
884 pub fn wasm_module_with_nonexistent_function_export() -> Vec<u8> {
885 let mut me = ModEmitter::default_with_test_protocol();
886 me.import_func("t", "_", Arity(0));
887 let mut fe = me.func(Arity(0), 0);
888 fe.push(Symbol::try_from_small_str("pass").unwrap());
889 let (mut me, fid) = fe.finish();
890 me.export_func(fid, "test");
892 me.export_func(FuncRef(0), "test0");
894 me.export_func(FuncRef(100), "test100");
896 me.finish_no_validate()
897 }
898
899 pub(crate) fn wasm_module_with_nonexistent_func_element() -> Vec<u8> {
900 let mut me = ModEmitter::default_with_test_protocol();
901 let f0 = me.import_func("t", "_", Arity(0));
903 let mut fe = me.func(Arity(0), 0);
905 fe.push(Symbol::try_from_small_str("pass").unwrap());
906 let (me, f1) = fe.finish();
907 let mut fe = me.func(Arity(0), 0);
909 fe.push(Symbol::try_from_small_str("pass2").unwrap());
910 let (mut me, f2) = fe.finish();
911 me.define_elem_funcs(&[f0, f1, f2, FuncRef(100)]);
913 me.finish_no_validate()
914 }
915
916 pub(crate) fn wasm_module_with_start_function() -> Vec<u8> {
917 let me = ModEmitter::default_with_test_protocol();
918 let fe = me.func_with_arity_and_ret(Arity(0), Arity(0), 0);
919 let (mut me, fid) = fe.finish();
920 me.export_func(fid.clone(), "start");
921 me.start(fid);
922 me.finish_no_validate()
923 }
924
925 pub(crate) fn wasm_module_with_multi_value() -> Vec<u8> {
926 let me = ModEmitter::default_with_test_protocol();
927 let mut fe = me.func_with_arity_and_ret(Arity(0), Arity(2), 0);
928 fe.push(Symbol::try_from_small_str("pass1").unwrap());
929 fe.push(Symbol::try_from_small_str("pass2").unwrap());
930 fe.finish_and_export("test").finish()
931 }
932
933 pub(crate) fn wasm_module_large_elements(m: u32, n: u32) -> Vec<u8> {
935 let mut me = ModEmitter::from_configs(1, m);
936 let f0 = me.import_func("t", "_", Arity(0));
938 me.define_elem_funcs(vec![f0; n as usize].as_slice());
939 me.finish()
940 }
941
942 pub(crate) fn wasm_module_various_constexpr_in_elements(case: u32) -> Vec<u8> {
943 let mut me = ModEmitter::default_with_test_protocol();
944 let f0 = me.import_func("t", "_", Arity(0));
946
947 match case {
948 0 =>
949 {
951 me.define_active_elements(
952 None,
953 &ConstExpr::i64_const(0),
954 Elements::Functions(&[f0.0]),
955 )
956 }
957 1 => me.define_active_elements(
959 None,
960 &ConstExpr::f64_const(1.0),
961 Elements::Functions(&[f0.0]),
962 ),
963 2 => me.define_active_elements(
965 None,
966 &ConstExpr::v128_const(1),
967 Elements::Functions(&[f0.0]),
968 ),
969 3 => me.define_active_elements(
971 None,
972 &ConstExpr::ref_func(f0.0),
973 Elements::Functions(&[f0.0]),
974 ),
975 _ => panic!("not a valid option"),
976 }
977 me.finish_no_validate()
978 }
979
980 pub(crate) fn wasm_module_large_globals(n: u32) -> Vec<u8> {
981 let mut me = ModEmitter::default_with_test_protocol();
982 for i in 0..n {
983 me.define_global_i64(i as i64, true, None);
984 }
985 me.finish()
986 }
987
988 pub(crate) fn wasm_module_various_constexr_in_global(case: u32) -> Vec<u8> {
989 let mut me = ModEmitter::default_with_test_protocol();
990 match case {
991 0 =>
992 {
994 me.define_global(wasm_encoder::ValType::I32, true, &ConstExpr::i64_const(1))
995 }
996 1 =>
997 {
999 me.define_global(wasm_encoder::ValType::F32, true, &ConstExpr::f32_const(1.0))
1000 }
1001 2 =>
1002 {
1004 me.define_global(wasm_encoder::ValType::V128, true, &ConstExpr::v128_const(1))
1005 }
1006 3 =>
1007 {
1009 let fr = me.import_func("t", "_", Arity(0));
1010 me.define_global(
1011 wasm_encoder::ValType::Ref(RefType::FUNCREF),
1012 true,
1013 &ConstExpr::ref_func(fr.0),
1014 )
1015 }
1016 _ => panic!("not a valid option"),
1017 }
1018 me.finish_no_validate()
1019 }
1020
1021 pub(crate) fn wasm_module_various_constexr_in_data_segment(case: u32) -> Vec<u8> {
1022 let mut me = ModEmitter::default_with_test_protocol();
1023 let f0 = me.import_func("t", "_", Arity(0));
1025
1026 match case {
1027 0 =>
1028 {
1030 me.define_active_data(0, &ConstExpr::i64_const(0), vec![0; 8]);
1031 }
1032 1 => {
1034 me.define_active_data(0, &ConstExpr::f64_const(0.0), vec![0; 8]);
1035 }
1036 2 => {
1038 me.define_active_data(0, &ConstExpr::v128_const(0), vec![0; 8]);
1039 }
1040 3 => {
1042 me.define_active_data(0, &ConstExpr::ref_func(f0.0), vec![0; 8]);
1043 }
1044 _ => panic!("not a valid option"),
1045 }
1046 me.finish_no_validate()
1047 }
1048
1049 pub(crate) fn wasm_module_with_extern_ref() -> Vec<u8> {
1050 let mut me = ModEmitter::new();
1051 me.table(RefType::EXTERNREF, 2, None);
1052 me.add_test_protocol_version_meta();
1053 me.finish_no_validate()
1054 }
1055
1056 pub(crate) fn wasm_module_with_additional_tables(n: u32) -> Vec<u8> {
1057 let mut me = ModEmitter::default_with_test_protocol();
1058 for _i in 0..n {
1061 me.table(RefType::FUNCREF, 2, None);
1062 }
1063 me.finish_no_validate()
1065 }
1066
1067 pub(crate) fn wasm_module_with_many_func_types(n: u32) -> Vec<u8> {
1071 let mut me = ModEmitter::default_with_test_protocol();
1072 for _i in 0..n {
1073 me.add_fn_type_no_check(Arity(0), Arity(0));
1075 }
1076 me.finish()
1077 }
1078
1079 pub(crate) fn wasm_module_with_simd_add_i32x4() -> Vec<u8> {
1080 let me = ModEmitter::default_with_test_protocol();
1081 let mut fe = me.func(Arity(0), 0);
1082 fe.i32_const(32); fe.i32_const(0); fe.v128_load(0, 0);
1086 fe.i32_const(16); fe.v128_load(0, 0);
1088 fe.i32x4_add();
1089 fe.v128_store(0, 0);
1090 fe.push(Symbol::try_from_small_str("pass").unwrap());
1091 fe.finish_and_export("test").finish()
1092 }
1093
1094 pub(crate) fn wasm_module_calling_protocol_gated_host_fn(wasm_proto: u32) -> Vec<u8> {
1095 let mut me = ModEmitter::new();
1096 me.add_protocol_version_meta(wasm_proto);
1097 let f0 = me.import_func("t", "0", Arity(0));
1099 let mut fe = me.func(Arity(0), 0);
1101 fe.call_func(f0);
1102 fe.finish_and_export("test").finish()
1103 }
1104
1105 pub(crate) fn wasm_module_with_a_bit_of_everything(wasm_proto: u32) -> Vec<u8> {
1106 let mut me = ModEmitter::new();
1107 me.add_protocol_version_meta(wasm_proto);
1108 me.table(RefType::FUNCREF, 128, None);
1109 me.memory(1, None, false, false);
1110 me.global(wasm_encoder::ValType::I64, true, &ConstExpr::i64_const(42));
1111 me.export("memory", wasm_encoder::ExportKind::Memory, 0);
1112 let _f0 = me.import_func("t", "_", Arity(0));
1113 let mut fe = me.func(Arity(0), 0);
1114 fe.push(Operand::Const64(1));
1115 fe.push(Operand::Const64(2));
1116 fe.i64_add();
1117 fe.drop();
1118 fe.push(Symbol::try_from_small_str("pass").unwrap());
1119 let (mut me, fid) = fe.finish();
1120 me.export_func(fid, "test");
1121 me.define_elem_funcs(&[fid]);
1122 me.define_data_segment(0x1234, vec![0; 512]);
1123 me.finish()
1124 }
1125}
1126
1127#[allow(clippy::type_complexity)]
1128pub fn simple_account_sign_fn<'a>(
1129 host: &'a Host,
1130 kp: &'a SigningKey,
1131) -> Box<dyn Fn(&[u8]) -> Val + 'a> {
1132 use crate::builtin_contracts::testutils::sign_payload_for_ed25519;
1133 Box::new(|payload: &[u8]| -> Val { sign_payload_for_ed25519(host, kp, payload).into() })
1134}