Expand description
§IOTA Audit Trails Rust Package
§Introduction
The Audit Trails Rust package provides the Rust client for structured record histories in the IOTA Notarization Toolkit.
The package also provides an AuditTrailBuilder that creates audit trail objects on the IOTA ledger and an AuditTrailHandle
that interacts with existing trails. The handle maps to one on-chain audit trail and provides typed APIs for records,
access control, locking, tags, metadata, migration, and deletion.
Use Audit Trails when you need a governed record history with sequential entries, role-based permissions, capabilities, locking, and tagging. Use Single Notarization when you need one locked or dynamic notarized object for arbitrary data, documents, hashes, or latest-state records.
You can find the full IOTA Notarization Toolkit documentation here.
§Process Flows
The following workflows demonstrate how AuditTrailBuilder and AuditTrailHandle instances create, update, govern, and
delete audit trail objects on the ledger.
§Creating an AuditTrail Object
An AuditTrail on-chain object is created on the ledger using the AuditTrailClient::create_trail() function. To
create an AuditTrail object, specify the following initial arguments with the AuditTrailBuilder setter functions.
The terms used here are defined in the glossary below.
- Optional
Initial Recordthat becomes sequence number0 - Optional
Immutable Metadata - Optional
Updatable Metadata - Optional
Locking Config - Optional
Record Tag Registry - Optional initial admin address
After an AuditTrail object has been created, the creator receives an Admin capability object. This capability authorizes
administrative operations such as defining roles, issuing capabilities, updating locks, managing tags, and deleting the
trail.
§Creating a new AuditTrail Object on the Ledger
The following sequence diagram explains the interaction between the involved technical components and the Admin when an
AuditTrail object is created on the ledger:
sequenceDiagram
actor Admin
participant Lib as Rust-Library
participant Move as Move-SC
participant Net as Iota-Network
Admin ->>+ Lib: fn AuditTrailClientReadOnly::new(iota_client)
Lib ->>- Admin: AuditTrailClientReadOnly
Admin ->>+ Lib: fn AuditTrailClient::new(read_only_client, signer)
Lib ->>- Admin: AuditTrailClient
Admin ->>+ Lib: fn AuditTrailClient::create_trail()
Lib ->>- Admin: AuditTrailBuilder
Admin ->> Lib: fn AuditTrailBuilder::with_trail_metadata(metadata)
Admin ->> Lib: fn AuditTrailBuilder::with_updatable_metadata(metadata)
Admin ->> Lib: fn AuditTrailBuilder::with_initial_record(record)
Admin ->>+ Lib: fn AuditTrailBuilder::finish()
Lib ->>- Admin: TransactionBuilder<CreateTrail>
Admin ->>+ Lib: fn TransactionBuilder<CreateTrail>::build_and_execute()
Note right of Admin: Alternatively fn execute_with_gas_station() <br> can be used to execute via Gas Station
Note right of Admin: Alternatively fn build() <br> can be used to only return the TransactionData and signatures
Lib ->>+ Move: main::create()
Move ->> Net: transfer::transfer(trail, sender)
Move ->> Net: transfer::transfer(admin_capability, admin)
Move ->>- Lib: TX Response
Lib ->>- Admin: TrailCreated + IotaTransactionBlockResponse§Adding And Reading Records
Records are managed through the trail-scoped record API returned by AuditTrailHandle::records(). A record append uses
TrailRecords::add(), while read paths use TrailRecords::get(), TrailRecords::record_count(), TrailRecords::list(),
or TrailRecords::list_page().
To add a record, the sender must hold a capability whose role allows record writes. Tagged records must use a tag already defined in the trail’s tag registry, and the sender’s role must allow that tag.
§Appending a Record to an Existing AuditTrail Object
The following sequence diagram shows the component interaction when a Record Admin appends a new record:
sequenceDiagram
actor RecordAdmin
participant Lib as Rust-Library
participant Move as Move-SC
participant Net as Iota-Network
RecordAdmin ->>+ Lib: fn AuditTrailClient::trail(trail_id)
Lib ->>- RecordAdmin: AuditTrailHandle
RecordAdmin ->>+ Lib: fn AuditTrailHandle::records()
Lib ->>- RecordAdmin: TrailRecords
RecordAdmin ->>+ Lib: fn TrailRecords::add(data, metadata, tag)
Lib ->>- RecordAdmin: TransactionBuilder<AddRecord>
RecordAdmin ->>+ Lib: fn TransactionBuilder<AddRecord>::build_and_execute()
Lib ->>+ Move: main::add_record()
Move ->> Move: validate capability, lock state, and tag policy
Move ->> Net: append record at next sequence number
Move ->> Net: event::emit(RecordAdded)
Move ->>- Lib: TX Response
Lib ->>- RecordAdmin: RecordAdded + IotaTransactionBlockResponse§Reading Records from an Existing AuditTrail Object
The following sequence diagram explains the component interaction for Verifiers or other parties fetching trail
records:
sequenceDiagram
actor Verifier
participant Lib as Rust-Library
participant Net as Iota-Network
Verifier ->>+ Lib: fn AuditTrailClientReadOnly::trail(trail_id)
Lib ->>- Verifier: AuditTrailHandle
Verifier ->>+ Lib: fn AuditTrailHandle::records()
Lib ->>- Verifier: TrailRecords
Verifier ->>+ Lib: fn TrailRecords::get(sequence_number)
Lib -->> Net: RPC Calls
Net -->> Lib: Record Data
Lib ->>- Verifier: Record§Managing Access
Access control is managed through the trail-scoped access API returned by AuditTrailHandle::access(). Roles define
which permissions are allowed, and capability objects delegate those roles to users or services.
The built-in Admin role is initialized when the trail is created. Additional roles can be created with
TrailAccess::for_role(name).create(...), updated with update_permissions(...), and delegated with
issue_capability(...). Issued capabilities can also be revoked, destroyed, or constrained by address and validity
window.
§Defining a Role and Issuing a Capability
The following sequence diagram shows the component interaction when an Admin defines a role and issues a capability:
sequenceDiagram
actor Admin
participant Lib as Rust-Library
participant Move as Move-SC
participant Net as Iota-Network
Admin ->>+ Lib: fn AuditTrailClient::trail(trail_id)
Lib ->>- Admin: AuditTrailHandle
Admin ->>+ Lib: fn AuditTrailHandle::access()
Lib ->>- Admin: TrailAccess
Admin ->>+ Lib: fn TrailAccess::for_role("RecordAdmin")
Lib ->>- Admin: RoleHandle
Admin ->>+ Lib: fn RoleHandle::create(permissions, role_tags)
Lib ->>- Admin: TransactionBuilder<CreateRole>
Admin ->>+ Lib: fn TransactionBuilder<CreateRole>::build_and_execute()
Lib ->>+ Move: main::create_role()
Move ->> Net: event::emit(RoleCreated)
Move ->>- Lib: TX Response
Admin ->>+ Lib: fn RoleHandle::issue_capability(options)
Lib ->>- Admin: TransactionBuilder<IssueCapability>
Admin ->>+ Lib: fn TransactionBuilder<IssueCapability>::build_and_execute()
Lib ->>+ Move: main::new_capability()
Move ->> Net: transfer::transfer(capability, issued_to)
Move ->> Net: event::emit(CapabilityIssued)
Move ->>- Lib: TX Response
Lib ->>- Admin: CapabilityIssued + IotaTransactionBlockResponse§Locking And Deletion
Locking is managed through the trail-scoped locking API returned by AuditTrailHandle::locking(). The lock configuration
controls three independent behaviors:
- when records can be deleted
- when the entire trail can be deleted
- when new records can be written
An audit trail can be deleted only after its records are removed and the delete-trail lock allows deletion. Records can
be deleted individually with TrailRecords::delete() or in batches with TrailRecords::delete_records_batch().
For count-based delete windows, the Move package protects the last N records currently present in trail order. Deletions
can move older records into that protected window, and large count values increase delete gas linearly.
§Updating Locking Rules
The following sequence diagram shows the component interaction when a Locking Admin updates the write lock:
sequenceDiagram
actor LockingAdmin
participant Lib as Rust-Library
participant Move as Move-SC
participant Net as Iota-Network
LockingAdmin ->>+ Lib: fn AuditTrailClient::trail(trail_id)
Lib ->>- LockingAdmin: AuditTrailHandle
LockingAdmin ->>+ Lib: fn AuditTrailHandle::locking()
Lib ->>- LockingAdmin: TrailLocking
LockingAdmin ->>+ Lib: fn TrailLocking::update_write_lock(lock)
Lib ->>- LockingAdmin: TransactionBuilder<UpdateWriteLock>
LockingAdmin ->>+ Lib: fn TransactionBuilder<UpdateWriteLock>::build_and_execute()
Lib ->>+ Move: main::update_write_lock()
Move ->> Move: validate capability and requested lock
Move ->> Net: update trail locking config
Move ->>- Lib: TX Response
Lib ->>- LockingAdmin: () + IotaTransactionBlockResponse§Deleting an AuditTrail Object
The workflow of deletion an AuditTrail object can be described as:
- Delete all eligible unlocked records with
TrailRecords::delete()orTrailRecords::delete_records_batch() - If not all records have been deleted:
- if a lock is configured, wait until the
Delete Trail Lockallows trail deletion, - if records are tag protected, notify a user with an appropriate role granting the needed tag access, to delete the remaining records
- if a lock is configured, wait until the
- Delete the trail object with
AuditTrailHandle::delete_audit_trail()
The trail deletion process does not remove records automatically. The trail must be empty before
delete_audit_trail() can succeed.
§Glossary
AuditTrailobject: A shared on-chain object that stores ordered records, metadata, locking configuration, tag registry, roles, and capability state.Record: A single trail entry stored at a sequence number. Records containData, optional record metadata, an optional tag, and creation information.Initial Record: An optional record created together with the trail. When present, it is stored at sequence number0.Sequence Number: The numeric position of a record inside a trail. Sequence numbers are used to fetch, delete, and reason about records.Admin Capability: The capability object created at trail creation time. It authorizes administrative operations for the trail.Role: A named permission set stored inside the trail. Roles define which operations a capability holder may perform.Permission Set: A collection of permissions such as adding records, deleting records, updating locks, managing tags, managing metadata, or managing capabilities.Capability: An owned object that grants one role for one audit trail. Capabilities can optionally be restricted to an address or a validity window.Record Tag Registry: The trail-owned list of tags that records may use. Tagged writes must reference a registered tag.Role Tags: Optional role-scoped tag restrictions. They narrow which tagged records a role may operate on.Locking Config: The active locking rules for record deletion, trail deletion, and record writes.Delete Record Window: A locking rule that controls when individual records can be deleted. Count-based windows protect the last N records currently present in trail order.Delete Trail Lock: A time lock that controls when the entire trail can be deleted.Write Lock: A time lock that controls when new records can be added.Immutable Metadata: Optional metadata stored at creation time and never updated after the trail is created.Updatable Metadata: Optional metadata stored on the trail that can be replaced or cleared after creation.Trail Handle: The typed Rust handle returned byAuditTrailClient::trail(trail_id). It scopes record, access, locking, tag, metadata, migration, and deletion operations to one audit trail.
§Documentation And Resources
- Audit Trails Move Package: On-chain contract package that defines the shared object model, permissions, locking, and events.
- Audit Trails Wasm Package: JavaScript and TypeScript bindings for browser and Node.js integrations.
- Audit Trails Wasm Examples: Runnable audit-trail examples for JS and TS consumers.
- Repository Examples: End-to-end examples across the Notarization Toolkit.
This README is also used as the crate-level rustdoc entry point, while the source files provide detailed API documentation for all public types and methods.
§Bindings
Foreign Function Interface (FFI) bindings of this Rust crate to other programming languages:
- Web Assembly (JavaScript/TypeScript)
§Contributing
We would love to have you help us with the development of the IOTA Notarization Toolkit. Each and every contribution is greatly valued.
Please review the contribution sections in the IOTA Docs Portal.
To contribute directly to the repository, simply fork the project, push your changes to your fork and create a pull request to get them included.
The best place to get involved in discussions about this library or to look for support at is the #notarization channel on the IOTA Discord. You can also ask questions on our Stack Exchange.
Re-exports§
pub use client::full_client::AuditTrailClient;pub use client::read_only::AuditTrailClientReadOnly;pub use client::read_only::PackageOverrides;
Modules§
- client
- Client wrappers for read-only and signing access to audit trails. Client implementations for interacting with audit trails on the IOTA ledger.
- core
- Core handles, builders, transactions, and domain types. Core handles, builders, transactions, and domain types for Audit Trails.
- error
- Error types returned by the public API. Error types returned by the audit-trail public API.