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