Skip to content

3. DAppNode SDK Tutorial: Complex package with setup wizard

Lanski edited this page May 13, 2020 · 1 revision

DAppNode Package tutorial - Vipnode

In this guide, we will walk you through creating the Vipnode DAppNode Package using the dappnodesdk. The Vipnode package is great as a learning example because it's simple but includes some extra features like the dependency on DAppNode's core packages.

0. The setup

If you haven't already, install the dappnodesdk package

npm install -g @dappnode/dappnodesdk

Set up and bootstrap our project. We recommend the naming convention of DAppNodePackage-${package_name}.

mkdir DAppNodePackage-vipnode
cd DAppNodePackage-vipnode

The init command will create a convenient basic starting point. To auto answer the init questions use the flag -y, you can edit the resulting information latter.

dappnodesdk init -y

The resulting file structure should be similar to

DAppNodePackage-vipnode/
├── build/
│   └── Dockerfile
├── avatar-default.png
├── dappnode_package.json
└── docker-compose.yml

1. Understand your package

Before we start, we need to understand what our DApp does, what does it need, and what other P2P DApps it depends on.

The Vipnode DApp is an incentivization layer that allows full node operators to join a pool where light nodes can go to connect to full node slots, in exchange for micropayments.

So in this case, the requirements are the following:

A) Connection to an Ethereum full node

It needs to connect to an Ethereum full node via the JSON RPC to edit the whitelist of light nodes. Aren't we lucky that DAppNode already has a full node?

The Vipnode binary accepts a --rpc flag. We will use this to connect the DAppNode's full node available at the generalized URL my.ethchain.dnp.dappnode.eth.

B) Read the node's key

Once connected to the full node, it needs to access the node key in order to identify it.

Accessing the nodekey can be done by giving the Vipnode docker container access to the DAppNode's fullnode DAppNode Package (ETHCHAIN) volume via an external docker volume. The ethchain's volume name is dncore_ethchaindnpdappnodeeth_identity so we must map it to our package and tell the vipnode binary where to find the nodekey.

C) Get a payout address

A third requirement is that it needs a payout address to send the rewards to - that is the micropayments that light clients will send for using the light client slots of the full node.

The payout address must be editable by the user, and the user needs to be able to change it whenever he/she wants. To accomplish that, it must be declared as an ENV which is shown in the ADMIN UI where the user can customize it at any point. Then, we will feed this ENV to the vipnode binary. We will name PAYOUT_ADDRESS for simplicity.

Note that this is an excellent field to ask the user during the setup process of the package installation, using our setup wizard. You will find more information on how to prepare this in the add a setup wizard section of this guide.

2. Develop your package

Now it's time to translate the above requirements into actual code. All DAppNode packages wrap a docker image, which is what we have to develop first.

This tutorial assumes you are comfortable with Docker and docker-compose. If not, please watch a basic tutorial or refer to the official documentation.

2.1. Write the Dockerfile

Taking the official Vipnode docker image as the base, we will expand it with custom options:

  • A) Tell the Vipnode binary to connect to the DAppNode's fullnode at http://my.ethchain.dnp.dappnode.eth:8545 with the option --rpc.
  • B) Tell the Vipnode binary where to find the node's key in the path of the volume that we will create later in the docker-compose /app/identity/nodekey with the option --nodekey.
  • C) Set the payout address with an environment variable that will be injected at runtime by the setting the user provides in each installation. Set the flag --payout to the ENV variable ${PAYOUT_ADDRESS} whose name must match the environment variable declared in the docker-compose.
FROM shazow/vipnode
ENTRYPOINT vipnode agent -vv \
  --rpc=http://my.ethchain.dnp.dappnode.eth:8545 \
  --payout=${PAYOUT_ADDRESS} \
  --nodekey=/app/identity/nodekey

2.2. Complete the docker-compose

