Skip to main content
Version: 3.8

Get Started with ScalarDL Ledger

This getting started tutorial explains how to configure ScalarDL on your preferred database and illustrates the process of creating a simple application where the historical states of data are traced.

Prerequisites​

warning

Since ScalarDL is built with JDK 8, contracts must be a JDK 8–compatible binary. If you use a version other than JDK 8, you must configure your build tool to build the JDK 8–compatible binary. There are several ways to specify binary compatibility, including using the --release 8 option for javac or setting Gradle or Maven configurations to use the JDK 8 toolchain. The following shows the configuration for Gradle:

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
}
}

For more details about the Gradle and Maven configurations, see Toolchains for JVM projects for Gradle and Guide to Using Toolchains for Maven.

Clone the ScalarDL samples repository​

Open Terminal, then clone the ScalarDL samples repository by running the following command:

git clone https://github.com/scalar-labs/scalardl-samples

Then, go to the directory that contains the sample configuration by running the following command:

cd scalardl-samples

Start up ScalarDL with your preferred database​

Select your database, and follow the instructions to deploy ScalarDL Ledger with it. For a list of databases that ScalarDL supports, see Databases.

Set up your license (Enterprise edition only)

If you're using the ScalarDL Enterprise edition, set up your license as follows. If you're using the Community edition, skip to the next section to start up ScalarDL.

See here to set up your license
  1. Enable the Docker image for the Enterprise edition in the docker-compose-ledger-mysql.yml file as follows:

    • Before changing the image (default configuration):

      services:
      scalar-ledger:
      image: ghcr.io/scalar-labs/scalardl-ledger:${SCALARDL_VERSION}
      # image: ghcr.io/scalar-labs/scalardl-ledger-byol:${SCALARDL_VERSION}
    • After changing the image:

      services:
      scalar-ledger:
      # image: ghcr.io/scalar-labs/scalardl-ledger:${SCALARDL_VERSION}
      image: ghcr.io/scalar-labs/scalardl-ledger-byol:${SCALARDL_VERSION}
  2. Set your license key for ScalarDL Ledger. In the docker-compose-ledger-mysql.yml file, replace <SET_YOUR_LICENSE_KEY> with your license key. For example:

    services:
    scalar-ledger:
    environment:
    - SCALAR_DL_LICENSING_LICENSE_KEY={"organization_name":"XXXXXXXX","expiration_date_time":"YYYY-MM-DDTHH:mm:SS+TIMEZONE","product_name":"ScalarDL Ledger","product_version":N,"license_type":"trial","signature":"XXXXXXXX"}
  3. To check the license, update the docker-compose-ledger-mysql.yml file as follows. If you're using a trial license, skip this step.

    • Before changing the certificate file path (default configuration):

      services:
      scalar-ledger:
      volumes:
      - ./fixture/ledger-key.pem:/scalar/ledger-key.pem
      - ./fixture/ledger.properties.tmpl:/scalar/ledger/ledger.properties.tmpl
      - ./fixture/trial-license-cert.pem:/scalar/license-cert.pem
      # If you have a commercial license key, you must use `commercial-license-cert.pem` instead of `trial-license-cert.pem`.
      # - ./fixture/commercial-license-cert.pem:/scalar/license-cert.pem
    • After changing the certificate file path:

      services:
      scalar-ledger:
      volumes:
      - ./fixture/ledger-key.pem:/scalar/ledger-key.pem
      - ./fixture/ledger.properties.tmpl:/scalar/ledger/ledger.properties.tmpl
      # - ./fixture/trial-license-cert.pem:/scalar/license-cert.pem
      # If you have a commercial license key, you must use `commercial-license-cert.pem` instead of `trial-license-cert.pem`.
      - ./fixture/commercial-license-cert.pem:/scalar/license-cert.pem

Start up ScalarDL

You can start using ScalarDL Ledger by following the steps below:

  1. Run MySQL locally by running the following command:

    docker compose -f docker-compose-ledger-mysql.yml up -d 
  2. Load the database schema for ScalarDL Ledger by running the following command:

    docker compose -f docker-compose-ledger-mysql.yml up -d scalardl-ledger-schema-loader
  3. Run ScalarDL Ledger by running the following command:

    docker compose -f docker-compose-ledger-mysql.yml up -d

Download the Client SDK​

Next, you'll use the ScalarDL client tools and samples in the scalardl-java-client-sdk repository to interact with ScalarDL.

Specify a version that is the same as the deployed ScalarDL version and is used for downloading the tools by running the following command:

VERSION=$(grep SCALARDL_VERSION .env | awk -F= '{print $2}')

Then, clone the repo and download the tools by running the following command:

git clone https://github.com/scalar-labs/scalardl-java-client-sdk.git
cd scalardl-java-client-sdk
git checkout v$VERSION
curl -OL https://github.com/scalar-labs/scalardl-java-client-sdk/releases/download/v$VERSION/scalardl-java-client-sdk-$VERSION.zip
unzip scalardl-java-client-sdk-$VERSION.zip
mv scalardl-java-client-sdk-$VERSION client

Configure the client properties​

Before you can run ScalarDL Ledger, you need to configure the ScalarDL client. To create a configuration file with the minimum required properties for the client to interact with ScalarDL Ledger, run the following command:

