Skip to main content
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

1
1. Request Creation
2
Create and sign an event request:
3
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)?,
};
4
2. Request Submission
5
Submit the signed request to the node:
6
let request_id = api.external_request(signed_request).await?;
7
Implemented in core/src/api/api.rs:90.
8
3. Evaluation
9
The event manager processes the request through the evaluation stage:
10
// Internal processing
let response = event_completer.pre_new_event(event_request).await;
11
Evaluators execute the contract and generate signatures. See core/src/event/manager.rs:157.
12
4. Approval (if required)
13
If governance requires approval, approvers vote on the event:
14
// Approvers receive approval requests
let response = event_completer.approver_signatures(approval).await;
15
Processed in core/src/event/manager.rs:205.
16
5. Validation
17
Validators verify the event and provide signatures:
18
// Validators process validation requests
let response = event_completer.validation_signatures(
    event_hash,
    signature,
    governance_version
).await;
19
Implemented in core/src/event/manager.rs:226.
20
6. Event Commitment
21
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)

Event Metadata

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

  1. Sequence Numbers: Always verify sequence numbers are sequential
  2. Signature Verification: Validate all signatures before trusting event data
  3. Governance Versions: Track governance versions to handle updates correctly
  4. Error Handling: Implement proper error handling for all event operations
  5. State Consistency: Verify state hashes match after applying patches
  6. 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

Build docs developers (and LLMs) love