Extend the boilerplate docker-compose with these configuration options:

  • B) Map the external volume of the DNP_ETHCHAIN dncore_ethchaindnpdappnodeeth_identity to the /app/identity path, which matches the path provided to the vipnode binary. Since we just need to read the key we make the volume read-only with :ro. Refer to the docker-compose documentation for the syntax used to declare the external volume.
  • C) Declare the environment variable PAYOUT_ADDRESS empty, which will be provided by the user during the installation through the setup wizard or later in the configuration tab of the package, where the Environment Variables can be changed.
version: "3.4"

services:
  vipnode.dnp.dappnode.eth:
    image: "vipnode.dnp.dappnode.eth:0.1.0"
    build: ./build
    environment:
      - "PAYOUT_ADDRESS="
    volumes:
      - "dncore_ethchaindnpdappnodeeth_identity:/app/identity:ro"

volumes:
  dncore_ethchaindnpdappnodeeth_identity:
    external: true

To make sure the docker image builds without errors let's try to build before continuing

$ docker-compose build

If the build completed successfully continue to next step. Otherwise make sure there typos in the files, troubleshoot possible docker errors or reach out to us.

3. Polish your package

The package now should work, but that doesn't mean the users know how to use it! It's time to introduce features to improve the UX for your DAppNode Package users.

Next, we will add the following items:

  • Manifest (mandatory): Help users understand what the package is about. It's used to identify the package and its descriptions are shown before installing
  • Avatar (mandatory): An image that will define your package
  • Setup wizard (optional, highly recommended if the package needs configuration): Help users configure the package. It's shown at installation time
  • Getting started (optional): Help users start using the package. It's shown after a successful installation

3.1. Write the manifest

This file declares your DAppNode package. All mandatory metadata was filled when running dappnodesdk init. However, you are highly encouraged to fill the following fields that will show up before installing the package:

  • upstreamVersion: What's the version of the underlying software being wrapped
  • shortDescription: 6-8 word hook description
  • description: Detailed description, allows markdown
  • author: Package author, please format as ${name} <${email}> (${github URL})
{
  "name": "vipnode.dnp.dappnode.eth",
  "version": "0.1.0",
  "upstreamVersion": "2.2.1",
  "shortDescription": "Economic incentive for running Ethereum full nodes",
  "description": "[Vipnode](https://vipnode.org)'s goal is to allow the Ethereum network to remain decentralized by creating a financial marketplace for more people to run full nodes and serve native light clients. Check this [medium article](https://medium.com/vipnode/an-economic-incentive-for-running-ethereum-full-nodes-ecc0c9ebe22) to understand the motivation behind this project and this [2.0 release article](https://medium.com/vipnode/vipnode-2-0-released-9af1d65b4552) for a tutorial on how to use Vipnode.",
  "type": "service",
  "author": "DAppNode Association <[email protected]> (https://github.com/dappnode)",
  "categories": ["Economic incentive"],
  "links": {
    "homepage": "https://github.com/dappnode/DAppNodePackage-vipnode"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/dappnode/DAppNodePackage-vipnode.git"
  },
  "bugs": {
    "url": "https://github.com/dappnode/DAppNodePackage-vipnode/issues"
  },
  "license": "GPL-3.0"
}

3.2. Add an avatar

Add an avatar to be shown in the Admin UI. To do so, just add this avatar (link TODO) avatar-vipnode.png to the root of the project. The dappnodesdk will automatically find it and add it to the release. Refer to the docs (link TODO) for the avatar requirements.

3.3. Add a setup wizard

This step is optional, but we highly recommend preparing the setup wizard as it can highly improve the usability of your package!

The wizard helps users configure the package. You can declare the different configuration variables that the user must or should set. You can also add a description and validation logic to them. This component is built on top of https://github.com/rjsf-team/react-jsonschema-form and requires three distinct files:

  • setup.schema.json: Declares parameters to be shown, metadata and validation options.
  • setup-ui.json (optional): Adds custom options affecting the display of the form fields.
  • setup-target.json: Tells the DAppNode installer what configuration parameter is each field referring too.

setup.schema.json

Declare which parameters should be shown in the setup wizard form, their name, description and validation options. For all description fields you can use markdown which will be rendered by https://github.com/rexxars/react-markdown.