cat << 'EOF' > client.properties
# A host name for ScalarDL Ledger.
scalar.dl.client.server.host=localhost

# An ID for the certificate holder. This must be configured for each private key and must be unique in the system.
scalar.dl.client.cert_holder_id=foo

# A path to the certificate file.
scalar.dl.client.cert_path=../fixture/client.pem

# A path to the private key file.
scalar.dl.client.private_key_path=../fixture/client-key.pem
EOF

You can use localhost for the ScalarDL Ledger host name in this tutorial. For the private key and certificate, you can use the ones provided in the fixture directory of scalardl-samples (client-key.pem and client.pem, respectively). For the certificate holder, any unique ID can be specified.

warning

Do not use the sample private key and certificate in production environments. For details about getting your own certificate, see How to Get a Certificate.

Register the certificate​

Next, you can register your certificate to ScalarDL Ledger by running the following command:

client/bin/register-cert --properties client.properties

The registered certificate will allow you to register and execute contracts and will also be used for detecting Byzantine faults in databases. Note that you can only add new certs and cannot update existing certs in place for security reasons. When you want to add a new cert, increment scalar.dl.client.cert_version before executing the registration tool.

Create a contract​

You can interact with ScalarDL through a contract, which is a Java program that implements single business logic. In this tutorial, you can see how a contract is written, built, and works by using a basic contract example, which creates an asset and associates some states with it.

Below, you can see a sample contract, StateUpdater.java. A contract is simply a Java class that extends the predefined base contract classes (such as JacksonBasedContract class) and overrides the invoke method. The business logic is implemented in the invoke method.

Specifically, the invoke method will extract a client-defined asset ID (asset_id) and state (state) from the argument, and then associate the asset ID with the state in the ledger if the given state is different from the asset's current state.

package com.org1.contract;

import com.fasterxml.jackson.databind.JsonNode;
import com.scalar.dl.ledger.contract.JacksonBasedContract;
import com.scalar.dl.ledger.exception.ContractContextException;
import com.scalar.dl.ledger.statemachine.Asset;
import com.scalar.dl.ledger.statemachine.Ledger;
import java.util.Optional;
import javax.annotation.Nullable;

public class StateUpdater extends JacksonBasedContract {

@Nullable
@Override
public JsonNode invoke(Ledger<JsonNode> ledger, JsonNode argument, @Nullable JsonNode properties) {
if (!argument.has("asset_id") || !argument.has("state")) {
// ContractContextException is the only throwable exception in a contract and
// it should be thrown when a contract faces some non-recoverable error
throw new ContractContextException("please set asset_id and state in the argument");
}

String assetId = argument.get("asset_id").asText();
int state = argument.get("state").asInt();

Optional<Asset<JsonNode>> asset = ledger.get(assetId);

if (!asset.isPresent() || asset.get().data().get("state").asInt() != state) {
ledger.put(assetId, getObjectMapper().createObjectNode().put("state", state));
}

return null;
}
}

You can compile the contract by running the following command:

./gradlew assemble

This will generate build/classes/java/main/com/org1/contract/StateUpdater.class.

Register the contract​

Next, register your contract by running the following command:

client/bin/register-contract --properties client.properties --contract-id StateUpdater --contract-binary-name com.org1.contract.StateUpdater --contract-class-file build/classes/java/main/com/org1/contract/StateUpdater.class

Please set a globally unique ID for the contract ID (e.g. StateUpdater in the above command).

tip

You can set different contract IDs on the same contract by using different certificates to clarify "who did what" in a tamper-evident way.

For example, think about a voting application. In the application, anyone can vote with the same voting logic and therefore can use the same contract, but A's vote and B's vote need to be properly and securely distinguished—A cannot vote for B, and vice versa. By using different contract IDs on the same contract, you can ensure that A's vote and B's vote are identified differently from one another.

Execute the contract​

Now you are ready to execute the contract with the following command.

client/bin/execute-contract --properties client.properties --contract-id StateUpdater --contract-argument '{"asset_id":"some_asset", "state":3}'

In the contract argument, the value specified with the key asset_id must be unique globally for each asset.

Validate the states of Ledger​

You can validate the states of Ledger by executing the following command.

client/bin/validate-ledger --properties client.properties --asset-id="some_asset"

What the validation does is depending on how you set up and configure ScalarDL. Briefly speaking, if only ScalarDL Ledger is used, the validation traverses assets to see if the assets can be recomputed and have a valid hash-chain structure. With ScalarDL Ledger and Auditor, the validation checks discrepancies (i.e., Byzantine faults) between the states of Ledger and Auditor without centralized coordination. Please read Getting Started with ScalarDL Auditor for more details about the validation with Auditor.

Create your own contracts or use generic contracts​

There are two options for preparing contracts: creating your own or using predefined ones.

As explained above, what you need to do to create your contracts is to extend the predefined base contract classes and override the invoke method as you like. For details, see A Guide on How to Write a Good Contract.

Predefined ones are called generic contracts and provide basic functionalities for common use cases. For details, see Use Generic Contracts and Functions.

See also​

To write your own contracts, see the following:

To use generic contracts, see the following:

To interact with ScalarDL components in your Java applications, see the following:

To better understand the foundation of ScalarDL, see the following: