Canton Administration APIs

Canton provides a console as a builtin mode for administrative interaction. However, under the hood, all administrative console actions are effected using the administration gRPC API. Therefore, it is also possible to write your own administration application and connect it to the administration gRPC endpoints of both types of nodes, participant and domain.

There are three categories of admin-apis: participant, domain and identity.

Participant Admin APIs

The participant exposes the following admin-api services:

Package Service

The package service is used to manage the installed packages.

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

import "google/protobuf/empty.proto";

service PackageService {
    // List all DAML-LF archives on the participant node - return their hashes
    rpc ListPackages(google.protobuf.Empty) returns (ListPackagesResponse);

    // Lists all the modules in package on the participant node
    rpc ListPackageContents (ListPackageContentsRequest) returns (ListPackageContentsResponse);

    // Upload a DAML archive to the participant node
    rpc UploadPackage (UploadPackageRequest) returns (google.protobuf.Empty);

    // Obtain a Package by packageId -- for inspection & download
    rpc GetPackage (GetPackageRequest) returns (GetPackageResponse);

    // List all DARs on the participant node - return their hashes and filenames
    rpc ListDars(google.protobuf.Empty) returns (ListDarsResponse);

    // Upload a DAR file and all packages inside to the participant node
    rpc UploadDar (UploadDarRequest) returns (UploadDarResponse);

    // Obtain a DAR file by hash -- for inspection & download
    rpc GetDar(GetDarRequest) returns (GetDarResponse);

    // Share a DAR with another participant
    rpc Share(ShareRequest) returns (google.protobuf.Empty);

    // List requests this participant has made to share DARs with another participant
    rpc ListShareRequests(google.protobuf.Empty) returns (ListShareRequestsResponse);

    // List offers to share a DAR that this participant has received
    rpc ListShareOffers(google.protobuf.Empty) returns (ListShareOffersResponse);

    // Accept a DAR sharing offer (this will install the DAR into the participant)
    rpc AcceptShareOffer(AcceptShareOfferRequest) returns (google.protobuf.Empty);

    // Reject a DAR sharing offer
    rpc RejectShareOffer(RejectShareOfferRequest) returns (google.protobuf.Empty);

    // Add party to our DAR distribution whitelist
    rpc WhitelistAdd(WhitelistChangeRequest) returns (google.protobuf.Empty);

    // Remove party from our DAR distribution whitelist
    rpc WhitelistRemove(WhitelistChangeRequest) returns (google.protobuf.Empty);

    // List all parties currently on the whitelist
    rpc WhitelistList(google.protobuf.Empty) returns (WhitelistListResponse);
}

message ListPackageContentsRequest {
    string package_id = 1;
}

message ListPackageContentsResponse {
    repeated ModuleDescription modules = 1;
}

message ModuleDescription {
    string name = 1;
}

message ListPackagesResponse {
    repeated PackageDescription package_descriptions = 1;
}

message UploadPackageRequest {
    bytes archive = 1;
    string source_description = 2;
}

message ListDarsResponse {
    repeated DarDescription dars = 1;
}

message DarDescription {
    string hash = 1;
    string name = 2;
}

message UploadDarRequest {
    bytes data = 1;
    string filename = 2;
}

message UploadDarResponse {
    oneof value {
        Success success = 1;
        Failure failure = 2;
    }
    message Success {
        string hash = 1;
    }
    message Failure {
        string reason = 1;
    }
}

message GetDarRequest {
    string hash = 1;
}

message GetDarResponse {
    bytes data = 1;
    string name = 2;
}

message GetPackageRequest {
    string package_id = 1;
}

message GetPackageResponse {
    bytes archive = 1;
}

message DeactivatePackageRequest {
    string package_id = 1;
}

message ActivatePackageRequest {
    string package_id = 1;
}

message PackageDescription {
    string package_id = 1;
    string source_description = 3;
}

message ShareRequest {
    string dar_hash = 1;
    string recipient_id = 2;
}

message ListShareRequestsResponse {
    repeated Item share_requests = 1;

    message Item {
        string id = 1;
        string dar_hash = 2;
        string recipient_id = 3;
        string name = 4;
    }
}

message ListShareOffersResponse {
    repeated Item share_offers = 1;

    message Item {
        string id = 1;
        string dar_hash = 2;
        string owner_id = 3;
        string name = 4;
    }
}

message AcceptShareOfferRequest {
    string id = 1;
}

message RejectShareOfferRequest {
    string id = 1;
    // informational message explaining why we decided to reject the DAR
    // can be empty
    string reason = 2;
}

message WhitelistChangeRequest {
    string party_id = 1;
}

message WhitelistListResponse {
    repeated string party_ids = 1;
}
syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

import "google/protobuf/empty.proto";

service BroadcastPackageUsageService {
    // Wait until the service has updated all UsePackage contracts.
    rpc WaitUntilClean (google.protobuf.Empty) returns (google.protobuf.Empty);
}

Participant Status Service

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

import "google/protobuf/empty.proto";
import "google/protobuf/duration.proto";

service ParticipantStatusService {
    rpc GetStatus(google.protobuf.Empty) returns (StatusResponse);
}

message StatusResponse {
    string id = 1;
    google.protobuf.Duration uptime = 2;
    map<string, int32> ports = 3;
    repeated string connected_domains = 4;
}

Ping Pong Service

Canton uses a default simple ping-pong workflow to smoke-test a deployment.

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

service PingService {
    rpc ping(PingRequest) returns (PingResponse);
}

message PingRequest {

    repeated string target_parties = 1;
    repeated string validators = 2;
    uint64 timeout_milliseconds = 3;
    uint64 levels = 4;
    uint64 grace_period_milliseconds = 5;
    string workflow_id = 6; // optional
    string id = 7; // optional UUID to be used for ping test

}

message PingSuccess {
    uint64 ping_time = 1;
    string responder = 2;
}

message PingFailure {
}

message PingResponse {
    oneof response {
        PingSuccess success = 1;
        PingFailure failure = 2;
    }

}

Domain Connectivity Service

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

import "com/digitalasset/canton/protocol/v0/identity.proto";
import "com/digitalasset/canton/protocol/v0/sequencing.proto";

/**
 * Domain connectivity service for adding and connecting to domains
 *
 * The domain connectivity service allows to register to new domains and control the
 * participants domain connections.
 */
service DomainConnectivityService {
    // reconnect to domains
    rpc ReconnectDomains(ReconnectDomainsRequest) returns (ReconnectDomainsResponse);
    // configure a new domain connection
    rpc RegisterDomain(RegisterDomainRequest) returns (RegisterDomainResponse);
    // reconfigure a domain connection
    rpc ModifyDomain(ModifyDomainRequest) returns (ModifyDomainResponse);
    // connect to a configured domain
    rpc ConnectDomain(ConnectDomainRequest) returns (ConnectDomainResponse);
    // disconnect from a configured domain
    rpc DisconnectDomain(DisconnectDomainRequest) returns (DisconnectDomainResponse);
    // list connected domains
    rpc ListConnectedDomains(ListConnectedDomainsRequest) returns (ListConnectedDomainsResponse);
    // list configured domains
    rpc ListConfiguredDomains(ListConfiguredDomainsRequest) returns (ListConfiguredDomainsResponse);
    // Get the service agreement for the domain
    rpc GetAgreement(GetAgreementRequest) returns (GetAgreementResponse);
    // Accept the agreement of the domain
    rpc AcceptAgreement(AcceptAgreementRequest) returns (AcceptAgreementResponse);
}

message DomainConnectionConfig {
    // participant local identifier of the target domain
    string domain_alias = 1;
    // connection information to domain (http[s]://<host>:<port>")
    string connection = 2;
    // if false, then domain needs to be manually connected to (default false)
    bool manual_connect = 3;
    // optional essential state (if TLS isn't to be trusted)
    com.digitalasset.canton.protocol.v0.EssentialState essential_state = 4;
    // optional. if not using system certificates this should be the bytes of a X.509 certificate collection in PEM format chain.
    bytes certificates = 5;
    // optional. Influences whether the participant submits to this domain, if several domains are eligible
    int32 priority = 6;
    // defines how the participant chooses the sequencer connection to use in case there are more than one sequencers available
    com.digitalasset.canton.protocol.v0.SequencerConnectionSelectionPolicy sequencerSelectionPolicy = 7;
}

message ReconnectDomainsRequest {

}
message ReconnectDomainsResponse {

}

/** Register and optionally auto-connect to a new domain */
message RegisterDomainRequest {
    DomainConnectionConfig add = 1;
}

message RegisterDomainResponse {

}

message ModifyDomainRequest {
    DomainConnectionConfig modify = 1;
}

message ModifyDomainResponse {

}

message ListConfiguredDomainsRequest {

}

message ListConfiguredDomainsResponse {
    message Result {
        DomainConnectionConfig config = 1;
        bool connected = 2;
    }
    repeated Result results = 1;
}

message ConnectDomainRequest {
    string domain_alias = 1;
}

message ConnectDomainResponse {
}

message DisconnectDomainRequest {
    string domain_alias = 1;
}

