Skip to content

Development Tips

patrickhuie19 edited this page May 5, 2023 · 56 revisions

Geth

Geth needs to be invoked with websockets enabled. An example of how to do this is:

geth --ws --ws.addr 127.0.0.1 --ws.port 8546 --ws.origins "*"

This would make Geth listen on ws://127.0.0.1:8546 and accept all incoming connections. Alternatively, you could change the --wsorigins parameter to 127.0.0.1 as well to only accept local connections.

For details on how to install, configure, and run Geth, please refer to their documentation.

Parity

Parity also needs to be invoked with the websockets API enabled:

parity --ws-interface 127.0.0.1 --ws-port 8546 --ws-origins "all"

For details on how to install, configure, and run Parity, please refer to their documentation.

Postgres

Postgres is used as a database for Chainlink nodes. If you would like to quickly get setup, we suggest using Docker and follow the instructions below.

  1. Create a persistent volume for Postgres data path:
# this needs to be created once
docker volume create pgdata
  1. Run Postgres docker image with volume mounted:
# replace $PASSWORD with password of choice
docker run -d \
  -p 5432:5432 \
  --name postgres \
  -e POSTGRES_USER=chainlink \
  -e POSTGRES_DB=chainlink \
  -e POSTGRES_PASSWORD=$PASSWORD \
  -v pgdata:/var/lib/postgresql/data \
  postgres:11

You can now point chainlink at it on startup by setting an environment variable:

export CL_DATABASE_URL="postgres://chainlink:$PASSWORD@localhost:5432/chainlink?sslmode=disable"

Adding migrations

To change the database schema you need to add a migration. As a prerequisite you need to get familiar with how gormigrate works. Then:

  1. create a new migration package with the current timestamp. Eg. mkdir core/store/migrations/migration$(date +%s)
  2. this package needs to export two methods Migrate() and Rollback(). This is a templates of what it may contain:
package migration12345

import (
  "github.com/jinzhu/gorm"
)
const up = `
... sql ...
`
const down = `
... sql ...
`
func Migrate(tx *gorm.DB) error {
  return tx.Exec(up).Error
}
func Rollback(tx *gorm.DB) error {
  return tx.Exec(down).Error
}
  1. import your migration package in core/store/migrations/migrate.go and add it to the list of migrations.
  2. if the changes in your migration are complex, consider adding a test in core/store/migrations/migrate_test.go
  3. consider whether your migration should be documented in the CHANGELOG

direnv

We use direnv to set up PATH and aliases for a friendlier developer experience. Here is an example .envrc that we use:

cat .envrc
export ROOT=tmp/.chainlink
PATH_add tools/bin
PATH_add tmp

Direnv can be installed by running

go get -u github.com/direnv/direnv

Then hooking direnv into your shell.

Environment variables that can be set in .envrc, along with default values that get used if no corresponding enviornment variable is found:

LOG_LEVEL                    Default: "info"
ROOT                         Default: "~/.chainlink"
CHAINLINK_PORT               Default: "6688"
GUI_PORT                     Default: "6689"
USERNAME                     Default: "chainlink"
PASSWORD                     Default: "twochains"
ETH_URL                      Default: "ws://localhost:8546"
ETH_CHAIN_ID                 Default: "0"
CLIENT_NODE_URL              Default: "http://localhost:6688"
MIN_INCOMING_CONFIRMATIONS   Default: "0"
MIN_OUTGOING_CONFIRMATIONS   Default: "12"
ETH_GAS_BUMP_THRESHOLD       Default: "12"
ETH_GAS_BUMP_WEI             Default: "5000000000"
ETH_GAS_PRICE_DEFAULT        Default: "20000000000"
LINK_CONTRACT_ADDRESS        Default: "0x514910771AF9Ca656af840dff83E8264EcF986CA"
MINIMUM_CONTRACT_PAYMENT     Default: "1000000000000000000"
ORACLE_CONTRACT_ADDRESS      Default: ""
DATABASE_POLL_INTERVAL       Default: "500ms"

Note: v2 nodes are moving from environment variable configuration to TOML configuration. Refer to https://docs.chain.link/chainlink-nodes/v1/configuration/ for providing the necessary inputs.

Colorized Test Output

Use grc to colorize your test output and make it more readable.

🚨Warning🚨 This can occasionally fail if the test output contains unicode characters that the colorizer could misread as color encoding. In this case, running your Go tests will give you a Python error similar to:

Traceback (most recent call last):
  File "/usr/local/bin/grcat", line 180, in <module>
    line = freadline()
  File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/codecs.py", line 322, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb8 in position 1527: invalid start byte

In this case, to read the actual error you must unalias go:

unalias go && go test ./...

Development Dependencies

The following is a list of dependencies that need to be installed on the host machine, categorized by role. A guide for installing each of these is located here

Chainlink

  • Go
  • gcc (for secp256k1 in go-ethereum)
  • yarn (for Node Operator UI development)

Devnet

  • Docker

Solidity contract development

  • Node.js & npm
  • Yarn
  • Truffle
  • Python 2.7 (for sha3 in node_modules)

Setting up Paths

Setting up paths for Golang development involves using a GOPATH environment variable, and adding two paths to your Go binaries to your PATH environment variable.

First, create a workspace for Go development:

mkdir ~/go

This will serve as your GOPATH environment variable. You'll want this to be persisted every time you run a terminal, so add this to the appropriate file that is ran when you log in. You can determine which one that is here, we'll be using ~/.bashrc for these examples.

echo "export GOPATH=~/go" >> ~/.bashrc

Next, you'll want to add the binaries for the Go installation, and for installed Go programs to your PATH environment variable. We're going to assume that your default Go installation is located at /usr/local/go, so adjust accordingly if it's different:

echo "export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin" >> ~/.bashrc

Now when logging out and logging on, your Go binaries will automatically be available for you to run, and the $GOPATH environment variable will persist.

Ignoring Developer-Specific Files

Instead of adding IDE-specific files to the .gitignore file in our repo, we ask that you add them to your own global .gitignore file.

You can do this by running:

git config --global core.excludesfile '~/.gitignore'

Or on Windows:

git config --global core.excludesfile "%USERPROFILE%\.gitignore"

Then you'll add files that are specific to your development here. For example, if you use Visual Studio Code, you'll want to add:

.vscode\
debug

Node Operator UI Development

The operator UI is compiled as part of node compilation. However, this is not suitable for development, as each change requires the node to be recompiled via a restart which can several minutes depending on your machine.

To aid with the speed of development we recommend using webpack-dev-server which is available via the yarn start command. This watches your file system in /operator_ui and recompiles when there are changes. It also supports hot module replacement so that the changes are visible without having to reload the page. We recommend running the command with the CHAINLINK_PORT environment variable so that API requests are sent to your local node. You can do this when running the command:

$ CHAINLINK_PORT=6688 yarn start

Or, if using direnv

# .envrc
export CHAINLINK_PORT=6688

# bash
$ yarn start