Skip to main content
Governance in TAPLE defines the rules and policies that control how subjects are created, modified, and validated within the network. It acts as the constitutional framework for the distributed ledger.

Overview

Governance contracts specify:
  • Schemas: Data structures for different subject types
  • Policies: Rules for event validation and approval
  • Members: Who can participate and their roles
  • Quorums: Required signatures for different operations

Governance Structure

Governance Messages

The governance system processes various types of requests:
pub enum GovernanceMessage {
    GetInitState {
        governance_id: DigestIdentifier,
        schema_id: String,
        governance_version: u64,
    },
    GetSchema {
        governance_id: DigestIdentifier,
        schema_id: String,
        governance_version: u64,
    },
    GetSigners {
        metadata: Metadata,
        stage: ValidationStage,
    },
    GetQuorum {
        metadata: Metadata,
        stage: ValidationStage,
    },
    GetInvokeInfo {
        metadata: Metadata,
        stage: ValidationStage,
        invoker: KeyIdentifier,
    },
    GetContracts {
        governance_id: DigestIdentifier,
        governance_version: u64,
    },
    GetGovernanceVersion {
        governance_id: DigestIdentifier,
        subject_id: DigestIdentifier,
    },
    IsGovernance {
        subject_id: DigestIdentifier,
    },
    GovernanceUpdated {
        governance_id: DigestIdentifier,
        governance_version: u64,
    },
}
Source: governance/mod.rs:38-77

Governance Interface

Components interact with governance through a well-defined async interface:
pub trait GovernanceInterface: Sync + Send {
    async fn get_init_state(
        &self,
        governance_id: DigestIdentifier,
        schema_id: String,
        governance_version: u64,
    ) -> Result<ValueWrapper, RequestError>;
    
    async fn get_schema(
        &self,
        governance_id: DigestIdentifier,
        schema_id: String,
        governance_version: u64,
    ) -> Result<ValueWrapper, RequestError>;

    async fn get_signers(
        &self,
        metadata: Metadata,
        stage: ValidationStage,
    ) -> Result<HashSet<KeyIdentifier>, RequestError>;

    async fn get_quorum(
        &self,
        metadata: Metadata,
        stage: ValidationStage,
    ) -> Result<u32, RequestError>;

    async fn get_invoke_info(
        &self,
        metadata: Metadata,
        stage: ValidationStage,
        invoker: KeyIdentifier,
    ) -> Result<bool, RequestError>;

    async fn get_contracts(
        &self,
        governance_id: DigestIdentifier,
        governance_version: u64,
    ) -> Result<Vec<(Contract, String)>, RequestError>;

    async fn get_governance_version(
        &self,
        governance_id: DigestIdentifier,
        subject_id: DigestIdentifier,
    ) -> Result<u64, RequestError>;

    async fn is_governance(&self, subject_id: DigestIdentifier) -> Result<bool, RequestError>;

    async fn governance_updated(
        &self,
        governance_id: DigestIdentifier,
        governance_version: u64,
    ) -> Result<(), RequestError>;
}
Source: governance/governance.rs:200-252

Governance Members

Each governance defines its members and their properties:
pub struct GovernanceMember {
    pub id: String,
    pub namespace: String,
    pub description: String,
    pub key: KeyIdentifier,
}
Source: governance/mod.rs:23-28
Members are identified by their cryptographic key identifiers, ensuring secure participation.

Validation Stages

Governance policies vary depending on the stage of event processing. The ValidationStage determines which rules apply:
pub enum ValidationStage {
    Evaluator,
    Approver,
    Validator,
}
Source: governance/stage.rs (referenced)

Stage Responsibilities

  • Evaluator: Executes smart contracts to compute state changes
  • Approver: Provides business approval for the event
  • Validator: Validates the final event and signatures

Governance Versioning

Governance contracts evolve over time through versioning:
GetGovernanceVersion {
    governance_id: DigestIdentifier,
    subject_id: DigestIdentifier,
}
Each subject is created under a specific governance version:
pub struct Subject {
    pub governance_id: DigestIdentifier,
    pub genesis_gov_version: u64,
    // ...
}
Source: commons/models/state.rs:24, 28
Subjects maintain their genesis governance version. When governance is updated, existing subjects continue with their original version unless migrated.