message DisconnectDomainResponse {
}

message ListConnectedDomainsRequest {
}

message ListConnectedDomainsResponse {
    message Result {
        string domain_alias = 1;
        string domain_id = 2;
    }
    repeated Result connected_domains = 1;
}

message GetAgreementRequest {
    string domain_alias = 1;
}

message GetAgreementResponse {
    Agreement agreement = 1;
    bool accepted = 2;
}

message Agreement {
    string id = 1;
    string text = 2;
}

message AcceptAgreementRequest {
    string domain_alias = 1;
    string agreement_id = 2;
}

message AcceptAgreementResponse {
}

Party Name Management Service

/*
 * Copyright 2020 Digital Asset (Switzerland) GmbH and/or its affiliates
 *
 * SPDX-License-Identifier: Apache-2.0
 */

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

/**
  * Local participant service allowing to set the display name for a party
  *
  * The display name is a local property to the participant. The participant is encouraged to perform
  * a DAML based KYC process and add some automation which will update the display names based
  * on the desired update rules.
  *
  * As such, this function here just offers the bare functionality to perform this.
  */
service PartyNameManagementService {
    rpc setPartyDisplayName(SetPartyDisplayNameRequest) returns (SetPartyDisplayNameResponse);
}

message SetPartyDisplayNameRequest {
    string party_id = 1;
    string display_name = 2;
}

message SetPartyDisplayNameResponse {

}

Inspection Service

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

/**
 * Inspection Service
 *
 * Supports inspecting the Participant for details about its ledger.
 * This contains only a subset of the ParticipantInspection commands that can run over the admin-api instead of requiring
 * direct access to the participant node instance.
 */
service InspectionService {
    // Lookup the domain where a contract is currently active.
    // Supports querying many contracts at once.
    rpc LookupContractDomain(LookupContractDomain.Request) returns (LookupContractDomain.Response);
    // Lookup the domain that the transaction was committed over. Can fail with NOT_FOUND if no domain was found.
    rpc LookupTransactionDomain(LookupTransactionDomain.Request) returns (LookupTransactionDomain.Response);
}

message LookupContractDomain {
    message Request {
        // set of contract ids to lookup their active domain aliases.
        repeated string contract_id = 1;
    }

    message Response {
        // map of contract id to domain alias.
        // if a request contract id from the request is missing from this map it indicates that the contract was not
        // active on any current domain.
        map<string, string> results = 1;
    }
}

message LookupTransactionDomain {
    message Request {
        // the transaction to look up
        string transaction_id = 1;
    }

    message Response {
        // the domain that the transaction was committed over
        string domain_id = 1;
    }
}

Transfer Service

syntax = "proto3";

package com.digitalasset.canton.participant.admin.v0;

import "google/protobuf/timestamp.proto";
import "com/digitalasset/canton/protocol/v0/synchronization.proto";

// Supports transferring contracts from one domain to another
service TransferService {
    // transfer out a contract
    rpc TransferOut (AdminTransferOutRequest) returns (AdminTransferOutResponse);

    // transfer-in a contract
    rpc TransferIn (AdminTransferInRequest) returns (AdminTransferInResponse);

    // return the in-flight transfers on a given participant for a given target domain
    rpc TransferSearch (AdminTransferSearchQuery) returns (AdminTransferSearchResponse);
}

message AdminTransferOutRequest {
    string submitting_party = 1;
    string contract_id = 2;
    string origin_domain = 3;
    string target_domain = 4;
}

message AdminTransferOutResponse {
    com.digitalasset.canton.protocol.v0.TransferId transfer_id = 1;
}

message AdminTransferInRequest {
    string submitting_party_id = 1;
    string target_domain = 2;
    com.digitalasset.canton.protocol.v0.TransferId transfer_id = 3;
}

message AdminTransferInResponse {

}

message AdminTransferSearchQuery {
    string search_domain = 1;
    string filter_origin_domain = 2; // exact match if non-empty
    google.protobuf.Timestamp filter_timestamp = 3; // optional; exact match if set
    string filter_submitting_party = 4;
    int64 limit = 5;
}

message AdminTransferSearchResponse {
    repeated TransferSearchResult results = 1;

    message TransferSearchResult {
        string contract_id = 1;
        com.digitalasset.canton.protocol.v0.TransferId transfer_id = 2;
        string origin_domain = 3;
        string target_domain = 4;
        string submitting_party = 5;
        bool ready_for_transfer_in = 6;
    }
}

Domain Admin APIs

The domain exposes the following admin-api services:

Domain Identity Manager Service

syntax = "proto3";

package com.digitalasset.canton.domain.admin.v0;

import "google/protobuf/empty.proto";
import "com/digitalasset/canton/protocol/v0/identity.proto";


/**
 * The Domain identity manager service
 *
 * This service is used to extend the basic identity manager service with domain specific operations on the
 * identity state.
 */
service DomainIdentityManagerService {
    /**
     * Set the state of a participant on the given domain.
     */
    rpc SetParticipantState(com.digitalasset.canton.protocol.v0.ParticipantState) returns (google.protobuf.Empty);

    /**
     * Download the essential state from this identity manager
     */
    rpc GetEssentialState(google.protobuf.Empty) returns (com.digitalasset.canton.protocol.v0.EssentialState);

    /**
     * Download the authorized essential state (based on transactions that have been stored by the identity managed but not yet sequenced)
     */
    rpc GetAuthorizedEssentialState(google.protobuf.Empty) returns (com.digitalasset.canton.protocol.v0.EssentialState);

}

Domain Status Service

syntax = "proto3";

package com.digitalasset.canton.domain.admin.v0;

import "google/protobuf/empty.proto";
import "google/protobuf/duration.proto";

service DomainStatusService {
    rpc GetStatus(google.protobuf.Empty) returns (StatusResponse);
}

message StatusResponse {
    string id = 1;
    google.protobuf.Duration uptime = 2;
    map<string, int32> ports = 3;
    repeated string connected_participants = 4;
}

Identity Admin APIs

Both, domain and participant nodes expose the following services:

Vault Management Service

syntax = "proto3";

package com.digitalasset.canton.identity.admin.v0;

import "com/digitalasset/canton/protocol/v0/identity.proto";

/**
 * Vault service providing programmatic access to locally stored keys and certificates
 *
 * We have two key-stores: a private key store where we are storing our pairs of
 * public and private keys and a public key store where we are storing other
 * public keys that we learned.
 *
 * We learn public key stores in different ways: either by importing them or
 * by picking them up from internal sources (such as identity management updates).
 *
 * The only purpose of the public key store (where we import foreign keys) is convenience for
 * identity management such that when we add identity management transactions, we can refer to
 * fingerprints in commands while building them rather than having to attach public-key files.
 *
 * In addition, we also provide access to the locally stored certificates which are used
 * either by the HTTP/1.1 sequencer client or for legal identity claims.
 */
service VaultService {

    /**
     * List public keys according to request filter for which we have a private key in our key vault.
     *
     * The request includes a filter for fingerprints which can be used for lookups.
     *
     * @param ListMyKeysRequest: request with optional fingerprint filter
     * @return: all serialized keys and their fingerprints that have the fingerprint filter as a substring in their fingerprint
     */
    rpc ListMyKeys(ListKeysRequest) returns (ListKeysResponse);

    /**
     * Generates a new public / private key
     *
     * Stores the private key in the vault, and returns the public key
     */
    rpc GenerateKey(GenerateKeyRequest) returns (KeyResult);

    /**
     * Import a public key into the registry in order to provide that Fingerprint -> PublicKey lookups
     *
     * @param: ImportPublicKeyRequest serialized public key to be imported
     * @return: fingerprint and serialized public key of imported public key
     */
    rpc ImportPublicKey(ImportPublicKeyRequest) returns (ImportPublicKeyResponse);
    /**
     * Lists all public keys matching the supplied filter which are internally cached
     *
     * Any public key returned here can be referenced in identity transaction building
     * by fingerprint.
     */
    rpc ListPublicKeys(ListKeysRequest) returns (ListKeysResponse);

    /**
     * Import a X509 certificate into the local vault.
     */
    rpc ImportCertificate(ImportCertificateRequest) returns (ImportCertificateResponse);

    /**
     * Create a new, self-signed certificate with CN=unique_identifier
     */
    rpc GenerateCertificate(GenerateCertificateRequest) returns (GenerateCertificateResponse);

    /**
     * List certificates stored in the local vault
     */
    rpc ListCertificates(ListCertificateRequest) returns (ListCertificateResponse);

}

message GenerateCertificateRequest {
    // unique identifier to be used for CN
    string unique_identifier = 1;
    // the private key fingerprint to use for this certificate
    string certificate_key = 2;
    // the additional subject names to be added to this certificate
    string subject = 3;
    // which SANs should be added
    repeated string subject_alternative_names = 4;
}

message GenerateCertificateResponse {
    // the certificate in PEM format
    string x509_cert = 1;
}

message ListCertificateRequest {
    string filterUid = 1;
}

message ListCertificateResponse {
    message Result {
        string x509_cert = 1;
    }
    repeated Result results = 1;
}

message ImportCertificateRequest {
    // X509 certificate as PEM
    string x509_cert = 1;
}

message ImportCertificateResponse {
    string certificate_id = 1;
}


message ImportPublicKeyRequest {
    // import a result of a previous PublicKey.serialize invocation
    bytes public_key = 1;
    // a context string that should be stored along side the key
    string context = 2;
}

message ImportPublicKeyResponse {
    // fingerprint of imported key
    string fingerprint = 1;
}

message KeyResult {
    // the fingerprint of the search
    string fingerprint = 1;
    // the context string associated with the key
    string context = 2;
    // the serialized version (which can be used to import it at another place)
    bytes public_key = 3;
    // the purposes of the key (signing/encryption)
    repeated com.digitalasset.canton.protocol.v0.KeyPurpose purposes = 4;
    // the key scheme used (during generation).
    // TODO(i3816): make this available for stored keys, not just on generation
    string key_Scheme = 5;
}

message ListKeysRequest {
    // the substring that needs to match a given fingerprint
    string filter_fingerprint = 1;
    // the substring to filter the context string
    string filter_context = 2;
    // the purposes that the key should support
    repeated com.digitalasset.canton.protocol.v0.KeyPurpose purposes = 3;
}

message ListKeysResponse {
    // repetitive result type of list keys response
    repeated KeyResult results = 1;
}

message GenerateKeyRequest {
    // human readable free style description associated with key
    string context = 1;
    // purpose of key. if more than one purpose can be given depends on crypto implementation
    repeated com.digitalasset.canton.protocol.v0.KeyPurpose purposes = 2;
    // key scheme to be used. use "EcDsaP384Raw" for keys you want to use the key for X509 certificates
    // and leave empty otherwise to use the wise and secure internal selection
    string key_scheme = 3;
}

Initialization Service

The one time initialization service, used to setup the identity of a node.

syntax = "proto3";

package com.digitalasset.canton.identity.admin.v0;

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

/**
 * The node initialization service
 */
service InitializationService {

    /**
     * Initialize the node with the unique identifier (can and must be done once)
     *
     * When a domain or participant instance starts for the first time, we need to bind it
     * to a globally unique stable identifier before we can continue with the
     * initialization procedure.
     *
     * This method is only used once during initialization.
     */
    rpc InitId(InitIdRequest) returns (InitIdResponse);


    /**
     * Returns the id of the node (or empty if not initialized)
     */
    rpc GetId(google.protobuf.Empty) returns (GetIdResponse);


    /**
     * Returns the current time of the node (used for testing with static time)
     */
    rpc CurrentTime(google.protobuf.Empty) returns (google.protobuf.Timestamp);

}

message InitIdRequest {
    string identifier = 1;
    string fingerprint = 2;
}

message InitIdResponse {
    string unique_identifier = 1;
}

message GetIdResponse {
    bool initialized = 1;
    string unique_identifier = 2;
}

Identity Aggregation Service

Aggregated view of the sequenced domain identity state.

syntax = "proto3";

package com.digitalasset.canton.identity.admin.v0;

import "com/digitalasset/canton/protocol/v0/identity.proto";
import "google/protobuf/timestamp.proto";

/**
 * Identity information aggregation service
 *
 * This service allows deep inspection into the aggregated identity state.
 * The services runs both on the domain and on the participant and uses the same
 * data. The service provides GRPC access to the information aggregated by the identity providing
 * service client.
 */
service IdentityAggregationService {

    /**
      * Obtain information about a certain set of active parties matching a given filter criterion.
      *
      * The request allows to filter per (domain, party, asOf) where the domain and party argument are
      * used in order to filter the result list using the `startsWith` method on the respective resulting string.
      *
      * As such, if you just need to do a lookup, then define a precise filter. Given the uniqueness of the
      * identifiers (and the fact that the identifiers contain key fingerprints), we should only ever get a single
      * result back if we are doing a precise lookup.
      *
      * The response is a sequence of tuples (party, domain, participant, privilege, trust-level).
      * The response is restricted to active active and their active participants.
      */
    rpc ListParties (ListPartiesRequest) returns (ListPartiesResponse);

    /**
      * Obtain key owner information matching a given filter criterion.
      *
      * Key owners in the system are different types of entities: Participant, Mediator, Domain Identity Manager and
      * Sequencer. The present method allows to define a filter to search for a key owner
      * using filters on (asOf, domain, ownerType, owner)
      *
      * The response is a sequence of (domain, ownerType, owner, keys) where keys is a sequence of
      * (fingerprint, bytes, key purpose). As such, we can use this method to export currently used signing or encryption
      * public keys.
      *
      * This method is quite general, as depending on the arguments, very different results can be obtained.
      *
      * Using OwnerType = 'Participant' allows to query for all participants.
      * Using OwnerType = 'Sequencer' allows to query for all sequencers defined.
      */
    rpc ListKeyOwners (ListKeyOwnersRequest) returns (ListKeyOwnersResponse);
}

