#![cfg(any(test, feature = "testutils"))]
#![cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
pub mod arbitrary;
mod sign;
pub use sign::ed25519;
mod mock_auth;
pub use mock_auth::{
AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthContract, MockAuthInvoke,
};
pub mod storage;
use crate::{xdr, Env, Val, Vec};
use soroban_ledger_snapshot::LedgerSnapshot;
#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Snapshot {
pub generators: Generators,
pub auth: AuthSnapshot,
pub ledger: LedgerSnapshot,
pub events: EventsSnapshot,
}
impl Snapshot {
pub fn read(r: impl std::io::Read) -> Result<Snapshot, std::io::Error> {
Ok(serde_json::from_reader::<_, Snapshot>(r)?)
}
pub fn read_file(p: impl AsRef<std::path::Path>) -> Result<Snapshot, std::io::Error> {
Self::read(std::fs::File::open(p)?)
}
pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> {
Ok(serde_json::to_writer_pretty(w, self)?)
}
pub fn write_file(&self, p: impl AsRef<std::path::Path>) -> Result<(), std::io::Error> {
let p = p.as_ref();
if let Some(dir) = p.parent() {
if !dir.exists() {
std::fs::create_dir_all(dir)?;
}
}
self.write(std::fs::File::create(p)?)
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct EventsSnapshot(pub std::vec::Vec<EventSnapshot>);
impl EventsSnapshot {
pub fn read(r: impl std::io::Read) -> Result<EventsSnapshot, std::io::Error> {
Ok(serde_json::from_reader::<_, EventsSnapshot>(r)?)
}
pub fn read_file(p: impl AsRef<std::path::Path>) -> Result<EventsSnapshot, std::io::Error> {
Self::read(std::fs::File::open(p)?)
}
pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> {
Ok(serde_json::to_writer_pretty(w, self)?)
}
pub fn write_file(&self, p: impl AsRef<std::path::Path>) -> Result<(), std::io::Error> {
let p = p.as_ref();
if let Some(dir) = p.parent() {
if !dir.exists() {
std::fs::create_dir_all(dir)?;
}
}
self.write(std::fs::File::create(p)?)
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct EventSnapshot {
pub event: xdr::ContractEvent,
pub failed_call: bool,
}
impl From<crate::env::internal::events::HostEvent> for EventSnapshot {
fn from(v: crate::env::internal::events::HostEvent) -> Self {
Self {
event: v.event,
failed_call: v.failed_call,
}
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AuthSnapshot(
pub std::vec::Vec<std::vec::Vec<(xdr::ScAddress, xdr::SorobanAuthorizedInvocation)>>,
);
impl AuthSnapshot {
pub fn read(r: impl std::io::Read) -> Result<AuthSnapshot, std::io::Error> {
Ok(serde_json::from_reader::<_, AuthSnapshot>(r)?)
}
pub fn read_file(p: impl AsRef<std::path::Path>) -> Result<AuthSnapshot, std::io::Error> {
Self::read(std::fs::File::open(p)?)
}
pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> {
Ok(serde_json::to_writer_pretty(w, self)?)
}
pub fn write_file(&self, p: impl AsRef<std::path::Path>) -> Result<(), std::io::Error> {
let p = p.as_ref();
if let Some(dir) = p.parent() {
if !dir.exists() {
std::fs::create_dir_all(dir)?;
}
}
self.write(std::fs::File::create(p)?)
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Generators {
address: u64,
nonce: u64,
}
impl Default for Generators {
fn default() -> Generators {
Generators {
address: 0,
nonce: 0,
}
}
}
impl Generators {
pub fn read(r: impl std::io::Read) -> Result<Generators, std::io::Error> {
Ok(serde_json::from_reader::<_, Generators>(r)?)
}
pub fn read_file(p: impl AsRef<std::path::Path>) -> Result<Generators, std::io::Error> {
Self::read(std::fs::File::open(p)?)
}
pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> {
Ok(serde_json::to_writer_pretty(w, self)?)
}
pub fn write_file(&self, p: impl AsRef<std::path::Path>) -> Result<(), std::io::Error> {
let p = p.as_ref();
if let Some(dir) = p.parent() {
if !dir.exists() {
std::fs::create_dir_all(dir)?;
}
}
self.write(std::fs::File::create(p)?)
}
}
impl Generators {
pub fn address(&mut self) -> [u8; 32] {
self.address = self.address.checked_add(1).unwrap();
let b: [u8; 8] = self.address.to_be_bytes();
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b[0], b[1],
b[2], b[3], b[4], b[5], b[6], b[7],
]
}
pub fn nonce(&mut self) -> i64 {
self.nonce = self.nonce.checked_add(1).unwrap();
self.nonce as i64
}
}
#[doc(hidden)]
pub trait ContractFunctionSet {
fn call(&self, func: &str, env: Env, args: &[Val]) -> Option<Val>;
}
#[doc(inline)]
pub use crate::env::internal::LedgerInfo;
pub trait Ledger {
fn set(&self, l: LedgerInfo);
fn get(&self) -> LedgerInfo;
fn with_mut<F>(&self, f: F)
where
F: FnMut(&mut LedgerInfo);
}
pub mod budget {
use core::fmt::{Debug, Display};
#[doc(inline)]
use crate::env::internal::budget::CostTracker;
#[doc(inline)]
pub use crate::xdr::ContractCostType;
pub struct Budget(pub(crate) crate::env::internal::budget::Budget);
impl Display for Budget {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{}", self.0)
}
}
impl Debug for Budget {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{:?}", self.0)
}
}
impl Budget {
pub(crate) fn new(b: crate::env::internal::budget::Budget) -> Self {
Self(b)
}
pub fn reset_default(&mut self) {
self.0.reset_default().unwrap();
}
pub fn reset_unlimited(&mut self) {
self.0.reset_unlimited().unwrap();
}
pub fn reset_limits(&mut self, cpu: u64, mem: u64) {
self.0.reset_limits(cpu, mem).unwrap();
}
pub fn reset_tracker(&mut self) {
self.0.reset_tracker().unwrap();
}
pub fn cpu_instruction_cost(&self) -> u64 {
self.0.get_cpu_insns_consumed().unwrap()
}
pub fn memory_bytes_cost(&self) -> u64 {
self.0.get_mem_bytes_consumed().unwrap()
}
pub fn tracker(&self, cost_type: ContractCostType) -> CostTracker {
self.0.get_tracker(cost_type).unwrap()
}
pub fn print(&self) {
println!("{}", self.0);
}
}
}
pub trait Events {
fn all(&self) -> Vec<(crate::Address, Vec<Val>, Val)>;
}
pub trait Logs {
fn all(&self) -> std::vec::Vec<String>;
fn print(&self);
}
pub trait BytesN<const N: usize> {
fn random(env: &Env) -> crate::BytesN<N>;
}
pub(crate) fn random<const N: usize>() -> [u8; N] {
use rand::RngCore;
let mut arr = [0u8; N];
rand::thread_rng().fill_bytes(&mut arr);
arr
}
pub trait Address {
fn generate(env: &Env) -> crate::Address;
}