Skip to content

Execution Engines

Execution Engines are specialized nodes that detect and run designated off-chain components embedded in smart contracts. Execution Engines runs the Off-Chain Component in an asynchronous manner on a server distinct from the blockchain.

When you boot a deployment of the platform, it includes four Execution Engine nodes which listen to all public contracts.

This article explains how to run Execution Engines.

Execution Engine Configuration

Execution Engines share the same configuration, which enables them to act as contract-listening servers.

The configuration contains fields for:

  • Listening to the blockchain: "readerNodeEndpoint", "tcpReaderAddresses" (The flooding network addresses of reader nodes to listen to for contract updates). These allow the engine to track contract updates and blockchain state changes. The "tcpReaderAddresses" have the format base64_pubkey:host:port, and in particular contains the public keys corresponding to the readers' externalListenerKey.
  • Interacting with the blockchain: "transactionPrivateKey". This sets the identity of the engine on the blockchain, and is used for authentication, both with the blockchain, and with the smart contract.
  • Being interacted with by users over HTTP: "restEndpointPort". Allows the engine to receive HTTP requests.
  • Interacting with other engines over TCP: "tcpNetworkPrivateKey", and "engineNetworkTcpAddress" are used for communication between execution engine nodes.
  • Specifying contracts to run: "contractFilter". The field specifies which contracts the node should listen to, either contract addresses or contract types, for example "ZK", "SYSTEM" or "PUBLIC", or a combination of these.

You can read more about these configuration parameters in the javadoc documentation.

Execution Engine configuration example
{
    "restEndpointPort": "8400",
    "readerNodeEndpoint": "http://reader-node:9432",
    "storagePath": "target/reader",
    "tcpReaderAddresses": ["AyIQ/K5j8m6Xp8+HjiA7ffVbQRzVgtWjUvLgBabn8b+G:reader-node:9111"],
    "transactionPrivateKey": "0123456789ABCDEF",
    "tcpNetworkPrivateKey": "FF0123456789ABCDEF",
    "engineNetworkTcpAddress": "localhost:8410",
    "contractFilter": ["PUBLIC"]
}

Starting and Connecting an Execution Engine

You can always add a new Execution Engine node to a running deployment of the platform, by following these steps:

  1. Add a configuration file for the Execution Engine.
  2. Create a .yaml file and add a container with an execution container image registry.gitlab.com/secata/platform/platform-dev-runner/execution-container-standalone:latest and the configuration file from step 1. See an example below.
  3. Boot your Execution Engine container by running the command: docker compose -f your-filename.yaml up -d.
A minimal container for an Execution Engine node
ee-node:
    container_name: ee-node
    image: registry.gitlab.com/secata/platform/platform-dev-runner/execution-container-standalone:latest
    volumes:
        - ./conf/ee-node.json:/conf/server.json
    ports:
        - '8400:8400'

The ports should match the "restEndpointPort" in the configuration file.

To ensure the execution node starts successfully and is able to connect to a reader node, check the docker logs for the container by running the command:

docker logs ee-node

When an execution engine node is started, it listens to all the contracts described by the "contractFilter" field in its configuration.

Info

If the smart contract uses authentication, new Execution Engine nodes will be rejected unless explicitly trusted.

Ensure your contract logic supports dynamic node authorization or redeploy with updated node info.

To make a running execution engine node listen to a new smart contract, change the "contractFilter" field in the configuration and reboot the node. Specifically, add the address of the smart contract to the "contractFilter".

Example: Off-chain Secret Sharing with an Execution Engine node

To see the execution engines in action, these Java code examples show you how to use an execution node with the Off-chain Secret Sharing smart contract. This smart contract allows users to store secret shares.

First, register an intention of storing a secret share on chain with the register_sharing action. Then upload the shares to the off-chain components configured in the contract state. Later, you can download the shares again from the off-chain components.

To try this out, first deploy an Off-chain Secret Sharing smart contract with the address(es) of the Execution Engine(s) node you are using. For example, the address "00b7c90c48ad7a6a0ed058fc286ae11230fa8c8500" corresponds to the address of the Execution Engine with private key 123456789ABCDEF.

Register a sharing with an integer id.

Then, run the example code to upload a secret of your choice, to the sharing with your chosen id. This will upload a Secret Sharing, i.e. each Execution Engine will get a share through a put-request.

Finally, you can download the secret again. This works by sending get-requests to each Execution Engine.

Info

Remember to change the placeholder variables in the code to match your own.

  • The READER_NODE_ENDPOINT. If you are using the platform-dev-runner initial setup, the reader node endpoint is "http://localhost:9432".

  • The contract address should be the address of the deployed Off-chain Secret Sharing smart contract.

  • Use your own private key as the SENDER_KEY.