use algonaut_model::algod::{
SimulateRequest, SimulateRequestTransactionGroup, SimulateTraceConfig,
SimulateTransactionResponse,
};
#[derive(Debug, Clone)]
pub struct SimulateResponse {
inner: SimulateTransactionResponse,
}
impl SimulateResponse {
pub(crate) fn new(inner: SimulateTransactionResponse) -> Self {
Self { inner }
}
pub fn would_succeed(&self) -> bool {
self.inner.would_succeed
}
pub fn last_round(&self) -> u64 {
self.inner.last_round
}
pub fn failure_message(&self, index: usize) -> Option<&str> {
self.inner
.txn_groups
.get(index)
.and_then(|group| group.failure_message.as_deref())
}
pub fn extra_opcode_budget(&self) -> Option<u64> {
self.inner
.eval_overrides
.as_deref()
.and_then(|overrides| overrides.extra_opcode_budget)
}
}
#[derive(Debug, Clone, Default)]
pub struct SimulateRequestBuilder {
inner: SimulateRequest,
}
impl SimulateRequestBuilder {
pub fn new(txn_groups: Vec<SimulateRequestTransactionGroup>) -> Self {
Self {
inner: SimulateRequest::new(txn_groups),
}
}
pub fn allow_more_logging(mut self, on: bool) -> Self {
self.inner.allow_more_logging = Some(on);
self
}
pub fn allow_empty_signatures(mut self, on: bool) -> Self {
self.inner.allow_empty_signatures = Some(on);
self
}
pub fn allow_unnamed_resources(mut self, on: bool) -> Self {
self.inner.allow_unnamed_resources = Some(on);
self
}
pub fn extra_opcode_budget(mut self, extra: u64) -> Self {
self.inner.extra_opcode_budget = Some(extra);
self
}
pub fn round(mut self, round: u64) -> Self {
self.inner.round = Some(round);
self
}
pub fn fix_signers(mut self, on: bool) -> Self {
self.inner.fix_signers = Some(on);
self
}
pub fn with_exec_trace<F>(mut self, configure: F) -> Self
where
F: FnOnce(SimulateTraceConfigBuilder) -> SimulateTraceConfigBuilder,
{
let cfg = configure(SimulateTraceConfigBuilder::new()).build();
self.inner.exec_trace_config = Some(Box::new(cfg));
self
}
pub fn build(self) -> SimulateRequest {
self.inner
}
}
#[derive(Debug, Clone, Default)]
pub struct SimulateTraceConfigBuilder {
inner: SimulateTraceConfig,
}
impl SimulateTraceConfigBuilder {
pub fn new() -> Self {
Self {
inner: SimulateTraceConfig {
enable: Some(true),
..Default::default()
},
}
}
pub fn enable(mut self, on: bool) -> Self {
self.inner.enable = Some(on);
self
}
pub fn stack(mut self) -> Self {
self.inner.stack_change = Some(true);
self
}
pub fn scratch(mut self) -> Self {
self.inner.scratch_change = Some(true);
self
}
pub fn state(mut self) -> Self {
self.inner.state_change = Some(true);
self
}
pub fn build(self) -> SimulateTraceConfig {
self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_sets_power_packs() {
let req = SimulateRequestBuilder::new(vec![SimulateRequestTransactionGroup::new(vec![])])
.allow_more_logging(true)
.extra_opcode_budget(2_000)
.allow_unnamed_resources(true)
.with_exec_trace(|t| t.stack().scratch().state())
.build();
assert_eq!(req.allow_more_logging, Some(true));
assert_eq!(req.extra_opcode_budget, Some(2_000));
assert_eq!(req.allow_unnamed_resources, Some(true));
let trace = req.exec_trace_config.as_deref().unwrap();
assert_eq!(trace.enable, Some(true));
assert_eq!(trace.stack_change, Some(true));
assert_eq!(trace.scratch_change, Some(true));
assert_eq!(trace.state_change, Some(true));
}
#[test]
fn default_request_omits_power_pack_fields_on_wire() {
let req = SimulateRequestBuilder::new(vec![]).build();
let json = serde_json::to_string(&req).unwrap();
assert!(!json.contains("allow-more-logging"));
assert!(!json.contains("extra-opcode-budget"));
assert!(!json.contains("exec-trace-config"));
}
}