message ListPartiesRequest {
    google.protobuf.Timestamp as_of = 1;
    string filter_domain = 2;
    string filter_party = 3;
    string filter_participant = 4;
}

message ListPartiesResponse {
    message Result {
        string party = 1;
        message ParticipantDomains {
            message DomainPermissions {
                string domain = 1;
                com.digitalasset.canton.protocol.v0.ParticipantPermission permission = 2;
            }
            string participant = 1;
            repeated DomainPermissions domains = 2;
        }
        repeated ParticipantDomains participants = 2;
    }
    repeated Result results = 2;
}

message ListKeyOwnersRequest {
    google.protobuf.Timestamp as_of = 1;
    string filter_domain = 2;
    string filter_key_owner_type = 3;
    string filter_key_owner_uid = 4;
}

message ListKeyOwnersResponse {
    message Result {
        message Key {
            string fingerprint = 1;
            bytes public_key = 2;
            com.digitalasset.canton.protocol.v0.KeyPurpose purpose = 3;
        }
        string domain = 1;
        string key_owner = 2;
        repeated Key keys = 3;
    }
    repeated Result results = 1;
}

Identity Manager Read Service

Raw access to the underlying identity transactions.

syntax = "proto3";

package com.digitalasset.canton.identity.admin.v0;

import "com/digitalasset/canton/protocol/v0/identity.proto";
import "google/protobuf/timestamp.proto";


// domain + idm + participant
service IdentityManagerReadService {
    rpc ListAvailableStores(ListAvailableStoresRequest) returns (ListAvailableStoresResult);
    rpc ListPartyToParticipant(ListPartyToParticipantRequest) returns (ListPartyToParticipantResult);
    rpc ListOwnerToKeyMapping(ListOwnerToKeyMappingRequest) returns (ListOwnerToKeyMappingResult);
    rpc ListNamespaceDelegation(ListNamespaceDelegationRequest) returns (ListNamespaceDelegationResult);
    rpc ListIdentifierDelegation(ListIdentifierDelegationRequest) returns (ListIdentifierDelegationResult);
    rpc ListSignedLegalIdentityClaim(ListSignedLegalIdentityClaimRequest) returns (ListSignedLegalIdentityClaimResult);
    rpc ListParticipantState(ListParticipantStateRequest) returns (ListParticipantStateResult);
}

message ListNamespaceDelegationRequest {
    BaseQuery base_query = 1;
}

message ListNamespaceDelegationResult {
    message Result {
        BaseResult context = 1;
        com.digitalasset.canton.protocol.v0.NamespaceDelegation item = 2;
        string target_key_fingerprint = 3;
    }
    repeated Result results = 1;
}

message ListIdentifierDelegationRequest {
    BaseQuery base_query = 1;
}

message ListIdentifierDelegationResult {
    message Result {
        BaseResult context = 1;
        com.digitalasset.canton.protocol.v0.IdentifierDelegation item = 2;
        string target_key_fingerprint = 3;
    }
    repeated Result results = 1;
}

message BaseQuery {
    string filter_store = 1;
    google.protobuf.Timestamp from = 2;
    google.protobuf.Timestamp until = 3;
    enum ResultType {
        MISSING_RESULT_TYPE = 0;
        ALL = 1;
        ADD = 2;
        REMOVE = 3;
        ACTIVE = 4;
    }
    ResultType filter_type = 4;
    string filter_signed_key = 5;
}

message BaseResult {
    string store = 1;
    google.protobuf.Timestamp timestamp = 2;
    com.digitalasset.canton.protocol.v0.IdentityChangeOp operation = 3;
    bytes serialized = 4;
    string signed_by_fingerprint = 5;
}

message ListPartyToParticipantResult {
    message Result {
        BaseResult context = 1;
        com.digitalasset.canton.protocol.v0.PartyToParticipant item = 2;
    }
    repeated Result results = 2;
}

message ListPartyToParticipantRequest {
    BaseQuery base_query = 1;
    string filter_party = 2;
    string filter_participant = 3;
    message FilterRequestSide {
        com.digitalasset.canton.protocol.v0.RequestSide value = 1;
    }
    FilterRequestSide filter_request_side = 4;
    message FilterPermission {
        com.digitalasset.canton.protocol.v0.ParticipantPermission value = 1;
    }
    FilterPermission filter_permission = 5;
}

