Skip to main content
The approval system in TAPLE Core enables governance-controlled validation of events before they’re committed to the ledger. This guide explains how to work with the approval workflow.

Understanding Approvals

Approvals provide a governance layer for events that require consensus:
  • Approval Requests: Sent to designated approvers
  • Voting: Approvers vote to accept or reject events
  • Quorum: Minimum number of approvals required
  • States: Track approval progress and outcomes
The approval system is implemented in core/src/approval/manager.rs:1.

Approval Entity Structure

pub struct ApprovalEntity {
    pub id: DigestIdentifier,
    pub subject_id: DigestIdentifier,
    pub sn: u64,
    pub request: Signed<ApprovalRequest>,
    pub response: Option<Signed<ApprovalResponse>>,
    pub state: ApprovalState,
}

Approval Request

When an event requires approval, an ApprovalRequest is created:
pub struct ApprovalRequest {
    pub event_request: Signed<EventRequest>,
    pub sn: u64,
    pub gov_version: u64,
    pub patch: ValueWrapper,
    pub state_hash: DigestIdentifier,
    pub hash_prev_event: DigestIdentifier,
    pub gov_id: DigestIdentifier,
}

Approval States

Approvals progress through different states:
pub enum ApprovalState {
    Pending,
    RespondedAccepted,
    RespondedRejected,
    Obsolete,
}
  • Pending: Waiting for votes
  • RespondedAccepted: This node voted to accept
  • RespondedRejected: This node voted to reject
  • Obsolete: Request is no longer valid

Getting Approval Requests

Get Pending Requests

Retrieve all approval requests awaiting your vote:
let pending = api.get_pending_requests().await?;
Implemented in core/src/api/api.rs:113.

Get Single Request

Retrieve a specific approval request:
let approval = api.get_single_request(request_id).await?;
See core/src/api/api.rs:134 for the implementation.

Get All Approvals

Retrieve approvals with optional state filtering:
let approvals = api.get_approvals(
    Some(ApprovalState::Pending),  // state filter
    None,  // from
    Some(20),  // quantity
).await?;
Defined in core/src/api/api.rs:426.

Get Single Approval

Get detailed information about an approval:
let approval = api.get_approval(request_id).await?;
Implemented in core/src/api/api.rs:409.

Voting on Approvals

Approve a Request

Vote to accept an approval request:
let approval_entity = api.approval_request(
    request_id,
    true  // acceptance
).await?;

Reject a Request

Vote to reject an approval request:
let approval_entity = api.approval_request(
    request_id,
    false  // rejection
).await?;
The approval_request method is defined in core/src/api/api.rs:301.
Your vote is cryptographically signed and sent to the event owner for collection.

Approval API Interface

The ApprovalAPI provides programmatic access:

Request Approval

Submit a signed approval request:
approval_api.request_approval(signed_request).await?;
Implemented in core/src/approval/manager.rs:65.

Emit Vote

Generate and send a vote:
let approval_entity = approval_api.emit_vote(
    request_id,
    acceptance
).await?;
See core/src/approval/manager.rs:75 for implementation details.

Get All Requests

Retrieve all approval requests:
let requests = approval_api.get_all_requests().await?;

Get Single Request

Fetch a specific request:
let request = approval_api.get_single_request(request_id).await?;

Approval Manager Processing

Processing Approval Requests

The approval manager handles incoming requests:
let result = inner_manager
    .process_approval_request(approval, sender)
    .await?;
This is processed in core/src/approval/manager.rs:219.

Generating Votes

When you vote, the manager generates a signed response:
let result = inner_manager
    .generate_vote(&request_id, acceptance)
    .await?;
Implemented in core/src/approval/manager.rs:280.

Governance Version Handling

Approvals track governance versions to ensure consistency:
match result {
    Err(ApprovalErrorResponse::OurGovIsLower {
        our_id,
        sender,
        gov_id,
    }) => {
        // Request updated governance
    },
    Err(ApprovalErrorResponse::OurGovIsHigher {
        our_id,
        sender,
        gov_id,
    }) => {
        // Notify sender of higher governance
    },
    _ => {}
}
Handled in core/src/approval/manager.rs:236-276.

