Quickstart Guide

Blockchain, while powerful, is a very misunderstood technology. The immutable ledger provided allows for simple and powerful application in supply chain, product sourcing, and audit trail use cases, but it can be difficult to know if a blockchain is right for a given use case. Even if it is right, it can be even harder to know how to implement a blockchain solution.

Before getting started, install our command line tool (dctl) with

yarn global add dctl

More in depth installation instructions found here.

Smart Contracts

Hello world

To show how easy it is to get started developing custom business logic on the Dragonchain platform, copy paste these three commands into a terminal.

dctl contract init --language node --dir my-contract
docker build ./my-contract/src/ -t my-contract
dctl contract test --test-directory ./my-contract/test/ --payload "hello world" my-contract:latest

At the end, the contract will output

STDERR: hello world
STDERR: Call Count: 1
{"myCounter":1}

These commands create a contract locally (including a fully-featured test environment), build the image, and run it! That’s all it takes to start building a contract on Dragonchain!

A Little more Detail

Unlike other blockchains where developers have to write smart contracts in specific languages so that the code can compile on the blockchain’s virtual machine, L1 nodes make use of Docker. Developers who want to write smart contracts for a Dragonchain business node can write in almost any programming language they want (limited only by Docker), use JSON for input and output, test locally, deploy frequently, and even update or delete existing smart contracts.

To get started building a smart contract, navigate to an empty directory and run:

$ dctl contract init --language node
Creating new local contract environment...
No directory specified. Write test env files to current directory? [Y/N] y
Writing: test/.env
Cloning into 'tmp'...
Done

Running contract init sets up the environment to develop a smart contract. Contract init supports several languages, but this example uses nodejs. Init also fills in a few test files with sample tests to help start development.

Replace the code in handler.js with the following:

module.exports = async function (fullTransaction) {
  if (!fullTransaction || !fullTransaction.payload || !fullTransaction.payload.name) {
    return { error: "I can't say hi if I don't know your name!" };
  }
  return { greeting: `Hello ${fullTransaction.payload.name}!`, OUTPUT_TO_HEAP: false}
}

Use docker build . -t my-contract to build the image. The image needs to be pushed to a remotely accessible docker repository before the contract can be deployed. Alternately, dctl can be used to test the smart contract locally:

$ dctl contract test --test-directory ./my-contract/test/ --payload '{"name": "banana"}' my-contract:latest
{"greeting":"Hello banana!", "OUTPUT_TO_HEAP": false}

dctl can also be used to deploy the contract:

$ dctl contract create my-contract my-contract:latest node index.js
{
  "status": 202,
  "response": {
    "dcrn": "SmartContract::L1::AtRest",
    "version": "1",
    "txn_type": "my-contract",
    "id": "b7165579-c9bb-46f7-8853-ae1c1939883f",
    "status": {
      "state": "Pending",
      "msg": "Contract creating",
      "timestamp": "2019-11-05 21:25:09.806836"
    },
    "image": "my-contract:latest",
    "auth_key_id": null,
    "image_digest": null,
    "cmd": "node",
    "args": [
      "index.js"
    ],
    "env": null,
    "existing_secrets": null,
    "cron": null,
    "seconds": null,
    "execution_order": "parallel"
  },
  "ok": true
}

Once a contract is deployed, it creates a transaction type that can be used to invoke the contract:

$ dctl transaction create my-contract '{ "payload": { "name": "banana" } }'
{
  "status": 201,
  "response": {
    "transaction_id": "8f3faf1d-3a18-4f5f-bc3e-36561643d8f1"
  },
  "ok": true
}

$ dctl transaction query my-contract "@invoker:8f3faf1d-3a18-4f5f-bc3e-36561643d8f1"
{
  "status": 200,
  "response": {
    "total": 1,
    "results": [
      {
        "version": "2",
        "dcrn": "Transaction::L1::FullTransaction",
        "header": {
          "txn_type": "my-contract",
          "dc_id": "28GiivQE5m8a9oyvFD33JgwnBpgyZp2RxtTVFGjcRPVDJ",
          "txn_id": "6d9e845c-125a-48cf-925d-af6c61c0a71c",
          "block_id": "28150206",
          "timestamp": "1572989248",
          "tag": "",
          "invoker": "8f3faf1d-3a18-4f5f-bc3e-36561643d8f1"
        },
        "payload": {
          "greeting":"Hello banana!"
        },
        "proof": {
          "full": "kXLmBlsKOh+vUTVH5F8lA3R4JAJBXTiohWLPIUpHNTc=",
          "stripped": "MEUCIQCZmruFoFy0UJcbtj3/wCbjDK0MUtcXeemPPq7j8tycPgIgOcGHJosVWWBPacWIxuNsEydYK8qPpck9rpSOMlvIjes="
        }
      }
    ]
  },
  "ok": true
}

Once a contract deploys successfully, it can be invoked.

Transactions

The core of a blockchain is a verifiably secure and immutable ledger. The most basic use case for a chain is ledgering data and state changes. As time goes on, each change is added on top of the last, forming a cryptographically secure chain of data transformations that can be easily traced from start to finish.

To follow along with this tutorial, you will need keys to access an L1 node.