message ListOwnerToKeyMappingRequest {
    BaseQuery base_query = 1;
    string filter_key_owner_type = 2;
    string filter_key_owner_uid = 3;
    message FilterKeyPurpose {
        com.digitalasset.canton.protocol.v0.KeyPurpose value = 1;
    }
    FilterKeyPurpose filter_key_purpose = 4;
}

message ListOwnerToKeyMappingResult {
    message Result {
        BaseResult context = 1;
        com.digitalasset.canton.protocol.v0.OwnerToKeyMapping item = 2;
        string key_fingerprint = 3;
    }
    repeated Result results = 1;
}

message ListSignedLegalIdentityClaimRequest {
    BaseQuery base_query = 1;
    string filter_uid = 2;
}

message ListSignedLegalIdentityClaimResult {
    message Result {
        BaseResult context = 1;
        com.digitalasset.canton.protocol.v0.SignedLegalIdentityClaim item = 2;
    }
    repeated Result results = 1;
}

message ListAvailableStoresRequest {

}
message ListAvailableStoresResult {
    repeated string store_ids = 1;
}

message ListParticipantStateRequest {
    string filter_store = 1;
    google.protobuf.Timestamp from = 2;
    google.protobuf.Timestamp until = 3;
    bool active_only = 4;
    string filter_participant = 5;
}

message ListParticipantStateResult {
    message Result {
        string store = 1;
        google.protobuf.Timestamp timestamp = 2;
        bool is_active = 3;
        com.digitalasset.canton.protocol.v0.ParticipantState participant_state = 4;
    }
    repeated Result results = 1;
}

Identity Manager Write Service

syntax = "proto3";

package com.digitalasset.canton.identity.admin.v0;

import "com/digitalasset/canton/protocol/v0/identity.proto";

/**
 * Write operations on the local identity manager.
 *
 * Both, participant and domain run a local identity manager exposing the same write interface.
 */
service IdentityManagerWriteService {

    /**
     * Authorizes a party to participant mapping change (add/remove) on the node local identity manager.
     */
    rpc AuthorizePartyToParticipant(PartyToParticipantAuthorization) returns (AuthorizationSuccess);

    /**
     * Authorizes an owner to key mapping change (add/remove) on the local identity manager
     */
    rpc AuthorizeOwnerToKeyMapping(OwnerToKeyMappingAuthorization) returns (AuthorizationSuccess);

    /**
     * Authorizes a namespace delegation (root or intermediate CA) (add/remove) on the local identity manager
     */
    rpc AuthorizeNamespaceDelegation(NamespaceDelegationAuthorization) returns (AuthorizationSuccess);

    /**
     * Authorizes a new identifier delegation (identifier certificate) (add/remove) on the local identity manager
     */
    rpc AuthorizeIdentifierDelegation(IdentifierDelegationAuthorization) returns (AuthorizationSuccess);

    /**
     * Authroizes a new signed legal identity
     */
    rpc AuthorizeSignedLegalIdentityClaim(SignedLegalIdentityClaimAuthorization) returns (AuthorizationSuccess);

    /**
     * Adds a signed identity transaction to the Authorized store
     */
    rpc AddSignedIdentityTransaction(SignedIdentityTransactionAddition) returns (AdditionSuccess);

    /**
     * Generates a legal identity claim
     */
    rpc GenerateSignedLegalIdentityClaim(SignedLegalIdentityClaimGeneration) returns (com.digitalasset.canton.protocol.v0.SignedLegalIdentityClaim);

}

message AuthorizationSuccess {
    bytes serialized = 1;
}

message AdditionSuccess {

}

message SignedIdentityTransactionAddition {
    bytes serialized = 1;
}

message AuthorizationData {

    /** Add / Remove */
    com.digitalasset.canton.protocol.v0.IdentityChangeOp change = 1;

    /**
     * Fingerprint of the key signing the authorization
     *
     * The signing key is used to identify a particular `NamespaceDelegation` or `IdentifierDelegation` certificate,
     * which is used to justify the given authorization.
     */
    string signed_by = 2;
}

message NamespaceDelegationAuthorization {
    AuthorizationData authorization = 1;

    // The namespace for which the authorization is issued.
    string namespace = 2;

    /**
     * The fingerprint of the signing key which will be authorized to issue identity transactions for this namespace.
     *
     * The key needs to be present in the local key registry either by being locally
     * generated or by having been previously imported.
     */
    string fingerprint_of_authorized_key = 3;

    /**
     * Flag indicating whether authorization is a root key delegation
     */
    bool is_root_delegation = 4;
}

