Events are the fundamental units of change in TAPLE Core. Every state transition in a subject is recorded as an immutable event in the subject’s event chain. This guide covers the complete event lifecycle.
Understanding Events
An event in TAPLE Core represents:
- State Change: A modification to subject properties
- Cryptographic Proof: Signatures from evaluators, approvers, and validators
- Immutability: Once committed, events cannot be altered
- Traceability: Complete audit trail of changes
The Event struct is defined in core/src/commons/models/event.rs:26.
Event Structure
pub struct Event {
pub subject_id: DigestIdentifier,
pub event_request: Signed<EventRequest>,
pub sn: u64,
pub gov_version: u64,
pub patch: ValueWrapper,
pub state_hash: DigestIdentifier,
pub eval_success: bool,
pub appr_required: bool,
pub approved: bool,
pub hash_prev_event: DigestIdentifier,
pub evaluators: HashSet<Signature>,
pub approvers: HashSet<Signature>,
}
Event Request Types
TAPLE Core supports four types of event requests:
Create Request
Creates a new subject:
pub struct StartRequest {
pub governance_id: DigestIdentifier,
pub schema_id: String,
pub namespace: String,
pub name: String,
pub public_key: KeyIdentifier,
}
Fact Request
Adds data to an existing subject:
pub struct FactRequest {
pub subject_id: DigestIdentifier,
pub payload: ValueWrapper,
}
Transfer Request
Transfers ownership of a subject:
pub struct TransferRequest {
pub subject_id: DigestIdentifier,
pub public_key: KeyIdentifier,
}
EOL Request
Marks a subject as end-of-life:
pub struct EOLRequest {
pub subject_id: DigestIdentifier,
}
All request types are defined in core/src/commons/models/request.rs:14.
Event Lifecycle Stages
Create and sign an event request:
let fact_request = EventRequest::Fact(FactRequest {
subject_id: subject_id.clone(),
payload: ValueWrapper(json!({
"temperature": 25.5,
"timestamp": "2024-01-01T12:00:00Z"
})),
});
let signed_request = Signed::<EventRequest> {
content: fact_request.clone(),
signature: Signature::new(&fact_request, &keypair)?,
};
Submit the signed request to the node:
let request_id = api.external_request(signed_request).await?;
Implemented in core/src/api/api.rs:90.
The event manager processes the request through the evaluation stage:
// Internal processing
let response = event_completer.pre_new_event(event_request).await;
Evaluators execute the contract and generate signatures. See core/src/event/manager.rs:157.
4. Approval (if required)
If governance requires approval, approvers vote on the event:
// Approvers receive approval requests
let response = event_completer.approver_signatures(approval).await;
Processed in core/src/event/manager.rs:205.
Validators verify the event and provide signatures:
// Validators process validation requests
let response = event_completer.validation_signatures(
event_hash,
signature,
governance_version
).await;
Implemented in core/src/event/manager.rs:226.
Once quorum is reached, the event is committed to the ledger.
Creating Events
Genesis Event
Create the first event for a new subject:
let genesis_event = Signed::<Event>::from_genesis_request(
event_request,
&subject_keys,
gov_version,
&init_state,
derivator,
)?;
Implemented in core/src/commons/models/event.rs:88.
Fact Event
Add a fact to an existing subject:
let event_request = EventRequest::Fact(FactRequest {
subject_id,
payload: ValueWrapper(json!({
"status": "active",
"value": 100
})),
});
Fact events are the only event type that requires evaluation and approval according to governance policies.
Retrieving Events
Get a Single Event
Retrieve a specific event by subject ID and sequence number:
let event = api.get_event(subject_id, sn).await?;
Defined in core/src/api/api.rs:229.
Get Event Range
Retrieve multiple events with pagination:
let events = api.get_events(
subject_id,
Some(0), // from sequence number
Some(10), // quantity
).await?;
Supports negative from values for reverse iteration. See core/src/api/api.rs:252.
Database Event Operations
Direct database access for events:
// Store an event
db.set_event(&subject_id, event)?;
// Retrieve an event
let event = db.get_event(&subject_id, sn)?;
// Get event range
let events = db.get_events_by_range(
&subject_id,
Some(0),
10
)?;
// Delete an event
db.del_event(&subject_id, sn)?;
Implemented in core/src/database/db.rs:157-185.
Event Verification
Verify Signatures
Verify event and request signatures:
signed_event.verify_signatures()?;
This verifies:
- Event signature by subject owner
- Event request signature by invoker
Implemented in core/src/commons/models/event.rs:141.
Verify Evaluators and Approvers
Verify evaluator and approver signatures:
signed_event.verify_eval_appr(
subject_context,
(&eval_signers, eval_quorum, eval_reject_quorum),
(&appr_signers, appr_quorum, appr_reject_quorum),
)?;
Implemented in core/src/commons/models/event.rs:147. This checks:
- Correct evaluators signed
- Evaluator quorum reached
- Correct approvers signed (if required)
- Approver quorum reached (if required)
Events include metadata for governance and validation:
pub struct Metadata {
pub namespace: String,
pub subject_id: DigestIdentifier,
pub governance_id: DigestIdentifier,
pub governance_version: u64,
pub schema_id: String,
}
Defined in core/src/commons/models/event.rs:246.
Event Hashing
Generate cryptographic hashes of events:
let event_hash = event.hash_id(derivator)?;
let signed_event_hash = signed_event.hash_id(derivator)?;
Implemented using the HashId trait in core/src/commons/models/event.rs:72-85.
Event Request Tracking
Get Request Status
Check the status of a submitted request:
let request = api.get_request(request_id).await?;
Request States
Requests can be in three states:
pub enum RequestState {
Finished,
Error,
Processing,
}
TAPLE Request Structure
pub struct TapleRequest {
pub id: DigestIdentifier,
pub subject_id: Option<DigestIdentifier>,
pub sn: Option<u64>,
pub event_request: Signed<EventRequest>,
pub state: RequestState,
pub success: Option<bool>,
}
Defined in core/src/commons/models/request.rs:106.
Event Responses
Evaluator Response
Evaluators return evaluation results:
pub struct EvaluationResponse {
pub patch: ValueWrapper,
pub eval_req_hash: DigestIdentifier,
pub state_hash: DigestIdentifier,
pub eval_success: bool,
pub appr_required: bool,
}
Approver Response
Approvers return approval decisions:
pub struct ApprovalResponse {
pub appr_req_hash: DigestIdentifier,
pub approved: bool,
}
Event Commands
The event manager handles various commands:
pub enum EventCommand {
Event { event_request: Signed<EventRequest> },
EvaluatorResponse { evaluator_response: Signed<EvaluationResponse> },
ApproverResponse { approval: Signed<ApprovalResponse> },
ValidatorResponse {
event_hash: DigestIdentifier,
signature: Signature,
governance_version: u64,
},
HigherGovernanceExpected {
governance_id: DigestIdentifier,
who_asked: KeyIdentifier,
},
}
Best Practices
- Sequence Numbers: Always verify sequence numbers are sequential
- Signature Verification: Validate all signatures before trusting event data
- Governance Versions: Track governance versions to handle updates correctly
- Error Handling: Implement proper error handling for all event operations
- State Consistency: Verify state hashes match after applying patches
- Request Tracking: Monitor request states for debugging and user feedback
Error Handling
Common event-related errors:
NotCreateEvent: Event type mismatch
SignatureCreationFails: Cryptographic operation failed
RepeatedSignature: Duplicate signer detected
SignersError: Invalid or insufficient signers
EventApiChannelNotAvailable: Communication failure with event manager
ChannelClosed: Event processing channel closed