Setting up a Canton OSS subnet leveraging on release 3.4.7

I’ve been trying to set up a docker-compose which assembles each component of Canton OSS (Sequencer, Mediator and Participant) as separate services.

I’ve managed to create a structure which has one Dockerfile for each component and respective conf file. The bootstrap/init files are still in the works, while trying to leverage on the console to build them, but the rest seems to be working standalone. However, I’m facing challenges finding the right way to connect all of these components together.

One such oddities is the following:

The mediator I’ve setup is not called mediator1 nor is it supposed to be connected to a local sequencer or a sandbox participant. These values make little sense given what I’ve configured and I’m wondering whether something is being overriden or how I should interpret these results.

Please note that so far the bootstrap files only have the following line

nodes.local.start()

I’ve also tried to connect with a remote configuration instead of using the sandbox-console and then when trying to list nodes I’m getting the same results.

I’ve also seen a few discrepancies between documentation and the config files under the canton release. E.g. there are references of a manager.conf in some docs ( Install Canton — Daml SDK 2.10.2 documentation , Install Canton — Digital Asset’s platform documentation) which I assume referred to the topology manager, yet the sample config files from the release zip or tar.gz seem to have no mention on them. I’m wondering if they’re needed or not.

I’ll post below a few of the snippets of code I’ve been running and any support or clarification on how to complete this setup, or whether this is not possible on OSS, is welcome.

Dockerfile.mediator

# Canton Domain Dockerfile (Mediator)
FROM eclipse-temurin:21-jdk-jammy