message IdentifierDelegationAuthorization {
    AuthorizationData authorization = 1;
    string identifier = 2;

    /**
     * The fingerprint of the signing key which will be authorized to issue identity transaction for this particular identifier.
     *
     * As with `NamespaceDelegation`s, the key needs to be present locally.
     */
    string fingerprint_of_authorized_key = 3;
}

message PartyToParticipantAuthorization {
    AuthorizationData authorization = 1;
    /**
     * The request side of this transaction
     *
     * A party to participant mapping can map a party from one namespace on a participant from another namespace.
     * Such a mapping needs to be authorized by both namespace keys. If the namespace is the same, we use
     * RequestSide.Both and collapse into a single transaction. Otherwise, `From` needs to be signed by a namespace key
     * of the party and `To` needs to be signed by a namespace key of the participant.
     */
    com.digitalasset.canton.protocol.v0.RequestSide side = 2;

    // The unique identifier of the party
    string party = 3;
    // The unique identifier of the participant
    string participant = 4;
    // The permission of the participant that will allow him to act on behalf of the party.
    com.digitalasset.canton.protocol.v0.ParticipantPermission permission = 5;
}

message OwnerToKeyMappingAuthorization {

    AuthorizationData authorization = 1;

    /**
     * The key owner
     *
     * An entity in Canton is described by his role and his unique identifier. As such, the same unique identifier
     * can be used for a mediator, sequencer, domain identity manager or even participant. Therefore, we expect
     * here the protoPrimitive of a key owner which is in effect its type as a three letter code separated
     * from the unique identifier.
     */
    string key_owner = 2;


    /**
     * The fingerprint of the key that will be authorized
     *
     * The key needs to be present in the local key registry (can be imported via KeyService)
     */
    string fingerprint_of_key = 3;

    /**
     * Purpose of the key
     */
    repeated com.digitalasset.canton.protocol.v0.KeyPurpose purposes = 4;
}

message SignedLegalIdentityClaimAuthorization {
    AuthorizationData authorization = 1;
    com.digitalasset.canton.protocol.v0.SignedLegalIdentityClaim claim = 2;
}

message SignedLegalIdentityClaimGeneration {
    message X509CertificateClaim {
        string unique_identifier = 1;
        string certificate_id = 2;
    }
    oneof request {
        com.digitalasset.canton.protocol.v0.LegalIdentityClaim claim = 1;
        X509CertificateClaim certificate = 2;
    }
}

Mediator Admin APIs

Standalone Mediator nodes expose the following services:

Mediator Initialization Service

Service to initialize an external Mediator to participate in confirming transaction results. Only expected to be called by the Domain node to allow the Mediator to connect to the domain Sequencer.

/*
 * Copyright 2020 Digital Asset (Switzerland) GmbH and/or its affiliates
 *
 * SPDX-License-Identifier: Apache-2.0
 */

syntax = "proto3";

package com.digitalasset.canton.domain.admin.v0;

import "com/digitalasset/canton/protocol/v0/sequencing.proto";
import "com/digitalasset/canton/protocol/v0/identity.proto";

service MediatorInitializationService {

  // Initialize a Mediator service
  // If the Mediator is uninitialized it should initialize itself with the provided configuration
  // If the Mediator is already initialized then verify the request is for the domain we're running against,
  // if correct then just return the current key otherwise fail.
  rpc Initialize (InitializeMediatorRequest) returns (InitializeMediatorResponse);

}

message InitializeMediatorRequest {
  // version the domain node/manager is running (mediator needs to be compatible with this version)
  string domain_version = 1;
  // the domain identifier (should become the mediator id)
  string domain_id = 2;
  // crypto provider used by the domain node (mediator must be compatible to operate on the domain)
  string crypto_type = 3;
  // domain essential state - should contain appropriate keys for the domain identity manager and sequencers
  com.digitalasset.canton.protocol.v0.EssentialState essential_state = 4;
  // parameters for the domain
  com.digitalasset.canton.protocol.v0.DomainParameters domain_parameters = 5;
  // how should the member connect to the domain sequencer
  // at least one connection config has to be defined
  // and it is up to the member to choose which one to use
  repeated com.digitalasset.canton.protocol.v0.SequencerConnectionConfig sequencer_connections = 6;
}

message InitializeMediatorResponse {
  oneof value {
    Success success = 1;
    Failure failure = 2;
  }

  message Success {
    // Current signing key
    bytes mediator_key = 1;
  }

  message Failure {
    // Reason that can be logged
    string reason = 1;
  }
}