Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
- Fixed an issue where `event.committed` was always equal to `true` in the block replay RPC endpoint
- Added `result_hex` and `post_condition_aborted` to the block replay RPC endpoint
- Added `--epoch <epoch_number>` flag to `clarity-cli` commands to specify the epoch context for evaluation.
- Added the `events` array to readonly endpoints output.

### Fixed

Expand Down
40 changes: 40 additions & 0 deletions clarity/src/vm/clarity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,46 @@ pub trait ClarityConnection {
(result, db)
})
}

#[allow(clippy::too_many_arguments)]
fn with_readonly_clarity_env_and_fill_events<F, R>(
&mut self,
mainnet: bool,
chain_id: u32,
sender: PrincipalData,
sponsor: Option<PrincipalData>,
cost_track: LimitedCostTracker,
events: &mut Vec<StacksTransactionEvent>,
to_do: F,
) -> Result<R, VmExecutionError>
where
F: FnOnce(&mut Environment) -> Result<R, VmExecutionError>,
{
let epoch_id = self.get_epoch();
let clarity_version = ClarityVersion::default_for_epoch(epoch_id);
self.with_clarity_db_readonly_owned(|clarity_db| {
let initial_context =
ContractContext::new(QualifiedContractIdentifier::transient(), clarity_version);
let mut vm_env = OwnedEnvironment::new_cost_limited(
mainnet, chain_id, clarity_db, cost_track, epoch_id,
);
let result = vm_env
.execute_in_env(sender, sponsor, Some(initial_context), to_do)
.map(|(result, _, transaction_events)| {
events.extend(transaction_events);
result
});
// this expect is allowed, if the database has escaped this context, then it is no longer sane
// and we must crash
#[allow(clippy::expect_used)]
let (db, _) = {
vm_env
.destruct()
.expect("Failed to recover database reference after executing transaction")
};
(result, db)
})
}
}

pub trait TransactionConnection: ClarityConnection {
Expand Down
15 changes: 14 additions & 1 deletion clarity/src/vm/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ pub struct GlobalContext<'a, 'hooks> {
pub chain_id: u32,
pub eval_hooks: Option<Vec<&'hooks mut dyn EvalHook>>,
pub execution_time_tracker: ExecutionTimeTracker,
/// avoid events to be cleared too early while in read only mode
pub keep_event_batches: bool,
}

#[derive(Serialize, Deserialize, Clone)]
Expand Down Expand Up @@ -1261,7 +1263,17 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> {
};

if make_read_only {
let mut event_batches_clone = None;
if self.global_context.keep_event_batches {
event_batches_clone = Some(self.global_context.event_batches.clone());
}

self.global_context.roll_back()?;

if let Some(event_batches_clone) = event_batches_clone {
self.global_context.event_batches = event_batches_clone
}

result
} else {
self.global_context.handle_tx_result(result, allow_private)
Expand Down Expand Up @@ -1624,6 +1636,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> {
chain_id,
eval_hooks: None,
execution_time_tracker: ExecutionTimeTracker::NoTracking,
keep_event_batches: false,
}
}

Expand Down Expand Up @@ -1801,7 +1814,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> {
let out_batch = match self.event_batches.last_mut() {
Some(tail_back) => {
tail_back.events.append(&mut event_batch.events);
None
Some(tail_back.clone())
}
None => Some(event_batch),
};
Expand Down
15 changes: 15 additions & 0 deletions docs/rpc/components/schemas/read-only-function-result.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,18 @@ oneOf:
cause:
type: string
description: A string representing the cause of the error.
events:
type: array
description: Contract events generated by the call
items:
type: object
properties:
sender:
type: string
description: The contract address generating the event.
key:
type: string
description: Who generated the event (generally "print").
value:
type: string
description: Hex-encoded Clarity value of the event.
Loading