Merge branch 'master' into amb-oracle

# Conflicts:
#	oracle-e2e/deploy.js
#	oracle-e2e/docker-compose.yml
#	oracle-e2e/run-tests.sh
#	oracle/config/base.config.js
#	oracle/src/services/gasPrice.js
#	oracle/src/utils/utils.js
#	oracle/test/gasPrice.test.js
This commit is contained in:
Gerardo Nardelli 2019-07-17 10:00:10 -03:00
commit 0694fc24e9
215 changed files with 3491 additions and 2932 deletions

@ -35,6 +35,12 @@ jobs:
key: initialize-{{ .Environment.CIRCLE_SHA1 }} key: initialize-{{ .Environment.CIRCLE_SHA1 }}
paths: paths:
- ~/project - ~/project
initialize-root:
docker:
- image: circleci/node:10.15
steps:
- checkout
- run: sudo su - -c 'export CI=true && cd /home/circleci/project && yarn initialize && yarn test'
build: build:
docker: docker:
- image: circleci/node:10.15 - image: circleci/node:10.15
@ -49,18 +55,9 @@ jobs:
- restore_cache: - restore_cache:
key: initialize-{{ .Environment.CIRCLE_SHA1 }} key: initialize-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn run lint - run: yarn run lint
ansible-lint:
docker:
- image: particlekit/ansible-lint
steps:
- checkout
- run: ./deployment/lint.sh
test: test:
docker: docker:
- image: circleci/node:10.15 - image: circleci/node:10.15
environment:
HOME_RPC_URL: http://example.com
FOREIGN_RPC_URL: http://example.com
steps: steps:
- restore_cache: - restore_cache:
key: initialize-{{ .Environment.CIRCLE_SHA1 }} key: initialize-{{ .Environment.CIRCLE_SHA1 }}
@ -101,6 +98,14 @@ jobs:
paths: paths:
- ~/.cache/yarn - ~/.cache/yarn
- run: yarn run ui-e2e - run: yarn run ui-e2e
monitor-e2e:
machine:
image: circleci/classic:latest
docker_layer_caching: true
steps:
- checkout
- run: git submodule update --init
- run: ./monitor-e2e/run-tests.sh
cover: cover:
docker: docker:
- image: circleci/node:10.15 - image: circleci/node:10.15
@ -109,11 +114,40 @@ jobs:
key: initialize-{{ .Environment.CIRCLE_SHA1 }} key: initialize-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn workspace ui run coverage - run: yarn workspace ui run coverage
- run: yarn workspace ui run coveralls - run: yarn workspace ui run coveralls
deployment-oracle:
machine:
image: circleci/classic:latest
docker_layer_caching: true
steps:
- checkout
- run: deployment/molecule/molecule.sh oracle
deployment-ui:
machine:
image: circleci/classic:latest
docker_layer_caching: true
steps:
- checkout
- run: deployment/molecule/molecule.sh ui
ultimate-native-to-erc:
machine:
image: circleci/classic:latest
docker_layer_caching: true
steps:
- checkout
- run: git submodule update --init
- run:
name: Prepare the infrastructure
command: e2e-commons/up.sh deploy native-to-erc
- run: 'echo "TODO - Run the e2e tests on top of the infrastructure created by previous step"'
workflows: workflows:
version: 2 version: 2
tokenbridge: tokenbridge:
jobs: jobs:
- initialize - initialize
- initialize-root:
filters:
branches:
only: master
- build: - build:
requires: requires:
- initialize - initialize
@ -129,6 +163,9 @@ workflows:
filters: filters:
branches: branches:
only: master only: master
- ansible-lint
- oracle-e2e - oracle-e2e
- ui-e2e - ui-e2e
- monitor-e2e
- deployment-oracle
- deployment-ui
- ultimate-native-to-erc

2
.gitignore vendored