First, create a transaction type. While transaction types are extensible and designed to support complex work flows, this type is just a simple ledger.

$ dctl transactionType create quickstart
{
  "status": 200,
  "response": {
    "success": true
  },
  "ok": true
}

Verify that the type has been created using dctl:

$ dctl transactionType get quickstart
{
  "status": 200,
  "response": {
    "version": "2",
    "txn_type": "quickstart",
    "custom_indexes": [],
    "contract_id": "",
    "active_since_block": "28147946"
  },
  "ok": true
}

Now that the chain has a transaction type, it will accept transactions. L1 chains support indexing and searching transactions by their transaction type. This helps provide logical separation between data.

Creating a transaction is as easy as providing a payload to dctl:

$ dctl transaction create quickstart "Greetings from the quickstart guide"
Could not parse JSON for payload, sending raw data instead...
{
  "status": 201,
  "response": {
    "transaction_id": "a4df336c-ba35-461c-ad8a-6e5d19049ddd"
  },
  "ok": true
}

To find the transaction, get it directly by id:

$ dctl transaction get a4df336c-ba35-461c-ad8a-6e5d19049ddd
{
  "status": 200,
  "response": {
    "version": "2",
    "dcrn": "Transaction::L1::FullTransaction",
    "header": {
      "txn_type": "quickstart",
      "dc_id": "28GiivQE5m8a9oyvFD33JgwnBpgyZp2RxtTVFGjcRPVDJ",
      "txn_id": "a4df336c-ba35-461c-ad8a-6e5d19049ddd",
      "block_id": "28148014",
      "timestamp": "1572978285",
      "tag": "",
      "invoker": ""
    },
    "payload": "Greetings from the quickstart guide",
    "proof": {
      "full": "RJ95GnsOmXVQIdIfjst/qldyFeFwT1Qh+vH2eJs3mnA=",
      "stripped": "MEQCIFXCc1GNSfYJsE6rSiGeETDwUYpHEdAbBH4eEPzCc2kEAiARfGNj3G4gCQ9y9+jdRwT5uz6WVJWLMQZsQBSdOTbhyQ=="
    }
  },
  "ok": true
}

Transactions can still be queried without the ID. By default, queries return transactions sorted by timestamp:

$ dctl transaction query quickstart "*"
{
  "status": 200,
  "response": {
    "total": 1,
    "results": [
      {
        "version": "2",
        "dcrn": "Transaction::L1::FullTransaction",
        "header": {
          "txn_type": "quickstart",
          "dc_id": "28GiivQE5m8a9oyvFD33JgwnBpgyZp2RxtTVFGjcRPVDJ",
          "txn_id": "a4df336c-ba35-461c-ad8a-6e5d19049ddd",
          "block_id": "28148014",
          "timestamp": "1572978285",
          "tag": "",
          "invoker": ""
        },
        "payload": "Greetings from the quickstart guide",
        "proof": {
          "full": "RJ95GnsOmXVQIdIfjst/qldyFeFwT1Qh+vH2eJs3mnA=",
          "stripped": "MEQCIFXCc1GNSfYJsE6rSiGeETDwUYpHEdAbBH4eEPzCc2kEAiARfGNj3G4gCQ9y9+jdRwT5uz6WVJWLMQZsQBSdOTbhyQ=="
        }
      }
    ]
  },
  "ok": true
}

Another way to index transactions is to use tags. When creating a transaction, tags are specified with --tag:

$ dctl transaction create quickstart "This is my tag" --tag "my-tag"
Could not parse JSON for payload, sending raw data instead...
{
  "status": 201,
  "response": {
    "transaction_id": "3c406d80-19c5-424e-999e-64a278e3fdca"
  },
  "ok": true
}

This looks exactly the same as creating a transaction without a tag, but can be queried by tag:

$ dctl transaction query quickstart "*"
{
  "status": 200,
  "response": {
    "total": 2,
    "results": [
      ...
    ]
  },
  "ok": true
}

$ dctl transaction query quickstart "@tag:my-tag"
{
  "status": 200,
  "response": {
    "total": 1,
    "results": [
      {
        "version": "2",
        "dcrn": "Transaction::L1::FullTransaction",
        "header": {
          "txn_type": "quickstart",
          "dc_id": "28GiivQE5m8a9oyvFD33JgwnBpgyZp2RxtTVFGjcRPVDJ",
          "txn_id": "3c406d80-19c5-424e-999e-64a278e3fdca",
          "block_id": "28148113",
          "timestamp": "1572978782",
          "tag": "my-tag",
          "invoker": ""
        },
        "payload": "This is my tag",
        "proof": {
          "full": "2RPMG+GLULyNUgYS1wATl+kVeHgOIJGuMS2qgmGoxnk=",
          "stripped": "MEQCIAy0aJXFExTQH4wKi1yBCJPa2T+hwfQy6WgeDzEgYauuAiABOwa914JlO/6goE/STLm/3LcF6wH1RxLAEQ4KfdRN6Q=="
        }
      }
    ]
  },
  "ok": true
}

And that’s all you need to get started ledgering transactions and monitoring data transformations with Dragonchain!