Approval Workflow

1
1. Event Requires Approval
2
Governance determines if an event needs approval based on policies.
3
2. Approval Requests Sent
4
Approval requests are sent to designated approvers:
5
let msg = create_approver_response(approval);
messenger_channel.tell(
    MessageTaskCommand::Request(
        None,
        msg,
        vec![sender],
        MessageConfig::direct_response(),
    )
).await?;
6
3. Approvers Vote
7
Approvers review and vote on the request:
8
let approval = api.approval_request(request_id, true).await?;
9
4. Votes Collected
10
The event owner collects votes and checks quorum.
11
5. Event Finalized
12
Once quorum is reached, the event proceeds to validation.

Database Operations

Store Approval

Persist an approval entity:
db.set_approval(&request_id, approval_entity)?;
Implemented in core/src/database/db.rs:438.

Get Approval

Retrieve an approval from storage:
let approval = db.get_approval(&request_id)?;
See core/src/database/db.rs:425.

Get Approvals with Filter

Retrieve approvals by state:
let approvals = db.get_approvals(
    Some(ApprovalState::Pending),
    None,
    10
)?;
Implemented in core/src/database/db.rs:429.

Delete Approval

Remove an approval:
db.del_approval(&request_id)?;

Approval Indexing

Index by Subject

Link approvals to subjects:
db.set_subject_approval_index(&subject_id, &request_id)?;

Get Approvals by Subject

Retrieve all approvals for a subject:
let approval_ids = db.get_approvals_by_subject(&subject_id)?;
Implemented in core/src/database/db.rs:450.

Index by Governance

Link approvals to governance:
db.set_governance_approval_index(&governance_id, &request_id)?;

Get Approvals by Governance

Retrieve approvals for a governance:
let approval_ids = db.get_approvals_by_governance(&governance_id)?;
See core/src/database/db.rs:475.

Approval Manager Lifecycle

The approval manager runs continuously:
loop {
    tokio::select! {
        command = input_channel.receive() => {
            let result = self.process_command(command).await;
        },
        _ = token.cancelled() => {
            break;
        },
        update = governance_update_channel.recv() => {
            self.inner_manager.new_governance_version(&governance_id)?;
        }
    }
}
Implemented in core/src/approval/manager.rs:151.

Pass Votation Setting

Configure automatic approval behavior:
let passvotation = settings.node.passvotation.into();
let inner_manager = InnerApprovalManager::new(
    gov_api,
    database,
    notifier,
    signature_manager,
    passvotation,
    derivator
);
When enabled, the node automatically approves valid requests.

Error Handling

Common approval errors:
  • VoteNotNeeded: Your vote is not required or already counted
  • NotFound: Approval request doesn’t exist
  • InvalidParameters: Malformed request ID
  • InternalError: Processing failure
  • APIChannelNotAvailable: Communication failure
  • OurGovIsLower: Local governance is outdated
  • OurGovIsHigher: Remote governance is outdated
Handle these appropriately:
match api.approval_request(request_id, true).await {
    Ok(approval) => {
        println!("Vote submitted successfully");
    },
    Err(ApiError::VoteNotNeeded) => {
        println!("Vote not needed");
    },
    Err(e) => {
        eprintln!("Error voting: {:?}", e);
    }
}

Best Practices

  1. Monitor Pending Requests: Regularly check for pending approval requests
  2. Timely Voting: Vote promptly to avoid delaying event processing
  3. Verify Governance: Ensure governance version matches before voting
  4. Audit Trail: Log all approval decisions for compliance
  5. Quorum Configuration: Set appropriate quorum thresholds in governance
  6. Error Recovery: Handle governance version mismatches gracefully
Approval votes are permanent and cryptographically signed. Ensure you verify the event details before voting.

Build docs developers (and LLMs) love