Governance API

The GovernanceAPI provides a convenient way to interact with the governance manager:
pub struct GovernanceAPI {
    sender: SenderEnd<GovernanceMessage, GovernanceResponse>,
}

impl GovernanceAPI {
    pub fn new(sender: SenderEnd<GovernanceMessage, GovernanceResponse>) -> Self {
        Self { sender }
    }
}
Source: governance/governance.rs:254-262

Example: Getting Signers

async fn get_signers(
    &self,
    metadata: Metadata,
    stage: ValidationStage,
) -> Result<HashSet<KeyIdentifier>, RequestError> {
    let response = self
        .sender
        .ask(GovernanceMessage::GetSigners {
            metadata: metadata.clone(),
            stage,
        })
        .await
        .map_err(|_| RequestError::ChannelClosed)?;
    if let GovernanceResponse::GetSigners(signers) = response {
        signers
    } else {
        Err(RequestError::UnexpectedResponse)
    }
}
Source: governance/governance.rs:311-329

Example: Getting Quorum

async fn get_quorum(
    &self,
    metadata: Metadata,
    stage: ValidationStage,
) -> Result<u32, RequestError> {
    let response = self
        .sender
        .ask(GovernanceMessage::GetQuorum {
            metadata: metadata.clone(),
            stage,
        })
        .await
        .map_err(|_| RequestError::ChannelClosed)?;
    if let GovernanceResponse::GetQuorum(quorum) = response {
        quorum
    } else {
        Err(RequestError::UnexpectedResponse)
    }
}
Source: governance/governance.rs:331-349

Governance Updates

When governance is updated, the system broadcasts the change:
pub enum GovernanceUpdatedMessage {
    GovernanceUpdated {
        governance_id: DigestIdentifier,
        governance_version: u64,
    },
}
Source: governance/mod.rs:93-98 Components subscribe to governance updates:
let (governance_update_sx, governance_update_rx) = broadcast::channel(BUFFER_SIZE);
Source: node.rs:90
The broadcast channel allows multiple components to react to governance changes simultaneously.

Governance Manager Lifecycle

The governance manager runs as an independent task:
pub async fn run(&mut self) {
    loop {
        tokio::select! {
            msg = self.input.receive() => {
                let result = self.process_input(msg).await;
                if result.is_err() {
                    log::error!("Error at governance module {}", result.unwrap_err());
                    break;
                }
            },
            _ = self.token.cancelled() => {
                log::debug!("Shutdown received");
                break;
            }
        }
    }
    self.token.cancel();
    log::info!("Ended");
}
Source: governance/governance.rs:52-70

Schema Management

Governance defines schemas for different subject types:
GetSchema {
    governance_id: DigestIdentifier,
    schema_id: String,
    governance_version: u64,
}
Schemas specify:
  • Data structure and types
  • Validation rules
  • Initial state format

Getting Initial State

async fn get_init_state(
    &self,
    governance_id: DigestIdentifier,
    schema_id: String,
    governance_version: u64,
) -> Result<ValueWrapper, RequestError> {
    let response = self
        .sender
        .ask(GovernanceMessage::GetInitState {
            governance_id,
            schema_id,
            governance_version,
        })
        .await
        .map_err(|_| RequestError::ChannelClosed)?;
    if let GovernanceResponse::GetInitState(init_state) = response {
        init_state
    } else {
        Err(RequestError::UnexpectedResponse)
    }
}
Source: governance/governance.rs:267-287

Contracts in Governance

Governance manages smart contracts (evaluators) for different schemas:
GetContracts {
    governance_id: DigestIdentifier,
    governance_version: u64,
}
async fn get_contracts(
    &self,
    governance_id: DigestIdentifier,
    governance_version: u64,
) -> Result<Vec<(Contract, String)>, RequestError>
Source: governance/governance.rs:373-391

Best Practices

Version Control

Carefully plan governance updates as they affect all subjects

Quorum Settings

Set appropriate quorums balancing security and availability

Schema Design

Design schemas to be forward-compatible when possible

Member Management

Regularly review and update governance members

Next Steps

Subjects

Learn how subjects are governed

Events

Understand how governance affects events

Build docs developers (and LLMs) love