use {
crate::{
scheduler::{OccurrenceRef, OccurrenceSource, WithdrawalReason},
sui,
},
serde::{Deserialize, Serialize},
};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TransactionReference {
digest: sui::types::Digest,
checkpoint: u64,
}
impl TransactionReference {
pub(crate) const fn new(digest: sui::types::Digest, checkpoint: u64) -> Self {
Self { digest, checkpoint }
}
pub const fn digest(&self) -> &sui::types::Digest {
&self.digest
}
pub const fn checkpoint(&self) -> u64 {
self.checkpoint
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ScheduledOccurrence {
reference: OccurrenceRef,
start_time_ms: u64,
deadline_ms: Option<u64>,
priority_fee_percentage: u64,
source: OccurrenceSource,
}
impl ScheduledOccurrence {
pub(crate) const fn new(
reference: OccurrenceRef,
start_time_ms: u64,
deadline_ms: Option<u64>,
priority_fee_percentage: u64,
source: OccurrenceSource,
) -> Self {
Self {
reference,
start_time_ms,
deadline_ms,
priority_fee_percentage,
source,
}
}
pub const fn reference(&self) -> OccurrenceRef {
self.reference
}
pub const fn start_time_ms(&self) -> u64 {
self.start_time_ms
}
pub const fn deadline_ms(&self) -> Option<u64> {
self.deadline_ms
}
pub const fn priority_fee_percentage(&self) -> u64 {
self.priority_fee_percentage
}
pub const fn source(&self) -> OccurrenceSource {
self.source
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct WithdrawnOccurrence {
reference: OccurrenceRef,
reason: WithdrawalReason,
}
impl WithdrawnOccurrence {
pub(crate) const fn new(reference: OccurrenceRef, reason: WithdrawalReason) -> Self {
Self { reference, reason }
}
pub const fn reference(&self) -> OccurrenceRef {
self.reference
}
pub const fn reason(&self) -> WithdrawalReason {
self.reason
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ScheduleDelta {
scheduled: Vec<ScheduledOccurrence>,
withdrawn: Vec<WithdrawnOccurrence>,
advertised: Option<OccurrenceRef>,
}
impl ScheduleDelta {
pub(crate) fn new(
scheduled: Vec<ScheduledOccurrence>,
withdrawn: Vec<WithdrawnOccurrence>,
advertised: Option<OccurrenceRef>,
) -> Self {
Self {
scheduled,
withdrawn,
advertised,
}
}
pub fn scheduled(&self) -> &[ScheduledOccurrence] {
&self.scheduled
}
pub fn withdrawn(&self) -> &[WithdrawnOccurrence] {
&self.withdrawn
}
pub const fn advertised(&self) -> Option<OccurrenceRef> {
self.advertised
}
pub fn is_empty(&self) -> bool {
self.scheduled.is_empty() && self.withdrawn.is_empty() && self.advertised.is_none()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TaskMutationReceipt {
transaction: TransactionReference,
task_id: sui::types::Address,
delta: ScheduleDelta,
}
impl TaskMutationReceipt {
pub(crate) const fn new(
transaction: TransactionReference,
task_id: sui::types::Address,
delta: ScheduleDelta,
) -> Self {
Self {
transaction,
task_id,
delta,
}
}
pub const fn transaction(&self) -> &TransactionReference {
&self.transaction
}
pub const fn task_id(&self) -> sui::types::Address {
self.task_id
}
pub const fn delta(&self) -> &ScheduleDelta {
&self.delta
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AbortReceipt {
transaction: TransactionReference,
occurrence: OccurrenceRef,
execution_id: sui::types::Address,
}
impl AbortReceipt {
pub(crate) const fn new(
transaction: TransactionReference,
occurrence: OccurrenceRef,
execution_id: sui::types::Address,
) -> Self {
Self {
transaction,
occurrence,
execution_id,
}
}
pub const fn transaction(&self) -> &TransactionReference {
&self.transaction
}
pub const fn occurrence(&self) -> OccurrenceRef {
self.occurrence
}
pub const fn execution_id(&self) -> sui::types::Address {
self.execution_id
}
}
#[cfg(test)]
mod tests {
use super::*;
fn address(value: &'static str) -> sui::types::Address {
sui::types::Address::from_static(value)
}
#[test]
fn mutation_receipts_preserve_transaction_and_schedule_changes() {
let task_id = address("0x20");
let reference = OccurrenceRef::new(task_id, 4);
let transaction = TransactionReference::new(sui::types::Digest::new([7; 32]), 12);
assert_eq!(transaction.digest(), &sui::types::Digest::new([7; 32]));
assert_eq!(transaction.checkpoint(), 12);
let scheduled = ScheduledOccurrence::new(
reference,
100,
Some(120),
30,
OccurrenceSource::Recurring { iteration: 2 },
);
assert_eq!(scheduled.reference(), reference);
assert_eq!(scheduled.start_time_ms(), 100);
assert_eq!(scheduled.deadline_ms(), Some(120));
assert_eq!(scheduled.priority_fee_percentage(), 30);
assert_eq!(
scheduled.source(),
OccurrenceSource::Recurring { iteration: 2 }
);
let withdrawn = WithdrawnOccurrence::new(reference, WithdrawalReason::RecurrenceReplaced);
assert_eq!(withdrawn.reference(), reference);
assert_eq!(withdrawn.reason(), WithdrawalReason::RecurrenceReplaced);
let delta = ScheduleDelta::new(
vec![scheduled.clone()],
vec![withdrawn.clone()],
Some(reference),
);
assert_eq!(delta.scheduled(), &[scheduled]);
assert_eq!(delta.withdrawn(), &[withdrawn]);
assert_eq!(delta.advertised(), Some(reference));
assert!(!delta.is_empty());
assert!(ScheduleDelta::default().is_empty());
let receipt = TaskMutationReceipt::new(transaction.clone(), task_id, delta.clone());
assert_eq!(receipt.transaction(), &transaction);
assert_eq!(receipt.task_id(), task_id);
assert_eq!(receipt.delta(), &delta);
}
#[test]
fn abort_receipt_identifies_the_occurrence_and_runtime_object() {
let transaction = TransactionReference::new(sui::types::Digest::new([8; 32]), 13);
let occurrence = OccurrenceRef::new(address("0x21"), 5);
let execution_id = address("0x22");
let receipt = AbortReceipt::new(transaction.clone(), occurrence, execution_id);
assert_eq!(receipt.transaction(), &transaction);
assert_eq!(receipt.occurrence(), occurrence);
assert_eq!(receipt.execution_id(), execution_id);
}
}