///|
fn add_finding(
findings : Array[AuditFinding],
receipt_index : Int,
code : AuditIssueCode,
message : String,
) -> Unit {
findings.push({ receipt_index, code, message, })
}
///|
pub fn audit_receipts(
permit : Permit,
receipts : Array[Receipt],
) -> AuditReport {
let replay = runtime(permit)
let findings : Array[AuditFinding] = []
for index, supplied in receipts {
let position = index + 1
if supplied.sequence != position {
add_finding(
findings,
position,
AuditIssueCode::SequenceMismatch,
"receipt sequence does not match its stream position",
)
}
if supplied.permit_id != permit.id {
add_finding(
findings,
position,
AuditIssueCode::PermitMismatch,
"receipt is bound to a different permit identifier",
)
}
try {
let expected = replay.check(
supplied.invocation_id,
supplied.requested,
supplied.logical_time,
byte_cost=supplied.byte_cost,
)
if expected != supplied {
add_finding(
findings,
position,
AuditIssueCode::ReplayMismatch,
"receipt does not match deterministic replay",
)
}
} catch {
_ =>
add_finding(
findings,
position,
AuditIssueCode::InvalidReceipt,
"receipt contains inputs rejected by the runtime",
)
}
}
{ checked: receipts.length(), findings, }
}
///|
pub fn AuditReport::passed(self : AuditReport) -> Bool {
self.findings.is_empty()
}
///|
pub fn AuditReport::checked(self : AuditReport) -> Int {
self.checked
}
///|
pub fn AuditReport::findings(self : AuditReport) -> Array[AuditFinding] {
self.findings.copy()
}