-
Notifications
You must be signed in to change notification settings - Fork 5
feat: add correct records functionality #288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
37abfa9
79e0d72
068328a
a97dc90
45a5944
7972197
97c779a
3b1b260
308aedb
1ab34c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,7 @@ use audit_trails::{ | |
| record::{Self, Record, InitialRecord}, | ||
| record_tags::{Self, RoleTags, TagRegistry} | ||
| }; | ||
| use iota::{clock::{Self, Clock}, event, linked_table::{Self, LinkedTable}, vec_set::VecSet}; | ||
| use iota::{clock::{Self, Clock}, event, linked_table::{Self, LinkedTable}, vec_set::{Self, VecSet}}; | ||
| use std::string::String; | ||
| use tf_components::{capability::Capability, role_map::{Self, RoleMap}, timelock::TimeLock}; | ||
|
|
||
|
|
@@ -51,6 +51,8 @@ const ERecordTagAlreadyDefined: vector<u8> = | |
| #[error] | ||
| const ERecordTagInUse: vector<u8> = | ||
| b"The requested tag cannot be removed because it is already used by an existing record or role"; | ||
| #[error] | ||
| const ERecordAlreadyReplaced: vector<u8> = b"The record has already been replaced"; | ||
|
|
||
| // ===== Constants ===== | ||
|
|
||
|
|
@@ -533,6 +535,106 @@ public fun add_record<D: store + copy>( | |
| output | ||
| } | ||
|
|
||
| /// Adds a correction record that supersedes an existing record. | ||
| /// | ||
| /// The original record remains immutable. The new correction record is appended | ||
| /// at the next sequence number with a correction tracker whose `replaces` set | ||
| /// contains `sequence_number`. The replaced record receives an `is_replaced_by` | ||
| /// back-pointer to the new correction so clients can resolve the current | ||
| /// canonical record by following the replacement chain. | ||
| /// | ||
| /// Requires a capability granting the `CorrectRecord` permission. When either | ||
| /// the replaced record or the new correction record carries a tag, that same | ||
| /// capability must also allow the corresponding tag. | ||
| /// | ||
| /// Aborts with: | ||
| /// * `EPackageVersionMismatch` when the trail is at a different package version. | ||
| /// * any error documented by `RoleMap::assert_capability_valid` when `cap` fails | ||
| /// authorization checks. | ||
| /// * `ETrailWriteLocked` while `write_lock` is active. | ||
| /// * `ERecordNotFound` when no record exists at `sequence_number`. | ||
| /// * `ERecordAlreadyReplaced` when `sequence_number` already points to a newer | ||
| /// correction. | ||
| /// * `ERecordTagNotDefined` when `record_tag` is not in the trail's tag registry. | ||
| /// * `ERecordTagNotAllowed` when `cap`'s role does not allow the replaced | ||
| /// record tag or the new correction tag. | ||
| /// | ||
| /// Emits a `RecordAdded` event for the correction record on success. | ||
| /// | ||
| /// Returns the same receipt that is emitted as the `RecordAdded` event. | ||
| public fun correct_record<D: store + copy>( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it is accounted here. or did I overlook something ? |
||
| self: &mut AuditTrail<D>, | ||
| cap: &Capability, | ||
| sequence_number: u64, | ||
| stored_data: D, | ||
| record_metadata: Option<String>, | ||
| record_tag: Option<String>, | ||
| clock: &Clock, | ||
| ctx: &mut TxContext, | ||
| ): RecordAdded { | ||
| assert!(self.version == PACKAGE_VERSION, EPackageVersionMismatch); | ||
| self | ||
| .roles | ||
| .assert_capability_valid( | ||
| cap, | ||
| &permission::correct_record(), | ||
| clock, | ||
| ctx, | ||
| ); | ||
| assert!(!self.locking_config.is_write_locked(clock), ETrailWriteLocked); | ||
| assert!(self.records.contains(sequence_number), ERecordNotFound); | ||
| assert!( | ||
| !self.records.borrow(sequence_number).correction().is_replaced(), | ||
| ERecordAlreadyReplaced, | ||
| ); | ||
| assert!( | ||
| is_record_tag_allowed( | ||
| self, | ||
| cap, | ||
| self.records.borrow(sequence_number).tag(), | ||
| ), | ||
| ERecordTagNotAllowed, | ||
| ); | ||
| assert!(is_record_tag_allowed(self, cap, &record_tag), ERecordTagNotAllowed); | ||
|
|
||
| let caller = ctx.sender(); | ||
| let timestamp = clock.timestamp_ms(); | ||
| let trail_id = self.id(); | ||
| let seq = self.sequence_number; | ||
|
|
||
| if (record_tag.is_some()) { | ||
| self.tags.increment_usage_count(record_tag.borrow()); | ||
| }; | ||
|
|
||
| let mut replaces = vec_set::empty(); | ||
| replaces.insert(sequence_number); | ||
|
|
||
| let correction = record::new( | ||
| stored_data, | ||
| record_metadata, | ||
| record_tag, | ||
| seq, | ||
| caller, | ||
| timestamp, | ||
| record::with_replaces(replaces), | ||
| ); | ||
|
|
||
| self.records.borrow_mut(sequence_number).correction_mut().set_replaced_by(seq); | ||
|
|
||
| linked_table::push_back(&mut self.records, seq, correction); | ||
| self.sequence_number = self.sequence_number + 1; | ||
|
|
||
| let output = RecordAdded { | ||
| trail_id, | ||
| sequence_number: seq, | ||
| added_by: caller, | ||
| timestamp, | ||
| }; | ||
|
|
||
| event::emit(copy output); | ||
| output | ||
| } | ||
|
|
||
| /// Deletes the record at `sequence_number` from the trail. | ||
| /// | ||
| /// When the deleted record carries a tag, the trail's tag-registry usage count for | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.