# Install dependencies
RUN apt-get update && apt-get install -y \
    curl \
    wget \
    unzip \
    && rm -rf /var/lib/apt/lists/*

# Download and install Canton
ARG CANTON_VERSION=3.4.7
WORKDIR /opt

RUN wget https://github.com/digital-asset/canton/releases/download/v${CANTON_VERSION}/canton-open-source-${CANTON_VERSION}.tar.gz && \
    tar -xzf canton-open-source-${CANTON_VERSION}.tar.gz && \
    mv canton-open-source-${CANTON_VERSION} canton && \
    rm canton-open-source-${CANTON_VERSION}.tar.gz

# Create Canton directories
RUN mkdir -p /canton/config /canton/init /canton/data

# Copy configuration files
COPY config/mediator.conf /canton/config/

# Set permissions
RUN chmod -R 755 /canton

WORKDIR /canton

# Expose ports
# 10042 - Admin API
# 10043 - grpc-health-server
# 10044 - http-health-server
EXPOSE 10042 10043 10044

# Start Canton domain with configuration
CMD ["/opt/canton/bin/canton", "daemon", "-c", "/canton/config/mediator.conf", "--bootstrap", "/canton/init/mediator.canton"]

mediator.conf

include required("shared.conf")

canton.mediators.mediator {

    storage = ${_shared.storage}
    storage.config.properties.databaseName = "canton_mediator"

    admin-api {
        address = 0.0.0.0
        port = 10042
    }

    monitoring {
        grpc-health-server {
            address = 0.0.0.0
            port = 10043
        }
        http-health-server {
            address = 0.0.0.0
            port = 10044
        }
    }
}

Dockerfile.sequencer

# Canton Domain Dockerfile (Sequencer)
FROM eclipse-temurin:21-jdk-jammy

# Install dependencies
RUN apt-get update && apt-get install -y \
    curl \
    wget \
    unzip \
    && rm -rf /var/lib/apt/lists/*

# Download and install Canton
ARG CANTON_VERSION=3.4.7
WORKDIR /opt

RUN wget https://github.com/digital-asset/canton/releases/download/v${CANTON_VERSION}/canton-open-source-${CANTON_VERSION}.tar.gz && \
    tar -xzf canton-open-source-${CANTON_VERSION}.tar.gz && \
    mv canton-open-source-${CANTON_VERSION} canton && \
    rm canton-open-source-${CANTON_VERSION}.tar.gz

# Create Canton directories
RUN mkdir -p /canton/config /canton/init /canton/data

# Copy configuration files
COPY config/sequencer.conf /canton/config/

# Set permissions
RUN chmod -R 755 /canton

WORKDIR /canton

# Expose ports
# 10038 - Public API
# 10039 - Admin API
# 10033 - grpc-health-server
# 10034 - http-health-server
EXPOSE 10038 10039 10033 10034

# Start Canton domain with configuration
CMD ["/opt/canton/bin/canton", "daemon", "-c", "/canton/config/mediator.conf", "--bootstrap", "/canton/init/sequencer.canton"]

sequencer.conf

include required("shared.conf")

canton.sequencers.sequencer {

    storage = ${_shared.storage}
    storage.config.properties.databaseName = "canton_sequencer"

    public-api {
        address = 0.0.0.0
        port = 10038
    }

    admin-api {
        address = 0.0.0.0
        port = 10039
    }

    sequencer {
        type = BFT
        block {
          writer = ${?_shared.sequencer-writer}
          reader = ${?_shared.sequencer-reader}
          writer.type = high-throughput
        }
    }

    monitoring {
        grpc-health-server {
            address = 0.0.0.0
            port = 10033
        }
        http-health-server {
            address = 0.0.0.0
            port = 10034
        }
    }
}

docker-compose.yml

services:
  # PostgreSQL database for Canton
  postgres:
    image: postgres:17.6
    container_name: retvn-postgres
    environment:
      POSTGRES_DB: canton
      POSTGRES_USER: canton
      POSTGRES_PASSWORD: *****
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U canton"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - retvn-network

  # Canton sequencer (sequencer)
  canton-sequencer:
    build:
      context: ./docker/canton
      dockerfile: Dockerfile.sequencer
    container_name: retvn-canton-sequencer
    ports:
      - 10038:10038 # Public API
      - 10039:10039 # Admin API
      - 10033:10033 #  grpc-health-server
      - 10034:10034 #  http-health-server
    environment:
      CANTON_DB_HOST: postgres
      CANTON_DB_PORT: 5432
      CANTON_DB_NAME: canton-sequencer
      CANTON_DB_USER: canton
      CANTON_DB_PASSWORD: *****
    volumes:
      - ./docker/canton/config:/canton/config
      - ./docker/canton/init:/canton/init
      - canton_domain_data:/canton/data
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - retvn-network

  # Canton mediator (mediator)
  canton-mediator:
    build:
      context: ./docker/canton
      dockerfile: Dockerfile.mediator
    container_name: retvn-canton-mediator
    ports:
      - 10042:10042  # Admin API
      - 10043:10043  # 
      - 10044:10044  #
    environment:
      CANTON_DB_HOST: postgres
      CANTON_DB_PORT: 5432
      CANTON_DB_NAME: canton-mediator
      CANTON_DB_USER: canton
      CANTON_DB_PASSWORD: *****
    volumes:
      - ./docker/canton/config:/canton/config
      - ./docker/canton/init:/canton/init
      - canton_domain_data:/canton/data
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - retvn-network

volumes:
  postgres_data:
    driver: local
  canton_domain_data:
    driver: local

networks:
  retvn-network:
    driver: bridge

Are you aware of the LocalNet Docker Compose resource? Its configuration files may serve as a guide for some of the questions you are working through.

I wasn’t looking on such a direction, primarily as I wanted to build first a permissioned network, not connected immediately to the Canton Network. My understanding is that splice is focused on the latter. I do want to explore it at some moment, but for now that was not my focus. Is this something that is not supported by the Canton protocol in its latest versions? Should I fallback to 2.X versions if I want to continue on such direction?

Just to be clear, the the LocalNet Docker Compose resource does not connect to the Canton Network’s Global Synchronizer. It is standalone. That is why you may find it useful in your exercise.

Regarding a private, subnet synchronizer, the DA product and engineering teams are still focused on the Global Synchronizer. Improving functionality and docs for private, subnet synchronizers is in the backlog.

That’s a tough call. We cannot give you a date for subnet support in 3.x. If you are trying to go to production “soon,” then you would need to go with 2.x. If you proceed with 2.x, avoid Daml contract keys for now.

I’ve fallen back on leveraging the sandbox for the 3.4 version. Was just struggling as well to put it to work through docker with network access from the host machine.

The key was finding the way to pass the right configurations to enable that with the daml sandbox command -C canton.participants.sandbox.ledger-api.address=0.0.0.0 -C canton.participants.sandbox.http-ledger-api.server.address=0.0.0.0.

For the moment that will suffice.

Thanks

1 Like