{
  "description": "This setup wizard will help you start. In case of problems: https://github.com/dappnode/DAppNodePackage-vipnode#installing-and-setting-up-vipnode",
  "type": "object",
  "required": ["payoutAddress"],
  "properties": {
    "payoutAddress": {
      "type": "string",
      "title": "Payout address",
      "description": "Define an Ethereum mainnet address to get rewards to",
      "pattern": "^0x[a-fA-F0-9]{40}$"
    }
  }
}

setup-ui.json

Add custom options affecting the display of setup.schema.json's fields. See https://react-jsonschema-form.readthedocs.io for more details.

{
  "payoutAddress": {
    "ui:help": "Don't use your main address",
    "errorMessages": {
      "pattern": "Must be a valid address (0x1fd16a...)"
    }
  }
}

setup-target.json

Tell the DAppNode installer what configuration parameter is each field referring too.

{
  "payoutAddress": {
    "type": "environment",
    "name": "PAYOUT_ADDRESS"
  }
}

3.4. Add a getting started

This step is optional

Once the user has installed the package, they might need some help to start using it. This file will be shown right after a successful installation, when the user enters the installed package, and is dismissable.

You can use internal DAppNode links if applicable, or guide the users to video tutorials you might have, external websites, etc. The contents of this file will be rendered as markdown by https://github.com/rexxars/react-markdown.

getting-started.md

You should see your enode
\```
[host] 2019/04/09 08:45:33 Connected to local node: enode://974f7b125a2a3756ddb917f9ae...
\```
on the pool status website [Status](https://vipnode.org/status)

4. Build and test

Now your package is ready for being tested locally in your DAppNode!

First, let's make sure the file directory is right. Your Vipnode DAppNode package directory should look like this:

DAppNodePackage-vipnode.dnp.dappnode.eth/
├── build/
│   └── Dockerfile
├── avatar-vipnode.png
├── dappnode_package.json
├── docker-compose.yml
├── getting-started.md
├── setup-target.json
├── setup-ui.json
└── setup.schema.json

The dappnodesdk build command will prepare the necessary files, build the docker image and upload the package directory to IPFS. The resulting IPFS hash will allow you to install and run the package without needing to create the APM Repo (more on that latter). This will allow you to test the package in any DAppNode before publishing the package. Make sure that you are connected to your DAppNode's VPN or Wi-Fi hotspot and run:

$ dappnodesdk build

The process can take several minutes depending on your internet connection and should end with an output similar to this


  DNP (DAppNode Package) built and uploaded
  Manifest hash : /ipfs/QmfDSDeK9fiWpB7tEAiFKzuXvcvJr7yPiYr2jZmto6ZPRa
  Install link : http://my.dappnode/#/installer/%2Fipfs%2FQmfDSDeK9fiWpB7tEAiFKzuXvcvJr7yPiYr2jZmto6ZPRa

You can open the install link in your browser and install the package in your DAppNode.

5. Publish

Once you have successfully tested the package using its IPFS hash, it's time to publish it.

But what does it mean to publish a DAppNode package? In DAppNode we use the Aragon Package Manager (APM) smart contract. To publish a DAppNode package means sending a transaction to the registry contract and link a Semver version to the IPFS hash of the manifest of the package.

Now, let's publish our DAppNode package! The publish command does the build of the image and shows a transaction data to be able to publish the package. The first time it will create the repository. Otherwise, it will update it.

To be able to update a repository you must be the authorized dev. The authorized dev Ethereum account is assigned when first deploying the APM repo of a package. When you deploy the APM repo of your package, the dappnodesdk will ask you to provide the authorized dev address.

The script increases the current version of the repository based on the specified type (patch, minor, major), unless a version hasn't yet been published

$ dappnodesdk publish < patch | minor | major >

for more information about versioning check semver

Please take into account that the package version is not the internal version of the package you want to upload. We use the Aragon package manager, and it only lets starting with version 1 and increments one by one. Valid initial versions are 0.0.1, 0.1.0 or 1.0.0.