@ -43,6 +43,8 @@ hosts
Vagrantfile Vagrantfile
vagrant-hosts.yml vagrant-hosts.yml
.vagrant .vagrant
deployment/venv
__pycache__
#monitor #monitor
monitor/responses/* monitor/responses/*

@ -2,17 +2,11 @@ FROM node:10
WORKDIR /mono WORKDIR /mono
COPY package.json . COPY package.json .
COPY oracle/package.json ./oracle/
COPY oracle-e2e/package.json ./oracle-e2e/ COPY oracle-e2e/package.json ./oracle-e2e/
COPY ui/package.json ./ui/
COPY ui/lib/web3-eth/index.js ./ui/lib/web3-eth/index.js
COPY ui-e2e/package.json ./ui-e2e/
COPY monitor/package.json ./monitor/
COPY contracts/package.json ./contracts/ COPY contracts/package.json ./contracts/
COPY ui/lib/web3-eth/index.js ./ui/lib/web3-eth/index.js
COPY yarn.lock . COPY yarn.lock .
RUN yarn install RUN yarn install --frozen-lockfile
COPY ./contracts ./contracts COPY ./contracts ./contracts
RUN yarn install:deploy RUN yarn install:deploy
RUN yarn compile:contracts RUN yarn compile:contracts

@ -24,10 +24,23 @@ Sub-repositories maintained within this monorepo are listed below.
| [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. | | [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. |
| [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. | | [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. |
| [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle | | [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle |
| [Monitor-E2E](monitor-e2e/README.md) | End to end tests for the Monitor |
| [UI-E2E](ui-e2e/README.md) | End to end tests for the UI | | [UI-E2E](ui-e2e/README.md) | End to end tests for the UI |
| [Commons](commons/README.md) | Interfaces, constants and utilities shared between the sub-repositories |
| [E2E-Commons](e2e-commons/README.md) | Common utilities and configuration used in end to end tests |
Additionally there are [Smart Contracts](https://github.com/poanetwork/poa-bridge-contracts) used to manage bridge validators, collect signatures, and confirm asset relay and disposal. Additionally there are [Smart Contracts](https://github.com/poanetwork/poa-bridge-contracts) used to manage bridge validators, collect signatures, and confirm asset relay and disposal.
## Available deployments
| **Launched by POA** | **Launched by 3rd parties** |
| ---------- | ---------- |
| [POA20 Bridge](https://bridge.poa.net/) | [Ocean Token Bridge](https://bridge.oceanprotocol.com/) |
| [xDai Bridge](https://dai-bridge.poa.network/) | [Thunder bridge](https://ui.stormdapps.com/) |
| [WETC Bridge](https://wetc.app/) | [Volta Token Bridge](https://vt.volta.bridge.eth.events/) & [DAI bridge to Volta Chain](https://dai.volta.bridge.eth.events/) |
| | [Artis Brige](https://bridge.artis.network/) |
| | [Tenda bridge](https://bridge-mainnet.tenda.network) & [xDai-to-Tenda bridge](https://bridge-xdai.tenda.network/) |
## Network Definitions ## Network Definitions
Bridging occurs between two networks. Bridging occurs between two networks.
@ -46,26 +59,14 @@ The POA TokenBridge provides three operational modes:
## Initializing the monorepository ## Initializing the monorepository
Clone the repository with submodules: Clone the repository:
```bash ```bash
git clone --recursive https://github.com/poanetwork/tokenbridge git clone https://github.com/poanetwork/tokenbridge
# or initialize submodules if already cloned without --recursive option:
git submodule update --init
``` ```
Install dependencies: Initialize submodules, install dependencies, compile the Smart Contracts:
``` ```
yarn install && yarn install:deploy yarn initialize
```
_**Note**: The installation should be performed with an unprivileged Linux account or with the following flag: `yarn install --unsafe-perm`. [More information](https://docs.npmjs.com/misc/scripts#user)_
Compile the Smart Contracts
```
yarn compile:contracts
``` ```
## Linting ## Linting
@ -76,14 +77,6 @@ Running linter for all JS projects:
yarn lint yarn lint
``` ```
Running linter for all Ansible playbooks:
- [ansible-lint](https://github.com/ansible/ansible-lint) is required
```
yarn ansible-lint
```
## Tests ## Tests
Running tests for all projects: Running tests for all projects:
@ -96,6 +89,10 @@ Additionaly there are end-to-end tests for [Oracle](oracle-e2e/README.md) and [U
For details on building, running and developing please refer to respective READMEs in sub-repositories. For details on building, running and developing please refer to respective READMEs in sub-repositories.
## Building, running and deploying
Please refer to the instructions in sub-directories.
## Contributing ## Contributing
See the [CONTRIBUTING](CONTRIBUTING.md) document for contribution, testing and pull request protocol. See the [CONTRIBUTING](CONTRIBUTING.md) document for contribution, testing and pull request protocol.

12
commons/.eslintrc Normal file

@ -0,0 +1,12 @@
{
"extends": [
"airbnb-base",
"../.eslintrc"
],
"rules": {
"no-unused-expressions": "off"
},
"env": {
"mocha": true
}
}

2
commons/README.md Normal file

@ -0,0 +1,2 @@
# POA Token Bridge / Commons
Interfaces, constants and utilities shared between the sub-repositories

56
commons/abis.js Normal file

@ -0,0 +1,56 @@
const HOME_NATIVE_TO_ERC_ABI = require('../contracts/build/contracts/HomeBridgeNativeToErc').abi
const FOREIGN_NATIVE_TO_ERC_ABI = require('../contracts/build/contracts/ForeignBridgeNativeToErc')
.abi
const HOME_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeBridgeErcToErc').abi
const FOREIGN_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignBridgeErc677ToErc677')
.abi
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignBridgeErcToNative')
.abi
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
const ERC677_ABI = require('../contracts/build/contracts/ERC677').abi
const ERC677_BRIDGE_TOKEN_ABI = require('../contracts/build/contracts/ERC677BridgeToken').abi
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/IBlockReward').abi
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/RewardableValidators').abi
const { homeV1Abi, foreignViAbi } = require('./v1Abis')
const { BRIDGE_MODES } = require('./constants')
function getBridgeABIs(bridgeMode) {
let HOME_ABI = null
let FOREIGN_ABI = null
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
HOME_ABI = HOME_NATIVE_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_NATIVE_TO_ERC_ABI
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
HOME_ABI = HOME_ERC_TO_ERC_ABI
FOREIGN_ABI = FOREIGN_ERC_TO_ERC_ABI
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
HOME_ABI = HOME_ERC_TO_NATIVE_ABI
FOREIGN_ABI = FOREIGN_ERC_TO_NATIVE_ABI
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
HOME_ABI = homeV1Abi
FOREIGN_ABI = foreignViAbi
} else {
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
}
return { HOME_ABI, FOREIGN_ABI }
}
module.exports = {
getBridgeABIs,
HOME_NATIVE_TO_ERC_ABI,
FOREIGN_NATIVE_TO_ERC_ABI,
HOME_ERC_TO_ERC_ABI,
FOREIGN_ERC_TO_ERC_ABI,
HOME_ERC_TO_NATIVE_ABI,
FOREIGN_ERC_TO_NATIVE_ABI,
ERC20_ABI,
ERC677_ABI,
ERC677_BRIDGE_TOKEN_ABI,
BLOCK_REWARD_ABI,
BRIDGE_VALIDATORS_ABI,
REWARDABLE_VALIDATORS_ABI
}

19
commons/constants.js Normal file

@ -0,0 +1,19 @@
const BRIDGE_MODES = {
NATIVE_TO_ERC: 'NATIVE_TO_ERC',
ERC_TO_ERC: 'ERC_TO_ERC',
ERC_TO_NATIVE: 'ERC_TO_NATIVE',
NATIVE_TO_ERC_V1: 'NATIVE_TO_ERC_V1'
}
const ERC_TYPES = {
ERC20: 'ERC20',
ERC677: 'ERC677'
}
const FEE_MANAGER_MODE = {
ONE_DIRECTION: 'ONE_DIRECTION',
BOTH_DIRECTIONS: 'BOTH_DIRECTIONS',
UNDEFINED: 'UNDEFINED'
}
module.exports = { BRIDGE_MODES, ERC_TYPES, FEE_MANAGER_MODE }

9
commons/index.js Normal file

@ -0,0 +1,9 @@
const constants = require('./constants')
const abis = require('./abis')
const utils = require('./utils')
module.exports = {
...constants,
...abis,
...utils
}

10
commons/package.json Normal file

@ -0,0 +1,10 @@
{
"name": "commons",
"version": "0.0.1",
"private": true,
"main": "index.js",
"scripts": {
"lint": "eslint . --ignore-path ../.eslintignore",
"test": "NODE_ENV=test mocha"
}
}

12
commons/test/constants.js Normal file

@ -0,0 +1,12 @@
const { expect } = require('chai')
const { BRIDGE_MODES, ERC_TYPES } = require('../constants')
describe('constants', () => {
it('should contain correct number of bridge types', () => {
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(4)
})
it('should contain correct number of erc types', () => {
expect(Object.keys(ERC_TYPES).length).to.be.equal(2)
})
})

60
commons/utils.js Normal file

@ -0,0 +1,60 @@
const { BRIDGE_MODES, FEE_MANAGER_MODE } = require('./constants')
function decodeBridgeMode(bridgeModeHash) {
switch (bridgeModeHash) {
case '0x92a8d7fe':
return BRIDGE_MODES.NATIVE_TO_ERC
case '0xba4690f5':
return BRIDGE_MODES.ERC_TO_ERC
case '0x18762d46':
return BRIDGE_MODES.ERC_TO_NATIVE
default:
throw new Error(`Unrecognized bridge mode hash: '${bridgeModeHash}'`)
}
}
const decodeFeeManagerMode = managerModeHash => {
switch (managerModeHash) {
case '0xf2aed8f7':
return FEE_MANAGER_MODE.ONE_DIRECTION
case '0xd7de965f':
return FEE_MANAGER_MODE.BOTH_DIRECTIONS
default:
throw new Error(`Unrecognized fee manager mode hash: '${managerModeHash}'`)
}
}
async function getBridgeMode(contract) {
try {
const bridgeModeHash = await contract.methods.getBridgeMode().call()
return decodeBridgeMode(bridgeModeHash)
} catch (e) {
return BRIDGE_MODES.NATIVE_TO_ERC_V1
}
}
const getUnit = bridgeMode => {
let unitHome = null
let unitForeign = null
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
unitHome = 'Native coins'
unitForeign = 'Tokens'
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
unitHome = 'Tokens'
unitForeign = 'Tokens'
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
unitHome = 'Native coins'
unitForeign = 'Tokens'
} else {
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
}
return { unitHome, unitForeign }
}
module.exports = {
decodeBridgeMode,
decodeFeeManagerMode,
getBridgeMode,
getUnit
}

11
deployment/.yamllint Normal file

@ -0,0 +1,11 @@
extends: default
rules:
braces:
max-spaces-inside: 1
level: error
brackets:
max-spaces-inside: 1
level: error
line-length: disable
truthy: disable

@ -0,0 +1,98 @@
# POA Token Bridge / Deployment Configuration
Please see the [Oracle](../oracle/README.md) for additional configuration and execution details.
## Prerequisites
A functional Ubuntu 16.04 server launched using a trusted hosting provider. For more information, see our tutorials on [setting up a validator node on AWS](https://github.com/poanetwork/wiki/wiki/Validator-Node-on-AWS) or [setting up on non-AWS](https://github.com/poanetwork/wiki/wiki/Validator-Node-Non-AWS).
* Record the IP address (required for file setup).
* Setup ssh access to your node via public+private keys (using passwords is less secure).
* When creating the node, set a meaningful `hostname` that can identify you (e.g. `validator-0x...`).
## Initialization
1. Clone this repository and go to the `deployment` folder
```
git clone --recursive https://github.com/poanetwork/tokenbridge
cd tokenbridge/deployment
```
2. Create the file `hosts.yml` from `hosts.yml.example`
```
cp hosts.yml.example hosts.yml
```
`hosts.yml` should have the following structure:
```yaml
<bridge_name>:
children:
oracle:
hosts:
<host_ip_A>:
ansible_user: <user>
VALIDATOR_ADDRESS_PRIVATE_KEY: "<private_key>"
#syslog_server_port: "<protocol>://<ip>:<port>" # When this parameter is set all bridge logs will be redirected to <ip>:<port> address.
<host_ip_B>:
# (...)
ui:
hosts:
<host_ip_B>:
ansible_user: <user>
#syslog_server_port: "<protocol>://<ip>:<port>"
<host_ip_C>:
ansible_user: <user>
#syslog_server_port: "<protocol>://<ip>:<port>"
monitor:
hosts:
<host_ip_B>:
ansible_user: <user>
```
The config above would install the Oracle on `<host_ip_A>`, UI on `<host_ip_C>`, and both Oracle, UI and Monitor on `<host_ip_B>`.
Example config for installing only UI:
```yaml
<bridge_name>:
children:
oracle:
hosts:
ui:
hosts:
<host_ip>:
ansible_user: <user>
```
| Value | Description |
|:------------------------------------------------|:----------------------------------------------------------------------------------------------------------|
| `<bridge_name>` | The bridge name which tells Ansible which file to use. This is located in `group_vars/<bridge_name>.yml`. |
| `<host_ip>` | Remote server IP address. |
| ansible_user: `<user>` | User that will ssh into the node. This is typically `ubuntu` or `root`. |
| VALIDATOR_ADDRESS_PRIVATE_KEY: `"<private_key>"` | The private key for the specified validator address. |
| syslog_server_port: `"<protocol>://<ip>:<port>"` | Optional port specification for bridge logs. This value will be provided by an administrator if required. |
`hosts.yml` can contain multiple bridge configurations at once.
3. Copy the bridge name(s) to the hosts.yml file.
1. Go to the group_vars folder.
`cd group_vars`
2. Note the <bridge_name> and add it to the hosts.yml configuration. For example, if a bridge file is named sokol-kovan.yml, you would change the <bridge_name> value in hosts.yml to sokol-kovan.
## Administrator Configurations
1. The `group_vars/<bridge_name>.yml` file contains the public bridge parameters. This file is prepared by administrators for each bridge. The validator only needs to add the required bridge name in the hosts.yml file to tell Ansible which file to use.
`group_vars/example.yml` shows an example configuration for the POA/Sokol - POA/Sokol bridge. Parameter values should match values from the .env file for the Oracle. See [Configuration parameters](../../oracle/README.md#configuration-parameters) for details.
2. You can also add the following parameters in the `group_vars` to change the default behavior of the playbooks:
2.1 `compose_service_user` - specifies the user created by the playbooks. This user runs the Token Bridge Oracle.
2.2 `bridge_repo` contains the address of the Token Bridge Oracle repository. The default value is https://github.com/poanetwork/tokenbridge.
2.3 `bridge_repo_branch` points to the specific branch or commit to use with the `bridge_repo`. If `bridge_repo_branch` is not specified, the default (`master`) branch is used.
2.4 `bridge_path` sets the path where the Token Bridge Oracle is installed. By default, it points. to the home folder of `compose_service_user`
2.5 `docker_compose_version` - specifies a version of docker-compose to be installed.
2.6 `ALLOW_HTTP` (`no` by default) can be set to `yes` to allow bridge insecure connections to the network.

85
deployment/EXECUTION.md Normal file

@ -0,0 +1,85 @@
# POA Token Bridge / Deployment Execution
Please refer to the [Configuration](./CONFIGURATION.md) first.
## Dependencies
On your local machine install:
* Python 2 (v2.6-v2.7)/Python3 (v3.5+)
* [Ansible v2.3+](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)
* Git
The playbook will automatically install `Docker`, `docker-compose`, `Python`, `Git` and it dependencies (such as `curl`, `ca-certificates`, `apt-transport-https`, etc.) to the node. Also this playbooks creates an additional non-sudo docker user to run service as.
## Running the playbook
```yaml
ansible-playbook -i hosts.yml site.yml
```
## Useful arguments
To be used with the ansible-playbook command, for example:
```yaml
ansible-playbook -i hosts.yml site.yml --ask-become-pass
```
* `--ask-pass` - ask for the password used to connect to the bridge VM.
* `--ask-become-pass` - ask for the `become` password used to execute some commands (such as Docker installation) with root privileges.
* `-i <file>` - use specified file as a `hosts.yml` file.
* `-e "<variable>=<value>"` - override default variable.
* `--private-key=<file_name>` - if private keyfile is required to connect to the ubuntu instance.
* `--user=<username>` - connect as this username
## Service commands
The deployed components have the following services:
Component | Service Name
--- | ---
Oracle | poabridge
UI | tokenbridge-ui
Monitor | tokenbridge-monitor
Use the default `SysVinit` commands to `start`, `stop`, `restart`, and `rebuild` the service and to check the `status` of the service.
Commands format:
```bash
sudo service <service_name> [start|stop|restart|status|rebuild]
```
## Rollback the Last Processed Block in Redis
If the bridge does not handle an event properly (i.e. a transaction stalls due to a low gas price), the Redis DB can be rolled back. You must identify which watcher needs to re-run. For example, if the validator signatures were collected but the transaction with signatures was not sent to the Foreign network, the `collected-signatures` watcher must look at the block where the corresponding `CollectedSignatures` event was raised.
Execute the `reset-lastBlock.sh` script in the bridge root directory. For example, if you've installed your bridge with this deployment script and all the default parameters, use the following set of commands:
```shell
$ sudo su poadocker
$ cd ~/bridge
$ docker-compose stop bridge_affirmation bridge_request bridge_collected
$ docker-compose exec bridge_senderhome bash ./reset-lastBlock.sh <watcher> <block num>
$ exit
$ sudo service poabridge restart
```
where the _<watcher>_ could be one of the following:
- `signature-request`
- `collected-signatures`
- `affirmation-request`
## Logs
If the `syslog_server_port` option in the hosts.yml file is not set, all logs will be stored in `/var/log/docker/` folder in the set of folders with the `bridge_` prefix.
If the `syslog_server_port` is set, logs will be redirected to the specified server and cannot be accessed on the bridge machine.
```yaml
syslog_server_port: "<protocol>://<ip>:<port>" # When this parameter is set all bridge logs will be redirected to the <ip>:<port> address.
```

@ -4,30 +4,19 @@ Ansible playbooks for deploying cross-chain bridges.
## Overview ## Overview
Please refer to the [POA Token Bridge](../README.md) overview first of all. Please refer to the [POA Token Bridge](../README.md) overview first of all.
These playbooks are designed to automate the deployment process for cross-chain bridges on bridge validator nodes. This process installs the bridge as a service and sets .env configurations on a remote server. Playbooks for the current Token Bridge Oracle deployment are located in the [Oracle](oracle) folder. These playbooks are designed to automate the deployment process for cross-chain bridges on bridge validator nodes. This process installs the bridge as a service and sets .env configurations on a remote server.
## Dependencies
The playbooks automatically install `Docker`, `docker-compose`, `Python`, `Git`and it dependencies (such as `curl`, `ca-certificates`, `apt-transport-https`, etc.). Install [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) to launch playbooks.
## Linting
- [ansible-lint](https://github.com/ansible/ansible-lint) is required
`yarn ansible-lint`
## Configuration ## Configuration
Please see the [Oracle](../oracle/README.md) for configuration and execution details. Please refer to [Configuration](./CONFIGURATION.md).
## Bridge service commands ## Execution
The Bridge service is named `poabridge`. Use the default `SysVinit` commands to `start`, `stop`, `restart`, and `rebuild` the service and to check the `status` of the service. Please refer to [Execution](./EXECUTION.md).
Commands format: ## Testing
```bash
sudo service poabridge [start|stop|restart|status|rebuild] Please refer to [Testing](./molecule/TESTING.md).
```
## Contributing ## Contributing

@ -0,0 +1,54 @@
---
## General settings
BRIDGE_MODE: "ERC_TO_NATIVE"
HOME_NATIVE_NAME: "xDai"
## Home contract
HOME_RPC_URL: "https://dai.poa.network"
HOME_NAME: "xDai chain"
HOME_WITHOUT_EVENTS: false
HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
HOME_POLLING_INTERVAL: 5000
## Foreign contract
FOREIGN_RPC_URL: "https://mainnet.infura.io"
FOREIGN_NAME: "Ethereum Mainnet"
FOREIGN_WITHOUT_EVENTS: false
FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
ERC20_TOKEN_ADDRESS: "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"
FOREIGN_POLLING_INTERVAL: 5000
## Home Gasprice
# HOME_GAS_PRICE_ORACLE_URL: "https://localhost:8888/"
HOME_GAS_PRICE_SPEED_TYPE: "standard"
HOME_GAS_PRICE_FALLBACK: 0
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
## Foreign Gasprice
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
FOREIGN_GAS_PRICE_FALLBACK: 10000000000
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
FOREIGN_GAS_PRICE_FACTOR: 1
## UI
UI_TITLE: "TokenBridge UI app - %c"
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring MakerDAO stable tokens between the Ethereum network to xDai chain in a quick and cost-efficient manner."
UI_PORT: 3001
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/dai/tx/%s
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/mainnet/tx/%s
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/dai/address/%s
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
UI_HOME_GAS_PRICE_FALLBACK: 1000000000
UI_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
## Monitor
MONITOR_PORT: 3003
MONITOR_HOME_DEPLOYMENT_BLOCK: 759
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 6478417
MONITOR_HOME_GAS_LIMIT: 300000
MONITOR_FOREIGN_GAS_LIMIT: 300000
MONITOR_HOME_GAS_PRICE_FALLBACK: 0
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
MONITOR_LEFT_TX_THRESHOLD: 100
MONITOR_CRON_SCHEDULE: "* * * * *"

@ -0,0 +1,55 @@
---
## General settings
BRIDGE_MODE: "NATIVE_TO_ERC"
HOME_NATIVE_NAME: "POA"
## Home contract
HOME_RPC_URL: "https://sokol.poa.network"
HOME_NAME: "POA Sokol"
HOME_WITHOUT_EVENTS: false
HOME_BRIDGE_ADDRESS: "0x98aFdE294f1C46aA0a27Cc4049ED337F879d8976"
HOME_POLLING_INTERVAL: 5000
## Foreign contract
FOREIGN_RPC_URL: "https://sokol.poa.network"
FOREIGN_NAME: "Kovan"
FOREIGN_WITHOUT_EVENTS: false
FOREIGN_BRIDGE_ADDRESS: "0x5a584f4C30B36f282848dAc9a2b20E7BEF481981"
ERC20_TOKEN_ADDRESS: "0x6ef22442D600E1865AD8A8c254d6befCe7f4e6e4"
FOREIGN_POLLING_INTERVAL: 1000
## Home Gasprice
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
HOME_GAS_PRICE_SPEED_TYPE: "standard"
HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
HOME_GAS_PRICE_FACTOR: 1
## Foreign Gasprice
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
FOREIGN_GAS_PRICE_FACTOR: 1
## UI
UI_TITLE: "TokenBridge UI app - %c"
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
UI_PORT: 3001
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
UI_HOME_GAS_PRICE_FALLBACK: 1000000000
UI_FOREIGN_GAS_PRICE_FALLBACK: 1000000000
## Monitor
MONITOR_PORT: 3003
MONITOR_HOME_DEPLOYMENT_BLOCK: 0
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 0
MONITOR_HOME_GAS_LIMIT: 300000
MONITOR_FOREIGN_GAS_LIMIT: 300000
MONITOR_HOME_GAS_PRICE_FALLBACK: 1000000000
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 1000000000
MONITOR_LEFT_TX_THRESHOLD: 100
MONITOR_CRON_SCHEDULE: "* * * * *"

@ -0,0 +1,55 @@
---
## General settings
BRIDGE_MODE: "NATIVE_TO_ERC"
HOME_NATIVE_NAME: "ETC"
## Home contract
HOME_RPC_URL: "https://ethereumclassic.network"
HOME_NAME: "Ethereum Classic"
HOME_WITHOUT_EVENTS: false
HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
HOME_POLLING_INTERVAL: 7000
## Foreign contract
FOREIGN_RPC_URL: "https://mainnet.infura.io/"
FOREIGN_NAME: "Ethereum Mainnet"
FOREIGN_WITHOUT_EVENTS: false
FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
ERC20_TOKEN_ADDRESS: "0x86aaBCc646f290b9Fc9Bd05CE17C3858d1511Da1"
FOREIGN_POLLING_INTERVAL: 7000
## Home Gasprice
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice-etc.poa.network/"
HOME_GAS_PRICE_SPEED_TYPE: "standard"
HOME_GAS_PRICE_FALLBACK: 15000000000 # in wei
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
HOME_GAS_PRICE_FACTOR: 1
## Foreign Gasprice
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
FOREIGN_GAS_PRICE_FALLBACK: 10000000000 # in wei
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
FOREIGN_GAS_PRICE_FACTOR: 1
## UI
UI_TITLE: "TokenBridge UI app - %c"
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring native tokens from the Ethereum Classic Network to the Ethereum network in a quick and cost-efficient manner."
UI_PORT: 3001
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/etc/mainnet/tx/%s
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/mainnet/tx/%s
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/etc/mainnet/address/%s
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
UI_HOME_GAS_PRICE_FALLBACK: 15000000000
UI_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
## Monitor
MONITOR_PORT: 3003
MONITOR_HOME_DEPLOYMENT_BLOCK: 7703292
MONITOR_FOREIGN_DEPLOYMENT_BLOCK: 7412459
MONITOR_HOME_GAS_LIMIT: 300000
MONITOR_FOREIGN_GAS_LIMIT: 300000
MONITOR_HOME_GAS_PRICE_FALLBACK: 15000000000
MONITOR_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
MONITOR_LEFT_TX_THRESHOLD: 100
MONITOR_CRON_SCHEDULE: "* * * * *"

@ -0,0 +1,18 @@
---
sokol-kovan:
children:
oracle:
hosts:
127.0.0.1:
ansible_user: ubuntu
VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
#syslog_server_port: "udp://127.0.0.1:514"
ui:
hosts:
127.0.0.1:
ansible_user: ubuntu
#syslog_server_port: "udp://127.0.0.1:514"
monitor:
hosts:
127.0.0.1:
ansible_user: ubuntu

@ -1,3 +0,0 @@
#!/bin/bash
cd $(dirname $0)
ansible-lint -v -t bug ./oracle/roles/**

@ -0,0 +1,5 @@
FROM python:3.7-stretch
RUN curl -fsSL https://get.docker.com | sh
RUN pip3 install docker molecule==2.22rc1 molecule[docker] flake8
WORKDIR runner
COPY . .

@ -0,0 +1,32 @@
# POA Token Bridge / Deployment Testing
The deployment playbooks are tested using [Molecule](https://molecule.readthedocs.io).
## Push remote branch
The deployment playbooks are cloning the monorepository on target hosts, using your current local git branch name. If the branch does not exists on remote, you need to push it.
```
git push
```
Alternatively, if there are no changes except the playbooks, you can use the `master` branch:
```
CIRCLE_BRANCH=master ./molecule.sh <scenario_name>
```
In this case `master` branch will be used as a codebase for Monitor, UI, Oracle and Contracts deployed by your local playbook.
## Run the tests
```
CIRCLE_BRANCH=master ./molecule.sh <scenario_name>
```
Available scenarios:
Scenario | Description
--- | ---
oracle | Deploys and checks standalone Oracle on Ubuntu host
ui | Deploys and checks standalone UI on Ubuntu host

@ -0,0 +1,12 @@
---
version: '3.0'
services:
molecule_runner:
build:
context: ..
dockerfile: molecule/Dockerfile
restart: 'no'
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock

12
deployment/molecule/molecule.sh Executable file

@ -0,0 +1,12 @@
#!/usr/bin/env bash
cd $(dirname $0)
set -e # exit when any command fails
CODEBASE_BRANCH=${CIRCLE_BRANCH-$(git symbolic-ref --short HEAD)}
DOCKER_LOCALHOST=${DOCKER_LOCALHOST-localhost}
while [ "$1" != "" ]; do
docker-compose build && docker-compose run -e CODEBASE_BRANCH=$CODEBASE_BRANCH -e DOCKER_LOCALHOST=$DOCKER_LOCALHOST molecule_runner /bin/bash -c "molecule test --scenario-name $1"
shift # Shift all the parameters down by one
done

@ -0,0 +1,14 @@
# Molecule managed
{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi

@ -0,0 +1,57 @@
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
enabled: True
options:
config-data:
ignore: ../../hosts.yml
platforms:
- name: oracle-host
groups:
- example
children:
- oracle
image: ubuntu:16.04
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
provisioner:
name: ansible
lint:
name: ansible-lint
enabled: True
options:
r: ["bug"]
playbooks:
prepare: ../prepare.yml
converge: ../../site.yml
inventory:
host_vars:
oracle-host:
VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
syslog_server_port: "udp://127.0.0.1:514"
bridge_repo_branch: $CODEBASE_BRANCH
verifier:
name: testinfra
lint:
name: flake8
additional_files_or_dirs:
- ../../tests/*
scenario:
name: oracle
test_sequence:
- lint
- cleanup
- destroy
- dependency
- syntax
- create
- prepare
- converge
- verify
- destroy

@ -0,0 +1,13 @@
---
- name: prepare
hosts: all
tasks:
- name: install apt packages
apt:
name: "{{ packages }}"
vars:
packages:
- apt-transport-https
- rsyslog
- shell: service rsyslog start
- shell: groupadd docker && chgrp docker /var/run/docker.sock

@ -0,0 +1,38 @@
import os
import pytest
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle')
@pytest.mark.parametrize("name", [
("oracle_rabbit_1"),
("oracle_redis_1"),
("oracle_bridge_request_1"),
("oracle_bridge_collected_1"),
("oracle_bridge_affirmation_1"),
("oracle_bridge_senderhome_1"),
("oracle_bridge_senderforeign_1"),
])
def test_docker_containers(host, name):
container = host.docker(name)
assert container.is_running
@pytest.mark.parametrize("service", [
("poabridge"),
("rsyslog")
])
def test_services(host, service):
assert host.service(service).is_enabled
assert host.service(service).is_running
@pytest.mark.parametrize("filename", [
("/etc/rsyslog.d/31-oracle-docker.conf"),
("/etc/rsyslog.d/36-oracle-remote-logging.conf")
])
def test_logging(host, filename):
assert host.file(filename).exists
assert host.file(filename).mode == 0o0644

@ -0,0 +1,13 @@
---
- name: prepare
hosts: all
tasks:
- name: install apt packages
apt:
name: "{{ packages }}"
vars:
packages:
- apt-transport-https
- rsyslog
- shell: service rsyslog start
- shell: groupadd docker && chgrp docker /var/run/docker.sock

@ -0,0 +1,34 @@
import os
import pytest
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
def test_repo(host):
assert host.file('/home/poadocker/bridge').exists
assert host.file('/home/poadocker/bridge').is_directory
assert host.file('/home/poadocker/bridge/package.json').exists
def test_docker_group(host):
assert host.group('docker').exists
def test_user(host):
assert host.user('poadocker').exists
assert 'docker' in host.user('poadocker').groups
@pytest.mark.parametrize("filename", [
("/etc/rsyslog.d/30-docker.conf"),
("/etc/rsyslog.d/35-docker-remote-logging.conf")
])
def test_logging(host, filename):
assert host.file(filename).exists
assert host.file(filename).mode == 0o0644
def test_docker_config(host):
assert host.file('/etc/docker/daemon.json').exists

@ -0,0 +1,14 @@
# Molecule managed
{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi

@ -0,0 +1,56 @@
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
enabled: True
options:
config-data:
ignore: ../../hosts.yml
platforms:
- name: ui-host
groups:
- example
children:
- ui
image: ubuntu:16.04
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
provisioner:
name: ansible
lint:
name: ansible-lint
enabled: True
options:
r: ["bug"]
playbooks:
prepare: ../prepare.yml
converge: ../../site.yml
inventory:
host_vars:
ui-host:
syslog_server_port: "udp://127.0.0.1:514"
bridge_repo_branch: $CODEBASE_BRANCH
verifier:
name: testinfra
lint:
name: flake8
additional_files_or_dirs:
- ../../tests/*
scenario:
name: ui
test_sequence:
- lint
- cleanup
- destroy
- dependency
- syntax
- create
- prepare
- converge
- verify
- destroy

@ -0,0 +1,48 @@
import os
import pytest
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('ui')
@pytest.mark.parametrize("name", [
("ui_ui_1")
])
def test_docker_containers(host, name):
container = host.docker(name)
assert container.is_running
@pytest.mark.parametrize("service", [
("tokenbridge-ui"),
("rsyslog")
])
def test_services(host, service):
assert host.service(service).is_enabled
assert host.service(service).is_running
@pytest.mark.parametrize("filename", [
("/etc/rsyslog.d/32-ui-docker.conf"),
("/etc/rsyslog.d/37-ui-remote-logging.conf")
])
def test_logging(host, filename):
assert host.file(filename).exists
assert host.file(filename).mode == 0o0644
def test_index_page_title(host):
assert host.run_test(
'curl -s http://localhost:3001 | '
'grep "<title>" | '
'grep -q "TokenBridge UI app"'
)
def test_index_page_error(host):
assert host.run_expect(
[1],
'curl -s http://localhost:3001 | '
'grep -i -q "error"'
)

@ -0,0 +1,14 @@
# Molecule managed
{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi

@ -0,0 +1,47 @@
---
driver:
name: docker
platforms:
- name: oracle-native-to-erc-host
groups:
- example
children:
- oracle
image: ubuntu:16.04
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
provisioner:
name: ansible
playbooks:
prepare: ../prepare.yml
converge: ../../site.yml
inventory:
host_vars:
oracle-native-to-erc-host:
bridge_repo_branch: $CODEBASE_BRANCH
VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
HOME_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
FOREIGN_BRIDGE_ADDRESS: "0x2B6871b9B02F73fa24F4864322CdC78604207769"
ERC20_TOKEN_ADDRESS: "0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B"
QUEUE_URL: "amqp://$DOCKER_LOCALHOST"
REDIS_URL: "redis://$DOCKER_LOCALHOST:6379"
HOME_RPC_URL: "http://$DOCKER_LOCALHOST:8541"
FOREIGN_RPC_URL: "http://$DOCKER_LOCALHOST:8542"
ALLOW_HTTP: yes
LOG_LEVEL: debug
verifier:
name: testinfra
lint:
name: flake8
scenario:
name: ultimate-native-to-erc
test_sequence:
- cleanup
- destroy
- syntax
- create
- prepare
- converge

@ -1,138 +0,0 @@
### Prerequisites
1. A functional Ubuntu 16.04 server launched using a trusted hosting provider. For more information, see our tutorials on [setting up a validator node on AWS](https://github.com/poanetwork/wiki/wiki/Validator-Node-on-AWS) or [setting up on non-AWS](https://github.com/poanetwork/wiki/wiki/Validator-Node-Non-AWS).
* Record the IP address (required for file setup).
* Setup ssh access to your node via public+private keys (using passwords is less secure).
* When creating the node, set a meaningful `hostname` that can identify you (e.g. `validator-0x...`).
2. On your local machine install:
* Python 2 (v2.6-v2.7)/Python3 (v3.5+)
* Ansible v2.3+
* Git
### Configuration
1. Clone this repository and go to the `deployment/oracle` folder
```
git clone --recursive https://github.com/poanetwork/tokenbridge
cd tokenbridge/deployment/oracle
```
2. Create the file `hosts.yml` from `hosts.yml.example`
```
cp hosts.yml.example hosts.yml
```
`hosts.yml` should have the following structure:
```yaml
<bridge_name>:
hosts:
<host_ip>:
ansible_user: <user>
VALIDATOR_ADDRESS_PRIVATE_KEY: "<private_key>"
#syslog_server_port: "<protocol>://<ip>:<port>" # When this parameter is set all bridge logs will be redirected to <ip>:<port> address.
```
| Value | Description |
|:------------------------------------------------|:----------------------------------------------------------------------------------------------------------|
| `<bridge_name>` | The bridge name which tells Ansible which file to use. This is located in `group_vars/<bridge_name>.yml`. |
| `<host_ip>` | Remote server IP address. |
| ansible_user: `<user>` | User that will ssh into the node. This is typically `ubuntu` or `root`. |
| VALIDATOR_ADDRESS_PRIVATE_KEY: `"<private_key>"` | The private key for the specified validator address. |
| syslog_server_port: `"<protocol>://<ip>:<port>"` | Optional port specification for bridge logs. This value will be provided by an administrator if required. |
`hosts.yml` can contain multiple hosts and bridge configurations (groups) at once.
3. Copy the bridge name(s) to the hosts.yml file.
1. Go to the group_vars folder.
`cd group_vars`
2. Note the <bridge_name> and add it to the hosts.yml configuration. For example, if a bridge file is named sokol-kovan.yml, you would change the <bridge_name> value in hosts.yml to sokol-kovan.
#### Administrator Configurations
1. The `group_vars/<bridge_name>.yml` file contains the public bridge parameters. This file is prepared by administrators for each bridge. The validator only needs to add the required bridge name in the hosts.yml file to tell Ansible which file to use.
`group_vars/example.yml` shows an example configuration for the POA/Sokol - POA/Sokol bridge. Parameter values should match values from the .env file for the Oracle. See [Configuration parameters](../../oracle/README.md#configuration-parameters) for details.
2. You can also add the following parameters in the `group_vars` to change the default behavior of `deployment-bridge` playbooks:
2.1 `compose_service_user` - specifies users to be created by playbooks. This user will be used to run Token Bridge Oracle.
2.2 `bridge_repo` contains address of Token Bridge Oracle repository. The default value is https://github.com/poanetwork/tokenbridge.
2.3 `bridge_repo_branch` points to the specific branch or commit to use with the `bridge_repo`. If `bridge_repo_branch` is not specified, the default (`master`) branch is used.
2.4 `bridge_path` set the path where Token Bridge Oracle would be installed. By default it point to the home folder of `compose_service_user`
2.5 `docker_compose_version` - specifies a version of docker-compose to be installed.
2.6 `ALLOW_HTTP` (`no` by default) can be set to `yes` to allow bridge insecure connections to the network.
## Execution
The playbook can be executed once [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) is installed and all configuration variables are set.
It will automatically install `Docker`, `docker-compose`, `Python`, `Git` and it dependencies (such as `curl`, `ca-certificates`, `apt-transport-https`, etc.) to the node. Also this playbooks creates an additional non-sudo docker user to run service as.
```yaml
ansible-playbook -i hosts.yml site.yml
```
**Useful arguments:**
To be used with the ansible-playbook command, for example:
```yaml
`ansible-playbook -i hosts.yml site.yml --ask-become-pass`
```
* `--ask-pass` - ask for the password used to connect to the bridge VM.
* `--ask-become-pass` - ask for the `become` password used to execute some commands (such as Docker installation) with root privileges.
* `-i <file>` - use specified file as a `hosts.yml` file.
* `-e "<variable>=<value>"` - override default variable.
* `--private-key=<file_name>` - if private keyfile is required to connect to the ubuntu instance.
* `--user=<username>` - connect as this username
## Bridge service commands
The Bridge service is named `poabridge`. Use the default `SysVinit` commands to `start`, `stop`, `restart`, and `rebuild` the service and to check the `status` of the service.
Commands format:
```bash
sudo service poabridge [start|stop|restart|status|rebuild]
```
## Rollback the Last Processed Block in Redis
If the bridge does not handle an event properly (i.e. a transaction stalls due to a low gas price), the Redis DB can be rolled back. You must identify which watcher needs to re-run. For example, if the validator signatures were collected but the transaction with signatures was not sent to the Foreign network, the `collected-signatures` watcher must look at the block where the corresponding `CollectedSignatures` event was raised.
Execute the `reset-lastBlock.sh` script in the bridge root directory. For example, if you've installed your bridge with this deployment script and all the default parameters, use the following set of commands:
```shell
$ sudo su poadocker
$ cd ~/bridge
$ docker-compose exec bridge_affirmation bash ./reset-lastBlock.sh <watcher> <block num>
$ exit
$ sudo service poabridge restart
```
where the _<watcher>_ could be one of the following:
- `signature-request`
- `collected-signatures`
- `affirmation-request`
## Logs
If the `syslog_server_port` option in the hosts.yml file is not set, all logs will be stored in `/var/log/docker/` folder in the set of folders with the `bridge_` prefix.
If the `syslog_server_port` is set, logs will be redirected to the specified server and cannot be accessed on the bridge machine.
```yaml
syslog_server_port: "<protocol>://<ip>:<port>" # When this parameter is set all bridge logs will be redirected to the <ip>:<port> address.
```

@ -1,24 +0,0 @@
## General settings
BRIDGE_MODE: "ERC_TO_NATIVE"
## Home contract
HOME_RPC_URL: "https://dai.poa.network"
HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
HOME_POLLING_INTERVAL: 5000
## Foreign contract
FOREIGN_RPC_URL: "https://mainnet.infura.io"
FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
ERC20_TOKEN_ADDRESS: "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"
FOREIGN_POLLING_INTERVAL: 5000
## Gasprice
#HOME_GAS_PRICE_ORACLE_URL: "https://localhost:8888/"
HOME_GAS_PRICE_SPEED_TYPE: "standard"
HOME_GAS_PRICE_FALLBACK: 0
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
FOREIGN_GAS_PRICE_FALLBACK: 10000000000
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000

@ -1,24 +0,0 @@
## General settings
BRIDGE_MODE: "NATIVE_TO_ERC"
## Home contract
HOME_RPC_URL: "https://sokol.poa.network"
HOME_BRIDGE_ADDRESS: "0x98aFdE294f1C46aA0a27Cc4049ED337F879d8976"
HOME_POLLING_INTERVAL: 5000
## Foreign contract
FOREIGN_RPC_URL: "https://sokol.poa.network"
FOREIGN_BRIDGE_ADDRESS: "0x5a584f4C30B36f282848dAc9a2b20E7BEF481981"
ERC20_TOKEN_ADDRESS: "0x6ef22442D600E1865AD8A8c254d6befCe7f4e6e4"
FOREIGN_POLLING_INTERVAL: 1000
## Gasprice
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
HOME_GAS_PRICE_SPEED_TYPE: "standard"
HOME_GAS_PRICE_FALLBACK: 1000000000 # in wei
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000

@ -1,24 +0,0 @@
## General settings
BRIDGE_MODE: "NATIVE_TO_ERC"
## Home contract
HOME_RPC_URL: "https://ethereumclassic.network"
HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
HOME_POLLING_INTERVAL: 7000
## Foreign contract
FOREIGN_RPC_URL: "https://mainnet.infura.io/"
FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
ERC20_TOKEN_ADDRESS: "0x86aaBCc646f290b9Fc9Bd05CE17C3858d1511Da1"
FOREIGN_POLLING_INTERVAL: 7000
## Gasprice
HOME_GAS_PRICE_ORACLE_URL: "https://gasprice-etc.poa.network/"
HOME_GAS_PRICE_SPEED_TYPE: "standard"
HOME_GAS_PRICE_FALLBACK: 15000000000 # in wei
HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
FOREIGN_GAS_PRICE_ORACLE_URL: "https://gasprice.poa.network/"
FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
FOREIGN_GAS_PRICE_FALLBACK: 10000000000 # in wei
FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000

@ -1,6 +0,0 @@
sokol-kovan:
hosts:
127.0.0.1:
ansible_user: ubuntu
VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
#syslog_server_port: "udp://127.0.0.1:514"

@ -1,17 +0,0 @@
This role installs required dependencies:
* apt-transport-https
* ca-certificates
* curl
* software-properties-common
* docker-ce (+python library)
* docker-compose (+python library)
* git
* python-pip

@ -1,2 +0,0 @@
docker_compose_version: 1.22.0
compose_service_user: poadocker

@ -1 +0,0 @@
This role brings up a docker container using docker-compose.

@ -1 +0,0 @@
bridge_path: "/home/{{ compose_service_user }}/bridge"

@ -1,4 +0,0 @@
- name: Launch container
shell: docker-compose up -d
args:
chdir: "{{ bridge_path }}/oracle"

@ -1 +0,0 @@
This role sets up remote logging for services.

@ -1,2 +0,0 @@
bridge_path: "/home/{{ compose_service_user }}/bridge"
syslog_server_port: udp://127.0.0.1:514

@ -1 +0,0 @@
This role gets the start blocks for both home and foreign networks.

@ -1 +0,0 @@
bridge_path: "/home/{{ compose_service_user }}/bridge"

@ -1 +0,0 @@
This role sets the .env config (excluding starting blocks).

@ -1 +0,0 @@
This role clones the repo from a specified URL.

@ -1,5 +0,0 @@
This role creates a poabridge service which is designed to manage docker-compose bridge deployment.
/etc/init.d/poabridge start, status, stop, restart - does what the services usually do in such cases.
/etc/init.d/poabridge rebuild - builds a new bridge deployment from scratch.

@ -1,4 +0,0 @@
---
# defaults
bridge_path: "/home/{{ compose_service_user }}/bridge"
keyfile_path: "/root/.key"

@ -1,14 +0,0 @@
---
- name: "Set poabridge service"
template:
src: poabridge.j2
dest: "/etc/init.d/poabridge"
owner: root
mode: 755
- name: "Start/Enable poabridge service"
service:
name: "poabridge"
state: started
enabled: yes
use: service

@ -1,19 +0,0 @@
- name: Install python if necessary
hosts: all
gather_facts: false
become: true
tasks:
- name: Install python
raw: "test -e {{ ansible_python_interpreter | default ('/usr/bin/python') }} || (sudo apt -y update && sudo apt install -y python-minimal)"
tags: install_dependencies
- name: Install bridge
hosts: all
roles:
- { role: dependencies, tags: install_dependencies, become: true }
- { role: repo, tags: clone_repo, become: true }
- { role: pre_config, tags: pre_config, become: true }
- { role: jumpbox, tags: launch_jumpbox, become: true }
- { role: post_config, tags: post_config, become: true }
- { role: logging, tags: set_logging, become: true}
- { role: servinstall, tags: install_service, become: true }

@ -0,0 +1,4 @@
# pre-release because it contains "CI Fixes for ansible 2.8"
molecule==2.22rc1
docker
flake8

@ -1,3 +1,6 @@
---
docker_compose_version: 1.23.2
compose_service_user: poadocker
bridge_path: "/home/{{ compose_service_user }}/bridge" bridge_path: "/home/{{ compose_service_user }}/bridge"
bridge_repo: https://github.com/poanetwork/tokenbridge.git bridge_repo: https://github.com/poanetwork/tokenbridge.git
bridge_repo_branch: master bridge_repo_branch: master

@ -1,3 +1,4 @@
---
- name: restart rsyslog - name: restart rsyslog
service: service:
name: rsyslog name: rsyslog

@ -1,3 +1,4 @@
---
- name: Install the gpg key for docker - name: Install the gpg key for docker
apt_key: apt_key:
url: "https://download.docker.com/linux/ubuntu/gpg" url: "https://download.docker.com/linux/ubuntu/gpg"
@ -19,7 +20,8 @@
- software-properties-common - software-properties-common
- docker-ce - docker-ce
- git - git
- "{{ (ansible_python_interpreter | default ('python')).split('/')[-1] }}-pip" - python3
- python3-pip
- name: Install Docker Compose - name: Install Docker Compose
get_url: get_url:
@ -31,11 +33,7 @@
mode: "0755" mode: "0755"
- name: Install python docker library - name: Install python docker library
pip: shell: pip3 install docker docker-compose setuptools
name: "{{ item }}"
with_items:
- docker
- docker-compose
- name: Add user to run docker-compose - name: Add user to run docker-compose
user: user:
@ -67,7 +65,7 @@
- name: Configure docker engine - name: Configure docker engine
copy: copy:
src: daemon.json src: daemon.json
dest: /etc/docker/daemon.json dest: /etc/docker/
owner: root owner: root
group: root group: root
mode: 0640 mode: 0640

@ -0,0 +1,30 @@
---
- name: Set the local docker logs configuration file
template:
src: 30-docker.conf.j2
dest: /etc/rsyslog.d/30-docker.conf
owner: root
group: root
mode: 0644
- name: Set the log configuration file to send docker logs to remote server
template:
src: 35-docker-remote-logging.conf.j2
dest: /etc/rsyslog.d/35-docker-remote-logging.conf
owner: root
group: root
mode: 0644
when: syslog_server_port is defined
- name: Set the logrotate config file
template:
src: docker-logs.j2
dest: /etc/logrotate.d/docker-logs
owner: root
group: root
mode: 0644
- name: restart rsyslog
service:
name: rsyslog
state: restarted

@ -0,0 +1,4 @@
---
- include_tasks: dependencies.yml
- include_tasks: repo.yml
- include_tasks: logging.yml

@ -1,6 +1,8 @@
---
- name: Get bridge repo - name: Get bridge repo
git: git:
repo: "{{ bridge_repo }}" repo: "{{ bridge_repo }}"
dest: "{{ bridge_path }}" dest: "{{ bridge_path }}"
force: yes force: no
update: no
version: "{{ bridge_repo_branch }}" version: "{{ bridge_repo_branch }}"

@ -0,0 +1,6 @@
$FileCreateMode 0644
if $programname startswith 'docker' then \
/var/log/docker/no_tag/docker.log
$FileCreateMode 0600

@ -11,7 +11,7 @@ template(name="RemoteForwardFormat" type="list") {
property(name="msg") property(name="msg")
} }
if $programname startswith 'oracle_bridge_' or $programname startswith 'docker' then { if $programname startswith 'docker' then {
action( action(
type="omfwd" type="omfwd"
protocol="{{ syslog_server_port.split(":")[0] }}" protocol="{{ syslog_server_port.split(":")[0] }}"

@ -0,0 +1,3 @@
---
dependencies:
- role: common

@ -0,0 +1,5 @@
---
- name: Build the containers
shell: docker-compose build
args:
chdir: "{{ bridge_path }}/monitor"

@ -0,0 +1,4 @@
---
- include_tasks: pre_config.yml
- include_tasks: jumpbox.yml
- include_tasks: servinstall.yml

@ -0,0 +1,5 @@
---
- name: Install .env config
template:
src: .env.j2
dest: "{{ bridge_path }}/monitor/.env"

@ -0,0 +1,20 @@
# This role creates a tokenbridge-monitor service which is designed to manage docker-compose monitor deployment.
# /etc/init.d/tokenbridge-monitor start, status, stop, restart - does what the services usually do in such cases.
# /etc/init.d/tokenbridge-monitor rebuild - builds a new monitor deployment from scratch.
---
- name: "Set the service"
template:
src: tokenbridge-monitor.j2
dest: "/etc/init.d/tokenbridge-monitor"
owner: root
mode: 755
- name: "Enable the service"
service:
name: "tokenbridge-monitor"
state: started
enabled: yes
use: service
- name: Start the service
shell: service tokenbridge-monitor start

@ -0,0 +1,25 @@
HOME_RPC_URL={{ HOME_RPC_URL }}
FOREIGN_RPC_URL={{ FOREIGN_RPC_URL }}
HOME_BRIDGE_ADDRESS={{ HOME_BRIDGE_ADDRESS }}
FOREIGN_BRIDGE_ADDRESS={{ FOREIGN_BRIDGE_ADDRESS }}
HOME_DEPLOYMENT_BLOCK={{ MONITOR_HOME_DEPLOYMENT_BLOCK }}
FOREIGN_DEPLOYMENT_BLOCK={{ MONITOR_FOREIGN_DEPLOYMENT_BLOCK }}
HOME_GAS_LIMIT={{ MONITOR_HOME_GAS_LIMIT }}
{% if HOME_GAS_PRICE_ORACLE_URL | default('') != '' %}
HOME_GAS_PRICE_ORACLE_URL={{ HOME_GAS_PRICE_ORACLE_URL }}
{% endif %}
{% if HOME_GAS_PRICE_SPEED_TYPE | default('') != '' %}
HOME_GAS_PRICE_SPEED_TYPE={{ HOME_GAS_PRICE_SPEED_TYPE }}
{% endif %}
HOME_GAS_PRICE_FALLBACK={{ MONITOR_HOME_GAS_PRICE_FALLBACK }}
{% if HOME_GAS_PRICE_FACTOR | default('') != '' %}
HOME_GAS_PRICE_FACTOR={{ HOME_GAS_PRICE_FACTOR }}
{% endif %}
FOREIGN_GAS_LIMIT={{ MONITOR_FOREIGN_GAS_LIMIT }}
FOREIGN_GAS_PRICE_ORACLE_URL={{ FOREIGN_GAS_PRICE_ORACLE_URL }}
FOREIGN_GAS_PRICE_SPEED_TYPE={{ FOREIGN_GAS_PRICE_SPEED_TYPE }}
FOREIGN_GAS_PRICE_FALLBACK={{ MONITOR_FOREIGN_GAS_PRICE_FALLBACK }}
FOREIGN_GAS_PRICE_FACTOR={{ FOREIGN_GAS_PRICE_FACTOR }}
LEFT_TX_THRESHOLD={{ MONITOR_LEFT_TX_THRESHOLD }}
PORT={{ MONITOR_PORT }}
CRON_SCHEDULE={{ MONITOR_CRON_SCHEDULE }}

@ -0,0 +1,76 @@
#! /bin/bash
### BEGIN INIT INFO
# Provides: tokenbridge-monitor
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
WORKDIR="{{ '/home/' + compose_service_user | default('poadocker') + '/' + bridge_path + '/monitor' if bridge_path[:1] != "/" else bridge_path + '/monitor' }}"
start(){
echo "Starting TokenBridge Monitor.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach
}
stop(){
echo "Stopping TokenBridge Monitor.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sleep 2
}
status(){
echo "TokenBridge Monitor status:"
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose ps
}
rebuild(){
echo "Rebuild TokenBridge Monitor.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach --force-recreate --no-deps --build
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
echo "Restarting TokenBridge Monitor.."
stop
start
;;
rebuild)
rebuild
;;
*)
echo $"Usage: $0 {start|stop|restart|rebuild|status}"
exit 1
;;
esac
exit 0

@ -1,6 +1,7 @@
---
bridge_path: "/home/{{ compose_service_user }}/bridge" bridge_path: "/home/{{ compose_service_user }}/bridge"
ALLOW_HTTP: no ALLOW_HTTP: no
QUEUE_URL: amqp://rabbit QUEUE_URL: amqp://rabbit
REDIS_URL: redis://redis REDIS_URL: redis://redis
REDIS_LOCK_TTL: 1000 syslog_server_port: udp://127.0.0.1:514
keyfile_path: "/root/.key"

@ -0,0 +1,3 @@
---
dependencies:
- role: common

@ -0,0 +1,5 @@
---
- name: Build the containers
shell: docker-compose build
args:
chdir: "{{ bridge_path }}/oracle"

@ -1,3 +1,4 @@
---
- name: Slurp docker compose file - name: Slurp docker compose file
slurp: slurp:
src: "{{ bridge_path }}/oracle/docker-compose.yml" src: "{{ bridge_path }}/oracle/docker-compose.yml"
@ -19,29 +20,21 @@
- name: Set the local container logs configuration file - name: Set the local container logs configuration file
template: template:
src: 30-docker.conf.j2 src: 31-oracle-docker.conf.j2
dest: /etc/rsyslog.d/30-docker.conf dest: /etc/rsyslog.d/31-oracle-docker.conf
owner: root owner: root
group: root group: root
mode: 0644 mode: 0644
- name: Set the log configuration file to send container logs to remote server - name: Set the log configuration file to send container logs to remote server
template: template:
src: 35-remote-logging.conf.j2 src: 36-oracle-remote-logging.conf.j2
dest: /etc/rsyslog.d/35-remote-logging.conf dest: /etc/rsyslog.d/36-oracle-remote-logging.conf
owner: root owner: root
group: root group: root
mode: 0644 mode: 0644
when: syslog_server_port is defined when: syslog_server_port is defined
- name: Set the logrotate config file
template:
src: docker-logs.j2
dest: /etc/logrotate.d/docker-logs
owner: root
group: root
mode: 0644
- name: Discarding unwanted messages in rsyslog - name: Discarding unwanted messages in rsyslog
blockinfile: blockinfile:
path: /etc/rsyslog.conf path: /etc/rsyslog.conf

@ -0,0 +1,6 @@
---
- include_tasks: pre_config.yml
- include_tasks: logging.yml
- include_tasks: jumpbox.yml
- include_tasks: post_config.yml
- include_tasks: servinstall.yml

@ -1,3 +1,4 @@
---
- name: Get blocks - name: Get blocks
become_user: "{{ compose_service_user }}" become_user: "{{ compose_service_user }}"
shell: docker-compose run --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation shell: docker-compose run --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation

@ -1,3 +1,4 @@
---
- name: Install .env config - name: Install .env config
template: template:
src: .env.j2 src: .env.j2

@ -0,0 +1,20 @@
# This role creates a poabridge service which is designed to manage docker-compose bridge deployment.
# /etc/init.d/poabridge start, status, stop, restart - does what the services usually do in such cases.
# /etc/init.d/poabridge rebuild - builds a new bridge deployment from scratch.
---
- name: "Set poabridge service"
template:
src: poabridge.j2
dest: "/etc/init.d/poabridge"
owner: root
mode: 755
- name: "Enable the service"
service:
name: "poabridge"
state: started
enabled: yes
use: service
- name: Start the service
shell: service poabridge start

@ -23,6 +23,9 @@ HOME_GAS_PRICE_FALLBACK={{ HOME_GAS_PRICE_FALLBACK }}
{% if HOME_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %} {% if HOME_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
HOME_GAS_PRICE_UPDATE_INTERVAL={{ HOME_GAS_PRICE_UPDATE_INTERVAL }} HOME_GAS_PRICE_UPDATE_INTERVAL={{ HOME_GAS_PRICE_UPDATE_INTERVAL }}
{% endif %} {% endif %}
{% if HOME_GAS_PRICE_FACTOR | default('') != '' %}
HOME_GAS_PRICE_FACTOR={{ HOME_GAS_PRICE_FACTOR }}
{% endif %}
{% if FOREIGN_GAS_PRICE_ORACLE_URL | default('') != '' %} {% if FOREIGN_GAS_PRICE_ORACLE_URL | default('') != '' %}
FOREIGN_GAS_PRICE_ORACLE_URL={{ FOREIGN_GAS_PRICE_ORACLE_URL }} FOREIGN_GAS_PRICE_ORACLE_URL={{ FOREIGN_GAS_PRICE_ORACLE_URL }}
@ -34,9 +37,11 @@ FOREIGN_GAS_PRICE_FALLBACK={{ FOREIGN_GAS_PRICE_FALLBACK }}
{% if FOREIGN_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %} {% if FOREIGN_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ FOREIGN_GAS_PRICE_UPDATE_INTERVAL }} FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ FOREIGN_GAS_PRICE_UPDATE_INTERVAL }}
{% endif %} {% endif %}
{% if FOREIGN_GAS_PRICE_FACTOR | default('') != '' %}
FOREIGN_GAS_PRICE_FACTOR={{ FOREIGN_GAS_PRICE_FACTOR }}
{% endif %}
## Transport configuration ## Transport configuration
ALLOW_HTTP={{ "yes" if ALLOW_HTTP else "no" }} ALLOW_HTTP={{ "yes" if ALLOW_HTTP else "no" }}
QUEUE_URL={{ QUEUE_URL }} QUEUE_URL={{ QUEUE_URL }}
REDIS_URL={{ REDIS_URL }} REDIS_URL={{ REDIS_URL }}
REDIS_LOCK_TTL={{ REDIS_LOCK_TTL }}

@ -1,12 +1,11 @@
$FileCreateMode 0644 $FileCreateMode 0644
template(name="DockerLogFileName" type="list") { template(name="DockerLogFileName_Oracle" type="list") {
constant(value="/var/log/docker/") constant(value="/var/log/docker/")
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="bridge_(.*)\\/[a-zA-Z0-9]+\\[") property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="bridge_(.*)\\/[a-zA-Z0-9]+\\[")
constant(value="/docker.log") constant(value="/docker.log")
} }
if $programname startswith 'oracle_bridge_' then \ if $programname startswith 'oracle_bridge_' then \
?DockerLogFileName ?DockerLogFileName_Oracle
else
/var/log/docker/no_tag/docker.log
$FileCreateMode 0600 $FileCreateMode 0600

@ -0,0 +1,15 @@
if $programname startswith 'oracle_bridge_' then {
action(
type="omfwd"
protocol="{{ syslog_server_port.split(":")[0] }}"
target="{{ (syslog_server_port.split(":")[1])[2:] }}"
port="{{ syslog_server_port.split(":")[2] }}"
template="RemoteForwardFormat"
queue.SpoolDirectory="/var/spool/rsyslog"
queue.FileName="remote"
queue.MaxDiskSpace="1g"
queue.SaveOnShutdown="on"
queue.Type="LinkedList"
ResendLastMSGOnReconnect="on"
)
}

@ -0,0 +1,3 @@
---
dependencies:
- role: common

@ -0,0 +1,5 @@
---
- name: Build the containers
shell: docker-compose build
args:
chdir: "{{ bridge_path }}/ui"

@ -0,0 +1,41 @@
---
- name: Slurp docker compose file
slurp:
src: "{{ bridge_path }}/ui/docker-compose.yml"
register: docker_compose_slurp
- name: Parse docker compose file
set_fact:
docker_compose_parsed: "{{ docker_compose_slurp['content'] | b64decode | from_yaml }}"
- name: Set logger to remote server
set_fact:
docker_compose_parsed: "{{ docker_compose_parsed |combine({'services': {item: {'logging': {'driver': 'syslog','options': {'tag': '{{.Name}}/{{.ID}}'}}}}}, recursive=True) }}"
with_items: "{{ docker_compose_parsed.services }}"
- name: Write new docker-compose file
copy:
content: "{{ docker_compose_parsed | to_yaml }}"
dest: "{{ bridge_path }}/ui/docker-compose.yml"
- name: Set the local container logs configuration file
template:
src: 32-ui-docker.conf.j2
dest: /etc/rsyslog.d/32-ui-docker.conf
owner: root
group: root
mode: 0644
- name: Set the log configuration file to send container logs to remote server
template:
src: 37-ui-remote-logging.conf.j2
dest: /etc/rsyslog.d/37-ui-remote-logging.conf
owner: root
group: root
mode: 0644
when: syslog_server_port is defined
- name: restart rsyslog
service:
name: rsyslog
state: restarted

@ -0,0 +1,5 @@
---
- include_tasks: pre_config.yml
- include_tasks: logging.yml
- include_tasks: jumpbox.yml
- include_tasks: servinstall.yml

@ -0,0 +1,5 @@
---
- name: Install .env config
template:
src: .env.j2
dest: "{{ bridge_path }}/ui/.env"

@ -0,0 +1,20 @@
# This role creates a tokenbridge-ui service which is designed to manage docker-compose ui deployment.
# /etc/init.d/tokenbridge-ui start, status, stop, restart - does what the services usually do in such cases.
# /etc/init.d/tokenbridge-ui rebuild - builds a new ui deployment from scratch.
---
- name: "Set the service"
template:
src: tokenbridge-ui.j2
dest: "/etc/init.d/tokenbridge-ui"
owner: root
mode: 755
- name: "Enable the service"
service:
name: "tokenbridge-ui"
state: started
enabled: yes
use: service
- name: Start the service
shell: service tokenbridge-ui start

@ -0,0 +1,38 @@
REACT_APP_HOME_BRIDGE_ADDRESS={{ HOME_BRIDGE_ADDRESS }}
REACT_APP_FOREIGN_BRIDGE_ADDRESS={{ FOREIGN_BRIDGE_ADDRESS }}
REACT_APP_FOREIGN_HTTP_PARITY_URL={{ FOREIGN_RPC_URL }}
REACT_APP_HOME_HTTP_PARITY_URL={{ HOME_RPC_URL }}
REACT_APP_HOME_NATIVE_NAME={{ HOME_NATIVE_NAME }}
REACT_APP_HOME_NETWORK_NAME={{ HOME_NAME }}
REACT_APP_FOREIGN_NETWORK_NAME={{ FOREIGN_NAME }}
REACT_APP_HOME_WITHOUT_EVENTS={{ HOME_WITHOUT_EVENTS }}
REACT_APP_FOREIGN_WITHOUT_EVENTS={{ FOREIGN_WITHOUT_EVENTS }}
REACT_APP_HOME_EXPLORER_TX_TEMPLATE={{ UI_HOME_EXPLORER_TX_TEMPLATE }}
REACT_APP_FOREIGN_EXPLORER_TX_TEMPLATE={{ UI_FOREIGN_EXPLORER_TX_TEMPLATE }}
REACT_APP_HOME_EXPLORER_ADDRESS_TEMPLATE={{ UI_HOME_EXPLORER_ADDRESS_TEMPLATE }}
REACT_APP_FOREIGN_EXPLORER_ADDRESS_TEMPLATE={{ UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE }}
{% if HOME_GAS_PRICE_ORACLE_URL | default('') != '' %}
REACT_APP_HOME_GAS_PRICE_ORACLE_URL={{ HOME_GAS_PRICE_ORACLE_URL }}
REACT_APP_HOME_GAS_PRICE_SPEED_TYPE={{ HOME_GAS_PRICE_SPEED_TYPE }}
{% endif %}
REACT_APP_HOME_GAS_PRICE_FALLBACK={{ UI_HOME_GAS_PRICE_FALLBACK }}
REACT_APP_HOME_GAS_PRICE_UPDATE_INTERVAL={{ HOME_GAS_PRICE_UPDATE_INTERVAL }}
{% if HOME_GAS_PRICE_FACTOR | default('') != '' %}
REACT_APP_HOME_GAS_PRICE_FACTOR={{ HOME_GAS_PRICE_FACTOR }}
{% endif %}
REACT_APP_FOREIGN_GAS_PRICE_ORACLE_URL={{ FOREIGN_GAS_PRICE_ORACLE_URL }}
REACT_APP_FOREIGN_GAS_PRICE_SPEED_TYPE={{ FOREIGN_GAS_PRICE_SPEED_TYPE }}
REACT_APP_FOREIGN_GAS_PRICE_FALLBACK={{ UI_FOREIGN_GAS_PRICE_FALLBACK }}
REACT_APP_FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ FOREIGN_GAS_PRICE_UPDATE_INTERVAL }}
REACT_APP_FOREIGN_GAS_PRICE_FACTOR={{ FOREIGN_GAS_PRICE_FACTOR }}
# Default
REACT_APP_TITLE={{ UI_TITLE }}
REACT_APP_DESCRIPTION={{ UI_DESCRIPTION }}
PORT={{ UI_PORT }}

@ -0,0 +1,11 @@
$FileCreateMode 0644
template(name="DockerLogFileName_UI" type="list") {
constant(value="/var/log/docker/")
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="ui_(.*)\\/[a-zA-Z0-9]+\\[")
constant(value="/docker.log")
}
if $programname startswith 'ui_' then \
?DockerLogFileName_UI
$FileCreateMode 0600

@ -0,0 +1,15 @@
if $programname startswith 'ui_' then {
action(
type="omfwd"
protocol="{{ syslog_server_port.split(":")[0] }}"
target="{{ (syslog_server_port.split(":")[1])[2:] }}"
port="{{ syslog_server_port.split(":")[2] }}"
template="RemoteForwardFormat"
queue.SpoolDirectory="/var/spool/rsyslog"
queue.FileName="remote"
queue.MaxDiskSpace="1g"
queue.SaveOnShutdown="on"
queue.Type="LinkedList"
ResendLastMSGOnReconnect="on"
)
}

@ -0,0 +1,76 @@
#! /bin/bash
### BEGIN INIT INFO
# Provides: tokenbridge-ui
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
WORKDIR="{{ '/home/' + compose_service_user | default('poadocker') + '/' + bridge_path + '/ui' if bridge_path[:1] != "/" else bridge_path + '/ui' }}"
start(){
echo "Starting TokenBridge UI.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach
}
stop(){
echo "Stopping TokenBridge UI.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sleep 2
}
status(){
echo "TokenBridge UI status:"
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose ps
}
rebuild(){
echo "Rebuild TokenBridge UI.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach --force-recreate --no-deps --build
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
echo "Restarting TokenBridge UI.."
stop
start
;;
rebuild)
rebuild
;;
*)
echo $"Usage: $0 {start|stop|restart|rebuild|status}"
exit 1
;;
esac
exit 0

16
deployment/site.yml Normal file

@ -0,0 +1,16 @@
---
- name: Install Oracle
hosts: oracle
become: true
roles:
- { role: oracle }
- name: Install UI
hosts: ui
become: true
roles:
- { role: ui }
- name: Install Monitor
hosts: monitor
become: true
roles:
- { role: monitor }

Some files were not shown because too many files have changed in this diff Show More